Flutter之根据运行的platform显示对应风格的widget
Flutter中的Cupertino和Material小部件 介绍 最近也在想,要如何实现FLutter在Android平台上显示Material风格的UI,在ios平台显示Cupertino风格的UI,刚好看到一篇外国文章:Do Flutter apps dream of platform aware widgets?,讲的就是这个问题,于是自己也跟着实现了一下。总的来说,不难,主要是抽象出一个BasePlatformWidget就可以了。
背景 Flutter是一个新的跨平台应用程序开发框架。Flutter中有两套UI组件,分别适用于ios和Android,分别叫做Cupertino和Material。
但是如果希望在各自的平台上继续保持原来的风格的话,比如在Android手机上保持Material风格,在ios上保持Cupertino风格的话,那应该如何实现呢?
如果要写两套代码的话,就太麻烦了。因为两套代码其实有大部分东西是一样的,只是因为风格不一样,而用了不一样的Widget而已。在FLutter中还要注意的一点问题就是,某一些小部件需要一个属于同一“平台特定”库的祖先。举个例子,RaisedButton和Switch属于Material包库,它需要一个Material小部件作为其祖先之一,如果没有的话,则运行的时候会报出下面的错误。
image 实现思路:我们可以创建个抽象的组件,并让它根据其运行的平台,显示不同风格的Widget。
代码实现 创建一个抽象类,子类只需要重写对应平台的抽象方法就可以了。
/**
- 会根据平台,去适配所在平台的小部件
-
Flutter中包含了适用于IOS和Android的两套原生小部件,名为Cupertino和Material */ abstract class BasePlatformWidget<A extends Widget, I extends Widget> extends StatelessWidget { A createAndroidWidget(BuildContext context);
I createIosWidget(BuildContext context);
@override Widget build(BuildContext context) { /**如果是IOS平台,返回ios风格的控件
- Android和其他平台都返回materil风格的控件 */ if (Platform.isIOS) { return createIosWidget(context); } return createAndroidWidget(context); } } 下面根据这个基础的平台类,去创建一些基本的Widget。比如去创建一个在Android平台显示AppBar,在ios平台显示CupertinoNavigationBar的Widget。
/**
-
脚手架 */ class PlatformScaffold extends BasePlatformWidget<Scaffold, CupertinoPageScaffold> { PlatformScaffold({this.appBar, this.body});
final PlatformAppBar appBar; final Widget body;
@override Scaffold createAndroidWidget(BuildContext context) { return Scaffold( appBar: appBar.createAndroidWidget(context), body: body, ); }
@override CupertinoPageScaffold createIosWidget(BuildContext context) { return CupertinoPageScaffold( navigationBar: appBar.createIosWidget(context), child: body, ); } }
/**
-
AppBar */ class PlatformAppBar extends BasePlatformWidget<AppBar, CupertinoNavigationBar> { final Widget title; final Widget leading;
PlatformAppBar({this.title, this.leading});
@override AppBar createAndroidWidget(BuildContext context) { return new AppBar(leading: leading, title: title,); }
@override CupertinoNavigationBar createIosWidget(BuildContext context) { return new CupertinoNavigationBar(leading: leading, middle: title,); }
}
/**
-
对话框 */ class PlatformAlertDialog extends BasePlatformWidget<AlertDialog, CupertinoAlertDialog> {
final Widget title; final Widget content; final List
actions; PlatformAlertDialog({this.title, this.content, this.actions});
@override AlertDialog createAndroidWidget(BuildContext context) { return new AlertDialog(title: title, content: content, actions: actions,); }
@override CupertinoAlertDialog createIosWidget(BuildContext context) { return new CupertinoAlertDialog( title: title, content: content, actions: actions,); } }
/**
- Switch */
class PlatformSwicth extends BasePlatformWidget<Switch, CupertinoSwitch> {
final bool value;
final ValueChanged
PlatformSwicth({this.value, this.onChanged});
@override Switch createAndroidWidget(BuildContext context) { return new Switch(value: value, onChanged: onChanged); }
@override CupertinoSwitch createIosWidget(BuildContext context) { return new CupertinoSwitch(value: value, onChanged: onChanged); } }
/**
-
Button */ class PlatformButton extends BasePlatformWidget<FlatButton, CupertinoButton> { final VoidCallback onPressed; final Widget child;
PlatformButton({this.onPressed, this.child});
@override FlatButton createAndroidWidget(BuildContext context) { return new FlatButton(onPressed: onPressed, child: child); }
@override CupertinoButton createIosWidget(BuildContext context) { return new CupertinoButton(child: child, onPressed: onPressed); } }
运行实例
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } }
class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override _MyHomePageState createState() => new _MyHomePageState(); }
class _MyHomePageState extends State
bool androidSelected = false; bool iosSelected = false;
@override Widget build(BuildContext context) { return new PlatformScaffold( appBar: new PlatformAppBar( title: new Text(widget.title),
),
body: new SafeArea(child: new Container(
child:
new Column(
children: [
new CupertinoButton(
child: new Text("显示ios风格的对话框"), onPressed: () {
showDialog(context: context, builder: (context) {
return new CupertinoAlertDialog(
title: new Text("title"),
content: new Text("content"),
actions:
[
new CupertinoButton(onPressed: () {},
child: new Text("Cancel")),
new CupertinoButton(onPressed: () {},
child: new Text("Confirm")),
]
,
);
});
}),
new FlatButton(child: new Text("显示android风格的对话框"), onPressed: () {
showDialog(context: context, builder: (context) {
return new AlertDialog(
title: new Text("title"),
content: new Text("content"),
actions:
[
new FlatButton(onPressed: () {},
child: new Text("Cancel")),
new FlatButton(onPressed: () {},
child: new Text("Confirm")),
]
,
);
});
}),
//下面这段代码在ios平台运行会出错,在android平台可以运行,所以暂时注释掉,原因就是Switch需要有一个Material的祖先 // new Switch( // value: androidSelected, onChanged: (value) { // setState(() { // androidSelected = value; // }); // },), new CupertinoSwitch(value: iosSelected, onChanged: (value) { setState(() { iosSelected = value; }); }),
],
)
),),
);
} }
发表评论