2024-09-28 07:41:54
之前我们介绍了一个Flutter的栈结构的layout组件叫做Stack,通过Stack我们可以将一些widget叠放在其他widget之上,从而可以实现图像的组合功能,也是日常中最常用的一种组件了。今天我们要介绍的组件是Stack的近亲,叫做IndexedStack,它有什么功能呢?一起来看看吧。
IndexedStack简介从名字可以看出,IndexedStack是给Stack添加了一个index的功能,事实是否如此呢?我们先来看一下IndexedStack的定义:
classIndexedStackextendsStack可以看到IndexedStack继承自Stack,它实际上是Stack的子类,所以之前介绍的Stack有的功能IndexedStack全都有,并且IndexedStack是对Stack的功能进行了增强。
我们来看下它的构造函数:
IndexedStack({Key?key,AlignmentGeometryalignment=AlignmentDirectional.topStart,TextDirection?textDirection,StackFitsizing=StackFit.loose,this.index=0,List<Widget>children=const<Widget>[],}):super(key:key,alignment:alignment,textDirection:textDirection,fit:sizing,children:children);可以看到和Stack相比,IndexedStack多了一个index参数,但是这个参数并没有传入到super的构造函数中去,那么index到底是在哪里使用的呢?
别急,IndexedStack还重写了下面的两个方法,分别是createRenderObject和updateRenderObject:
@overrideRenderIndexedStackcreateRenderObject(BuildContextcontext){assert(_debugCheckHasDirectionality(context));returnRenderIndexedStack(index:index,alignment:alignment,textDirection:textDirection??Directionality.maybeOf(context),);}@overridevoidupdateRenderObject(BuildContextcontext,RenderIndexedStackrenderObject){assert(_debugCheckHasDirectionality(context));renderObject..index=index..alignment=alignment..textDirection=textDirection??Directionality.maybeOf(context);}和Stack相比,IndexedStack在这两个方法中使用的是RenderIndexedStack,而Stack使用的是RenderStack。
所以虽然IndexedStack继承自Stack,但是两者在表现上是有本质区别的。
对于Stack来说,一个widget被放在另外一个widget之上,但是多个widget可以同时展示出来。而对于IndexedStack来说,它只会展示对应index的widget。
RenderIndexedStack也是继承自RenderStack:
classRenderIndexedStackextendsRenderStack我们看下它的paintStack方法:
@overridevoidpaintStack(PaintingContextcontext,Offsetoffset){if(firstChild==null||index==null)return;finalRenderBoxchild=_childAtIndex();finalStackParentDatachildParentData=child.parentData!asStackParentData;context.paintChild(child,childParentData.offset+offset);}可以看到在paintStack方法中,只绘制了和index对应的_childAtIndex这个组件,所以如果index不匹配的话,并不会展示出来。
IndexedStack的表现有点像我们常见的tab。
IndexedStack的使用从上面IndexedStack的构造函数中,我们知道IndexedStack需要传入一个index属性和对应的children。
在本例中,我们给IndexedStack传入一个可变的index属性,和4个child:
IndexedStack(index:_counter,children:[widgetOne(),widgetTwo(),widgetThree(),widgetFour(),],)_counter是定义在StatefulWidget中的变量。可以通过调用setState方法对index进行修改,从而实现动态切换child的目的。
这里的childwidget很简单,我们使用了不同大小的SizedBox,SizedBox中设置不同的color来方便观察切换的效果:
WidgetwidgetOne(){returnSizedBox(width:100,height:100,child:Container(color:Colors.yellow,),);}最后,在Scaffold的floatingActionButton中调用_changeIndex方法实现index的改变,最终的代码如下:
classMyHomePageextendsStatefulWidget{constMyHomePage({Key?key,requiredthis.title}):super(key:key);finalStringtitle;@overrideState<MyHomePage>createState()=>_MyHomePageState();}class_MyHomePageStateextendsState<MyHomePage>{int_counter=0;void_changeIndex(){setState((){_counter=(_counter+1)%4;print(_counter);});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text(widget.title),),body:Center(child:IndexedStack(index:_counter,children:[widgetOne(),widgetTwo(),widgetThree(),widgetFour(),],),),floatingActionButton:FloatingActionButton(onPressed:_changeIndex,tooltip:'changeindex',child:constIcon(Icons.arrow_back),),);}程序运行之后的效果如下:
通过点击右下方的按钮,我们得到了不同的widget。
总结IndexWidget和tab有点类似,大家可以在需要的时候使用。
本文的例子:https://github.com/ddean2009/learn-flutter.git
更多内容请参考www.flydean.com
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
原文:https://juejin.cn/post/7113177754006192165