建议使用以下浏览器,以获得最佳体验。 ie 9.0 以上版本 chrome 31 谷歌浏览器 firefox 30 火狐浏览器
温馨提示

抱歉,您需设置社区昵称后才能参与社区互动!

前往修改
我再想想
选择版块
主题:2366帖子:10802

【技术干货】

10天学会flutter day10 flutter 玩转 动画与打包[转载]

2022/6/6 298

动画
​ flutter中的动画系统基于animation对象的,和之前的手势不同,它不是一个widget,这是因为animation对象本身和ui渲染没有任何关系。animation是一个抽象类,就相当于一个定时器,它用于保存动画的插值和状态,并执行数值的变化。widget可以在build函数中读取animation对象的当前值, 并且可以监听动画的状态改变。

animationcontroller
​ animationcontroller用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。animationcontroller会在动画的每一帧,就会生成一个新的值。默认情况下,animationcontroller在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。

animationcontroller controller = animationcontroller( 
 duration: const duration(milliseconds: 2000), //动画时间
 lowerbound: 10.0,    //生成数字的区间 
 upperbound: 20.0,    //10.0 - 20.0
 vsync: this  //tickerprovider 动画驱动器提供者
);

ticker
​ ticker的作用是添加屏幕刷新回调,每次屏幕刷新都会调用tickercallback。使用ticker来驱动动画会防止屏幕外动画(动画的ui不在当前屏幕时,如锁屏时)消耗不必要的资源。因为flutter中屏幕刷新时会通知ticker,锁屏后屏幕会停止刷新,所以ticker就不会再触发。最简单的做法为将singletickerproviderstatemixin添加到state的定义中。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();
    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      lowerbound: 10.0,
      upperbound: 100.0,
      // 提供 vsync 最简单的方式,就是直接混入 singletickerproviderstatemixin
      // 如果有多个animationcontroller,则使用tickerproviderstatemixin。
      vsync: this,
    );
       //状态修改监听
    controller
      ..addstatuslistener((animationstatus status) {
        debugprint("状态:$status");
      })
      ..addlistener(() {
        setstate(() => {});
      });

    debugprint("controller.value:${controller.value}");
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          width: controller.value,
          height: controller.value,
          color: colors.blue,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


动画状态监听:在forword结束之后状态为completed。在reverse结束之后状态为dismissed

tween
​ 默认情况下,animationcontroller对象值为:double类型,范围是0.0到1.0 。如果我们需要不同的范围或不同的数据类型,则可以使用tween来配置动画以生成不同的范围或数据类型的值。要使用tween对象,需要调用其animate()方法,然后传入一个控制器对象,同时动画过程中产生的数值由tween的lerp方法决定。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;

  bool forward = true;

  tween tween;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );
    //使用color
    tween = colortween(begin: colors.blue, end: colors.yellow);
    //添加动画值修改监听
    tween.animate(controller)..addlistener(() => setstate(() {}));
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          width: 100,
          height: 100,
          //获取动画当前值
          color: tween.evaluate(controller),
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


curve
​ 动画过程默认是线性的(匀速),如果需要非线形的,比如:加速的或者先加速后减速等。flutter中可以通过curve(曲线)来描述动画过程。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  animation animation;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //弹性
    animation = curvedanimation(parent: controller, curve: curves.bouncein);
    //使用color
    animation = tween(begin: 10.0, end: 100.0).animate(animation)
      ..addlistener(() {
        setstate(() => {});
      });
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          //不需要转换
          width: animation.value,
          height: animation.value,
          //获取动画当前值
          color: colors.blue,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


animatedwidget
​ 通过上面的学习我们能够感受到animation对象本身和ui渲染没有任何关系。而通过addlistener()和setstate() 来更新ui这一步其实是通用的,如果每个动画中都加这么一句是比较繁琐的。animatedwidget类封装了调用setstate()的细节,简单来说就是自动调用setstate()。

