Flutter28,android插件化面试

selected: selected,

enabled: enabled,

child: ConstrainedBox(

constraints: BoxConstraints(minHeight: 200.0, maxHeight: 200.0),

//这个是自定义Layout

child: CustomMultiChildLayout(

// 这个Delegate用来做实际的布局

delegate: ItemLayoutDelegate(),

//用来做布局的子控件们

children: children,

))),

);

}

}

CustomMultiChildLayout就是来让你做自定义布局的控件,需要一个Delegate做参数,这个Delegate需要我们自己实现。另一个参数children是需要布局的子控件。自定义布局控件的子控件们都需要用一个LayoutId的控件包起来。这也是Flutter一个比较有意思的地方,很多在Android中我们当做属性来用的东西,Flutter都会做成一个类来包裹,这也是造成UI代码比较难看的一个原因。

这里的id一般用枚举来表示,例如

enum _Block {

bg,

text,

}

bg代表新闻图片,text代表新闻标题。那么你传给CustomMultiChildLayout子控件列表需要是这样的,每一个都要用LayoutId包起来:

final List children = [];

children.add(LayoutId(

//头图的id

id: _Block.bg,

child: FadeInImage.assetNetwork(),

));

children.add(LayoutId(

// 标题的id

id: Flutter28,android插件化面试
_Block.text,

child: Container()

));

最后我们在看看实际布局是怎么做的,来看ItemLayoutDelegate的代码:

class ItemLayoutDelegate extends MultiChildLayoutDelegate {

@override

void performLayout(Size size) {

if (hasChild(_Block.bg)) {

layoutChild(_Block.bg, new BoxConstraints.tight(size));

positionChild(_Block.bg, Offset.zero);

}

if (hasChild(_Block.text)) {

layoutChild(_Block.text,

new BoxConstraints.tight(Size(size.width, size.height * 0.4)));

positionChild(

_Block.text, new Offset(0.0, size.height - size.height * 0.4));

}

}

@override

bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;

}

自定义的布局是在performLayout这个函数中进行的。入参是个Size,也就是父控件的宽高。函数体就是根据id来取子控件,不同的子控件先调用layoutChild给约束,再调用positionChild摆位置,自定义布局就完成了,是不是很简单?

下拉刷新

====

添加一个Material design风格的下拉刷新比较简单,直接给列表包一个RefreshIndicator就可以了

return RefreshIndicator(

//触发的回调

onRefresh: _onRefresh,

child: ListView.builder()

)

下拉刷新触发的回调通过onRefresh参数设置。在_onRefesh里实现刷新数据的逻辑,需要注意的是函数_onRefresh需要返回Null类型的Future。在这个Future complete之后。刷新的图标会自己消失。效果如图:

Flutter28,android插件化面试

上拉加载更多

======

Flutter没有系统提供的加载更过控件,这里我们想办法做一个比较粗糙的实现。思路是在列表的末尾添加一个加载控件,当滑动到列表底部的时候触发加载的操作。

ListView.builder(

//列表长度加1

itemCount: _articles.length + 1,

itemBuilder: (context, index) {

if (index == _articles.length) {

//如果是最后一个,返回加载更过控件

return LoadingFooter(

retry: () {

loadMore();

},

state: _footerStatus);

} else {

//返回正常列表项

return NewsItem();

}

},

//检测列表滚动状态

controller: _controller));

在创建列表的时候我们给列表长度加1,当要获取最后一项时返回加载更多的控件,同时还要通过controller监测列表滚动状态。这样我们就给列表加了个上拉加载更多的功能。效果如图:

Flutter28,android插件化面试

使用Assets

========

添加 Assets

在Flutter中如果你有图片等文件需要引入到app中,都需要使用Assets, 这个Assets的概念不同于Android中Assets的概念,某种意义上讲, Flutter的Assets更像是Android中Resource。Flutter中添加的asset都需要在pubspec.yaml

中声明。例如,我需要添加一张图片作为加载网络图片时候的占位图,只需要做如下声明就可以了。

flutter:

assets:

  • images/news_cover.png

Android中的Resources我们可以给资源文件夹按照一定规律来命名,这样系统可以挑选最适合的资源,同样的Flutter的Asset也可以。下面的声明就提供了3种不同分辨率的图标。

…/my_icon.png

…/2.0x/my_icon.png

…/3.0x/my_icon.png

访问 Assets

Flutter中访问Assets很灵活,最基本的可以用以下方式来访问Assets:

images/news_cover.png

Android中的Resources我们可以给资源文件夹按照一定规律来命名,这样系统可以挑选最适合的资源,同样的Flutter的Asset也可以。下面的声明就提供了3种不同分辨率的图标。

…/my_icon.png

…/2.0x/my_icon.png

…/3.0x/my_icon.png

访问 Assets

Flutter中访问Assets很灵活,最基本的可以用以下方式来访问Assets:

上一篇:Navigation3


下一篇:Bootstrap 4 中文开发手册 Cards(卡)