flutter第四篇:学习大地老师《Flutter入门实战系列视频教程》笔记

Container如果没有child,则其宽高等于父容器的宽高。如果有child,则其宽高等于其child的宽高。如果child是个Row,那么其宽等于屏幕的宽。

在ListView中,如果ListView是上下滚动的,那么如果其中有Container,则Container的width属性会失效,不管设成多少,在水平方向上都会铺满平铺。同样的,如果LitView是水平滚动的,那么其中的Container的height属性会失效,在竖直方向上会铺满屏幕。为了自定义宽高,我们可以把ListView用SizedBox包裹。

把ListView的children中各元素都居中:children中同属一行的元素用Row包裹,同属一列的元素用Column包裹。???

ListTile是一个固定高度的行,在这个行中可以放标题和子标题,在标题、子标题之前之后还可以放一个Icon或图片。ListTile经常用在ListView中,也可以单独使用。

想引入一条横线,可以用Divider。

Container的padding是内边距,是其child组件与container的边距,margin是外边距,是container本身与其父组件的边距。

SizedBox相比于Container,只能设置宽、高和child,不能设置背景,边框,圆角等。

flex是Expanded组件的属性。

可以用Stack组件和Positioned组件实现定位。Stack组件children中个元素默认会堆叠,如果把元素用Positioned包裹,则可以用Positioned组件的left、right、top、bottom属性实现自定义位置(设置left值为0、right值为0就会占满整行)。Positioned的width、height是其子组件的宽高,必须为一个具体的值,不能是double.infinity,否则会报错。可以调用MediaQuery.of(context).size获取屏幕的宽高。而double.infinity主要用在Container中。Stack可以用Container包裹,此时left、right、top、bottom是在SizedBox中的方位,否则是在整个屏幕的方位。

创建圆形图片的三种方式:

1、使用Container:

Container默认是矩形,可以设置其decoration属性,设置BoxDecoration的shape属性值为BoxShape.circle,使其变为圆形。

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 40,
      height: 40,
      decoration: const BoxDecoration(
          shape: BoxShape.circle,
          image: DecorationImage(
              fit: BoxFit.cover,
              image: NetworkImage(
                "http://oss.echowa.xndm.tech/test/op/98ir9yjgJc8krUcyp9Ztd4.png",
              ))),
    );
  }

2、使用ClipOval

Oval是椭圆的意思

  @override
  Widget build(BuildContext context) {
    return ClipOval(
      child: Image.network(
          "http://oss.echowa.xndm.tech/test/op/98ir9yjgJc8krUcyp9Ztd4.png",
          width: 40,
          height: 40,
          fit: BoxFit.cover),
    );
  }

3、使用CircleAvatar:

这种方式最简单,CircleAvatar其实是对AnimatedContainer的封装。

  @override
  Widget build(BuildContext context) {
    return const CircleAvatar(
      radius: 20,
      backgroundImage: NetworkImage(
          "http://oss.echowa.xndm.tech/test/op/98ir9yjgJc8krUcyp9Ztd4.png"),
    );
  }

创建圆形按钮: 

使用ElevatedButton、TextButton、OutlinedButton、IconButton等按钮组件的style属性值ButtonStyle组件的shape属性,使其值为WidgetStateProperty.all(CircleBorder())。还可以通过CircleBorder的side属性设置圆边框的颜色与宽度。如果想设置圆形按钮的大小,则需要把按钮放到Container中。

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        Row(
          children: [
            ElevatedButton(
              onPressed: () {},
              style: ButtonStyle(
                  shape: WidgetStateProperty.all(const CircleBorder(
                      side: BorderSide(
                color: Colors.yellow,
              )))),
              child: const Text("圆形按钮"),
            ),
            Container(
              width: 120,
              height: 120,
              child: ElevatedButton(
                onPressed: () {},
                style: ButtonStyle(
                    shape: WidgetStateProperty.all(const CircleBorder(
                        side: BorderSide(
                  color: Colors.yellow,
                )))),
                child: const Text("自定义大小圆形按钮"),
              ),
            ),
          ],
        ),
      ],
    );
  }

AlertDialog可以用来实现提示框(样式如删除确认对话框),SimpleDialog可以用来实现select选择框,showModalBottomSheet函数可以用来实现底部弹框。有一个开源的第三方包fluttertoast,也可以用来实现底部弹框。

PageView可以用来实现滚屏和轮播图。滚屏指的是像抖音推荐页那种可以一直往下滑。

flutter项目在run时,屏幕右上角默认有debug标志,把MaterialApp的debugShowCheckedModeBanner属性值设为false,即可去掉。

flutter中的动画主要分为隐式动画、显式动画、自定义隐式动画、自定义显式动画、Hero动画5种。

隐式动画:Animatedxxx

AnimatedContainer,当容器属性改变时,触发动画。

AnimatedPadding,当padding值改变时,触发动画。

AnimatedPositioned,当position的位置改变时,触发动画。

AnimatedOpacity,当透明度改变时,触发动画。

AnimatedDefaultTextStyle,当TextStyle的属性改变时,触发动画。

AnimatedSwitcher,当其子元素改变时,触发动画。