​ flutter中已经封装了很多动画,比如对widget进行缩放,可以直接使用scaletransition

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  animation animation;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //弹性
    animation = curvedanimation(parent: controller, curve: curves.bouncein);
    //使用color
    animation = tween(begin: 10.0, end: 100.0).animate(animation);
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        scaletransition(
          child:  container(
            width: 100,
            height: 100,
            color: colors.blue,
          ),
          scale: controller,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


hero动画
​ hero动画就是在路由切换时,有一个共享的widget可以在新旧路由间切换,由于共享的widget在新旧路由页面上的位置、外观可能有所差异,所以在路由切换时会逐渐过渡,这样就会产生一个hero动画。

import 'package:flutter/material.dart';

void main() => runapp(myapp());

class myapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return new materialapp(
      title: 'flutter demo',
      home: scaffold(
          appbar: appbar(
            title: text("凯发k8国际娱乐官网入口主页"),
          ),
          body: route1()),
    );
  }
}

// 路由a
class route1 extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return container(
      alignment: alignment.topcenter,
      child: inkwell(
        child: hero(
          tag: "avatar", //唯一标记,前后两个路由页hero的tag必须相同
          child: circleavatar(
            backgroundimage: assetimage(
              "assets/banner.jpeg",
            ),
          ),
        ),
        ontap: () {
          navigator.push(context, materialpageroute(builder: (_) {
            return route2();
          }));
        },
      ),
    );
  }
}

class route2 extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return center(
      child: hero(
          tag: "avatar", //唯一标记,前后两个路由页hero的tag必须相同
          child: image.asset("assets/banner.jpeg")),
    );
  }
}


组合动画
有些时候我们可能会需要执行一个动画序列执行一些复杂的动画。

import 'package:flutter/material.dart';

void main() => runapp(myapp());

class myapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return new materialapp(
      title: 'flutter demo',
      home: route(),
    );
  }
}

class route extends statefulwidget {
  @override
  state createstate() {
    return routestate();
  }
}

class routestate extends state with singletickerproviderstatemixin {
  animation color;
  animation width;
  animationcontroller controller;

  @override
  void initstate() {
    super.initstate();
    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //高度动画
    width = tween(
      begin: 100.0,
      end: 300.0,
    ).animate(
      curvedanimation(
        parent: controller,
        curve: interval(
          //间隔,前60%的动画时间 1200ms执行高度变化
          0.0, 0.6,
        ),
      ),
    );

    color = colortween(
      begin: colors.green,
      end: colors.red,
    ).animate(
      curvedanimation(
        parent: controller,
        curve: interval(
          0.6, 1.0, //高度变化完成后 800ms 执行颜色编码
        ),
      ),
    );
  }

  @override
  widget build(buildcontext context) {
    return scaffold(
      appbar: appbar(
        title: text("凯发k8国际娱乐官网入口主页"),
      ),
      body: inkwell(
        ///1、不用显式的去添加帧监听器,再调用setstate()
        ///2、缩小动画构建的范围,如果没有builder,setstate()将会在父widget上下文调用,导致父widget的build方法重新调用,现在只会导致动画widget的build重新调用
        child: animatedbuilder(
            animation: controller,
            builder: (context, child) {
              return container(
                color: color.value,
                width: width.value,
                height: 100.0,
              );
            }),
        ontap: () {
          controller.forward().whencompleteorcancel(() => controller.reverse());
        },
      ),
    );
  }
}


打包
​ flutter在打release包时候回使用aot,因此在对一个flutter测试时候务必使用release来进行测试。打包命令:flutter build apk 。当然我们需要打包时,还需要配置一些比如签名的内容。配置这些内容和普通android工程没有区别,都是在build.gradle中进行,只是flutter工程as没有提供gui。

​ 在flutter工程的android/app下面的build.gradle可以修改包名、版本等信息,这就不用多说了。获得签名文件之后,将它复制到flutter的android目录:


