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,通过合理地给每个组件分配时间区间,让其在一定的时间区间内执行特定的动画,从而实现一连串动画。