隐式动画,在触发时需要调用setState(),让State的build()方法重新执行。

自定义隐式动画

使用TweenAnimationBuilder。tween属性赋值为一个Tween实例,duration指定动画执行时间,builder属性指定一个返回Widget的函数,函数第二个参数是Tween实例中指定的从begin变到end的值,我们在构造Widget时使用这个值,从而实现动画。函数的第三个参数是用于性能优化的,如果我们返回的Widget有child,那么可以把TweenAnimationBuilder的child属性赋值为此child,即在此构造,这样第三个参数就是这个child了,在构造Widget时就可以把第三个参数直接赋值给Widget的child属性,这样虽然执行动画过程中builder函数会多次执行,但是child不会多次构造。

显式动画:xxxTransition。要用到AnimationController。

RotationTransition,让元素旋转。child属性是普通元素,turns属性是一个AnimationController实例。通过调用这个AnimationController实例的repeat()方法可以让元素一直旋转,调用forward()方法可以让元素顺时针旋转一圈,调用reverse()方法可以让元素逆时针旋转一圈,调用reset()方法可以让元素重置到初始角度,调用stop()方法可以让元素停止旋转。AnimationController构造方法必须指定vsync属性,值是一个TickerProvider实例,我们让xxxState with SingleTickerProviderStateMixin,然后传this即可。还必须指定duration属性,值是一个Duration实例,表示动画执行的时间,不传的话,虽然编译时不会报错,但动画执行时会报错。

FadeTransition,改变元素的透明度。opacity属性是一个Animation<double>实例,用AnimationController实例。

ScaleTransition,对元素进行缩放。scale属性是一个Animation<double>实例,用AnimationController实例。

SlideTransition,对元素进行位移。position属性是一个Animation<Offset>实例,调用Tween实例的animate()方法赋值。Tween(begin: Offset(0, 0), end: Offset(0.2, 0.2)).animate(controller)。第一个0.2表示向右移0.2*(元素的宽度),第二个0.2表示向下移动0.2*(元素的高度)。

AnimatedIcon,改变图标,由一个图标变为另一个图标。

显式动画,在触发时不需要调用setState()。

自定义显式动画

使用AnimatedBuilder。animation属性赋值为一个AnimationController实例,builder属性指定一个返回Widget的函数。在构造Widget时,用到controller.value,或者用到controller.drive(Tween(begin: a, end: b)).value,这个value是动态变化的,从而实现动画效果。builder函数的第二个参数和自定义隐式动画中builder函数的第三个参数用法和作用一样。如我们想改变Container的透明度,则可以用Opacity包裹Container,builder返回Opacity,Opacity的opacity属性值用到controller.value。如我们想让Container进行位移,则可以让Container的transform属性用到controller.value。

交错动画

交错动画,指的是一次触发,多个组件依次执行动画。

如我们想实现页面上的一个左箭头icon在0.5s内逐渐消失,然后在0.5s内逐渐出来一个右箭头icon。

可以使用ScaleTransition来实现上述交错动画。创建两个ScaleTransition,第一个ScaleTransition的child是一个左箭头icon,第二个ScaleTransition的child是一个右箭头icon,两个ScaleTransition共用一个AnimationController实例,假设为controller。左箭头的scale属性设为controller.drive(Tween(begin: 2.0, end: 0.0).chain(CurveTween(curve: const Interval(0, 0.5)))),即不再是孤零零的controller,而是调用controller的drive()方法得到的新的Animation实例。drive()方法需要传一个Animatable实例,Animatable是个抽象类,我们用其子类Tween。构造Tween实例时,指定begin属性值为2.0,表示左箭头一开始的size是icon的size的2倍,指定end值为0.0,表示左箭头最后缩没了。若要指定动画的执行、结束时间,需要调用Tween实例的chain()方法,得到一个新的Animatable实例。chain()方法要传一个Animatable<double>实例。我们用其子类CurveTween。构造CurveTween实例时必须指定curve属性,值是个Curve实例。Curve是个抽象类,我们用其子类Interval。构造Interval实例时,第一个参数指定动画开始执行的时间,第二个参数指定动画执行结束的时间。这两个参数都是小数,真正时间还要乘以Duration指定的时间。即假如Duration指定为10s,第一个参数是0.1,第二个参数是0.2,则其实表示的是动画从第1s开始执行,到第2s执行结束。总结起来,左箭头的scale属性表示左箭头一开始放到icon 指定size的2倍,从触发后立刻开始缩小,到0.5*Duration缩小到消失。同理把右箭头的scale属性设为controller.drive(Tween(begin: 0.0, end: 2.0).chain(CurveTween(curve: const Interval(0.5, 1)))),表示一开始不显示,从触发后0.5*Duration开始放大,到1*Duration放大到icon指定size的2倍。

通过上面例子不难看出,其实交错动画就是利用多个组件共用一个AnimationController,通过合理地给每个组件分配时间区间,让其在一定的时间区间内执行特定的动画,从而实现一连串动画。

 

posted on 2024-09-11 10:39  koushr  阅读(5)  评论(0编辑  收藏  举报

导航