​ 然后在app的build.gradle中配置:

signingconfigs {
        release {
            keyalias 'enjoy'
            keypassword '123456'
            // 因为是放到父级的根目录,使用rootproject
            // 如果放在这个build.gradle的同级,直接使用file
            storefile rootproject.file('enjoy.jks')
            storepassword '123456'
        }
    }
    buildtypes {
        release {
            // todo: add your own signing config for the release build.
            // signing with the debug keys for now, so `flutter run --release` works.
            signingconfig signingconfigs.release
        }
    }
饼图
https://github.com/google/charts

stack布局中的fit属性与image的fit类似,表示内容的扩充情况。默认为stackfit.loose表示stack与内容一样大。如果设置为stackfit.passthrough则表示stack父widget的约束会传给stack内部非positioned的子widget。效果如代码中的stackfit.dart

原文链接:https://blog.csdn.net/u010755471/article/details/124691809

回复1

0 0
2022/6/19 09:12

感谢分享

上划加载中
直达楼层
全部回复
正序浏览
标签
您还可以添加5个标签
  • 没有搜索到和“关键字”相关的标签
  • 云产品
  • 凯发k8国际娱乐官网入口的解决方案
  • 技术领域
  • 通用技术
  • 平台功能
取消

10天学会flutter day10 flutter 玩转 动画与打包[转载]-凯发k8国际娱乐官网入口

您已采纳当前回复为最佳回复

仙女本仙

发帖: 81粉丝: 2

发表于2022年06月06日 14:34:48 298 1
[技术干货] 10天学会flutter day10 flutter 玩转 动画与打包[转载]

动画
​ flutter中的动画系统基于animation对象的,和之前的手势不同,它不是一个widget,这是因为animation对象本身和ui渲染没有任何关系。animation是一个抽象类,就相当于一个定时器,它用于保存动画的插值和状态,并执行数值的变化。widget可以在build函数中读取animation对象的当前值, 并且可以监听动画的状态改变。

animationcontroller
​ animationcontroller用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。animationcontroller会在动画的每一帧,就会生成一个新的值。默认情况下,animationcontroller在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。

animationcontroller controller = animationcontroller( 
 duration: const duration(milliseconds: 2000), //动画时间
 lowerbound: 10.0,    //生成数字的区间 
 upperbound: 20.0,    //10.0 - 20.0
 vsync: this  //tickerprovider 动画驱动器提供者
);

ticker
​ ticker的作用是添加屏幕刷新回调,每次屏幕刷新都会调用tickercallback。使用ticker来驱动动画会防止屏幕外动画(动画的ui不在当前屏幕时,如锁屏时)消耗不必要的资源。因为flutter中屏幕刷新时会通知ticker,锁屏后屏幕会停止刷新,所以ticker就不会再触发。最简单的做法为将singletickerproviderstatemixin添加到state的定义中。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();
    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      lowerbound: 10.0,
      upperbound: 100.0,
      // 提供 vsync 最简单的方式,就是直接混入 singletickerproviderstatemixin
      // 如果有多个animationcontroller,则使用tickerproviderstatemixin。
      vsync: this,
    );
       //状态修改监听
    controller
      ..addstatuslistener((animationstatus status) {
        debugprint("状态:$status");
      })
      ..addlistener(() {
        setstate(() => {});
      });

    debugprint("controller.value:${controller.value}");
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          width: controller.value,
          height: controller.value,
          color: colors.blue,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


动画状态监听:在forword结束之后状态为completed。在reverse结束之后状态为dismissed

tween
​ 默认情况下,animationcontroller对象值为:double类型,范围是0.0到1.0 。如果我们需要不同的范围或不同的数据类型,则可以使用tween来配置动画以生成不同的范围或数据类型的值。要使用tween对象,需要调用其animate()方法,然后传入一个控制器对象,同时动画过程中产生的数值由tween的lerp方法决定。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;

  bool forward = true;

  tween tween;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );
    //使用color
    tween = colortween(begin: colors.blue, end: colors.yellow);
    //添加动画值修改监听
    tween.animate(controller)..addlistener(() => setstate(() {}));
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          width: 100,
          height: 100,
          //获取动画当前值
          color: tween.evaluate(controller),
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


curve
​ 动画过程默认是线性的(匀速),如果需要非线形的,比如:加速的或者先加速后减速等。flutter中可以通过curve(曲线)来描述动画过程。

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  animation animation;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //弹性
    animation = curvedanimation(parent: controller, curve: curves.bouncein);
    //使用color
    animation = tween(begin: 10.0, end: 100.0).animate(animation)
      ..addlistener(() {
        setstate(() => {});
      });
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        container(
          //不需要转换
          width: animation.value,
          height: animation.value,
          //获取动画当前值
          color: colors.blue,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


animatedwidget
​ 通过上面的学习我们能够感受到animation对象本身和ui渲染没有任何关系。而通过addlistener()和setstate() 来更新ui这一步其实是通用的,如果每个动画中都加这么一句是比较繁琐的。animatedwidget类封装了调用setstate()的细节,简单来说就是自动调用setstate()。

​ flutter中已经封装了很多动画,比如对widget进行缩放,可以直接使用scaletransition

import 'package:flutter/material.dart';

void main() => runapp(animationapp());

class animationapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return materialapp(
      title: "animation",
      home: scaffold(
        appbar: appbar(
          title: text('animation'),
        ),
        body: animwidget(),
      ),
    );
  }
}

// 动画是有状态的
class animwidget extends statefulwidget {
  @override
  state createstate() {
    return _animwidgetstate();
  }
}

class _animwidgetstate extends state
    with singletickerproviderstatemixin {
  animationcontroller controller;
  animation animation;
  bool forward = true;

  @override
  void initstate() {
    super.initstate();

    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //弹性
    animation = curvedanimation(parent: controller, curve: curves.bouncein);
    //使用color
    animation = tween(begin: 10.0, end: 100.0).animate(animation);
  }

  @override
  widget build(buildcontext context) {
    return column(
      children: [
        scaletransition(
          child:  container(
            width: 100,
            height: 100,
            color: colors.blue,
          ),
          scale: controller,
        ),
        raisedbutton(
          child: text("播放"),
          onpressed: () {
            if (forward) {
              controller.forward();
            } else {
              controller.reverse();
            }
            forward = !forward;
          },
        ),
        raisedbutton(
          child: text("停止"),
          onpressed: () {
            controller.stop();
          },
        )
      ],
    );
  }
}


hero动画
​ hero动画就是在路由切换时,有一个共享的widget可以在新旧路由间切换,由于共享的widget在新旧路由页面上的位置、外观可能有所差异,所以在路由切换时会逐渐过渡,这样就会产生一个hero动画。

import 'package:flutter/material.dart';

void main() => runapp(myapp());

class myapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return new materialapp(
      title: 'flutter demo',
      home: scaffold(
          appbar: appbar(
            title: text("凯发k8国际娱乐官网入口主页"),
          ),
          body: route1()),
    );
  }
}

// 路由a
class route1 extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return container(
      alignment: alignment.topcenter,
      child: inkwell(
        child: hero(
          tag: "avatar", //唯一标记,前后两个路由页hero的tag必须相同
          child: circleavatar(
            backgroundimage: assetimage(
              "assets/banner.jpeg",
            ),
          ),
        ),
        ontap: () {
          navigator.push(context, materialpageroute(builder: (_) {
            return route2();
          }));
        },
      ),
    );
  }
}

class route2 extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return center(
      child: hero(
          tag: "avatar", //唯一标记,前后两个路由页hero的tag必须相同
          child: image.asset("assets/banner.jpeg")),
    );
  }
}


组合动画
有些时候我们可能会需要执行一个动画序列执行一些复杂的动画。

import 'package:flutter/material.dart';

void main() => runapp(myapp());

class myapp extends statelesswidget {
  @override
  widget build(buildcontext context) {
    return new materialapp(
      title: 'flutter demo',
      home: route(),
    );
  }
}

class route extends statefulwidget {
  @override
  state createstate() {
    return routestate();
  }
}

class routestate extends state with singletickerproviderstatemixin {
  animation color;
  animation width;
  animationcontroller controller;

  @override
  void initstate() {
    super.initstate();
    controller = animationcontroller(
      // 动画的时长
      duration: duration(milliseconds: 2000),
      // 提供 vsync 最简单的方式,就是直接继承 singletickerproviderstatemixin
      vsync: this,
    );

    //高度动画
    width = tween(
      begin: 100.0,
      end: 300.0,
    ).animate(
      curvedanimation(
        parent: controller,
        curve: interval(
          //间隔,前60%的动画时间 1200ms执行高度变化
          0.0, 0.6,
        ),
      ),
    );

    color = colortween(
      begin: colors.green,
      end: colors.red,
    ).animate(
      curvedanimation(
        parent: controller,
        curve: interval(
          0.6, 1.0, //高度变化完成后 800ms 执行颜色编码
        ),
      ),
    );
  }

  @override
  widget build(buildcontext context) {
    return scaffold(
      appbar: appbar(
        title: text("凯发k8国际娱乐官网入口主页"),
      ),
      body: inkwell(
        ///1、不用显式的去添加帧监听器,再调用setstate()
        ///2、缩小动画构建的范围,如果没有builder,setstate()将会在父widget上下文调用,导致父widget的build方法重新调用,现在只会导致动画widget的build重新调用
        child: animatedbuilder(
            animation: controller,
            builder: (context, child) {
              return container(
                color: color.value,
                width: width.value,
                height: 100.0,
              );
            }),
        ontap: () {
          controller.forward().whencompleteorcancel(() => controller.reverse());
        },
      ),
    );
  }
}


打包
​ flutter在打release包时候回使用aot,因此在对一个flutter测试时候务必使用release来进行测试。打包命令:flutter build apk 。当然我们需要打包时,还需要配置一些比如签名的内容。配置这些内容和普通android工程没有区别,都是在build.gradle中进行,只是flutter工程as没有提供gui。

​ 在flutter工程的android/app下面的build.gradle可以修改包名、版本等信息,这就不用多说了。获得签名文件之后,将它复制到flutter的android目录:


​ 然后在app的build.gradle中配置:

signingconfigs {
        release {
            keyalias 'enjoy'
            keypassword '123456'
            // 因为是放到父级的根目录,使用rootproject
            // 如果放在这个build.gradle的同级,直接使用file
            storefile rootproject.file('enjoy.jks')
            storepassword '123456'
        }
    }
    buildtypes {
        release {
            // todo: add your own signing config for the release build.
            // signing with the debug keys for now, so `flutter run --release` works.
            signingconfig signingconfigs.release
        }
    }
饼图
https://github.com/google/charts

stack布局中的fit属性与image的fit类似,表示内容的扩充情况。默认为stackfit.loose表示stack与内容一样大。如果设置为stackfit.passthrough则表示stack父widget的约束会传给stack内部非positioned的子widget。效果如代码中的stackfit.dart

原文链接:https://blog.csdn.net/u010755471/article/details/124691809

分享文章到朋友圈

分享文章到微博
您已采纳当前回复为最佳回复

发帖: 752粉丝: 61

发表于2022年06月19日 09:12:25

感谢分享

您需要登录后才可以回帖 | 立即注册

推荐阅读

您对问题的回复是否满意?
满意度
非常满意 满意 一般 不满意
我要反馈
0/200
网站地图