flutter与RN的异同
- 均实现了跨平台
- 都支持热重载,开发调试非常方便
- RN基于React,使用js开发,受众较广,flutter则是使用Dart,受众小,对于Java开发人员来说非常友好
- 通俗来讲,RN的UI框架是将JS转化为原生控件,所以流畅度会比webview要高,而flutter则是从更底层进行控件的绘制,直接废弃了原生UI控件,性能要比RN更高!可以将flutter的应用理解成一个跨平台的游戏引擎写的游戏APP。
- RN发展较早,比flutter稳定,flutter的第三方库还很少
flutter界面控件
在flutter中,所有控件都是widget,页面(可以理解成Android的activity,iOS的controller)和应用程序自身都是一个widget。
flutter中存在两种widget,StatelessWidget用于定义无状态控件,适用于显示静态文字、图片等,这种控件在编译运行后无法更新内容;StatefulWidget用于定义有状态控件,后期可以通过调用setState方法来刷新内容,用途更广,更灵活。
flutter自带了Material Design的整套UI设计控件,可构建非常完整MD风格的APP,也拥有用于当前iOS设计语言的美丽和高保真widget。
详细widget控件目录可浏览flutter中文官网
flutter构建页面
在flutter中页面自身也是widget,以下示例中的MaterialApp控件提供了MD风格的整套UI模板,另外也有针对iOS风格的CupertinoApp
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 这个widget是这个应用的根部widget
@override
Widget build(BuildContext context) {
return MyHomePage();
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
// 这是应用的主页widget,同时它是一个有状态的widget,意味着它可以动态刷新内容
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
//当你调用setState方法时,会通知framework触发build方法,刷新UI界面
_counter++;
});
}
@override
Widget build(BuildContext context) {
//当你条用setState方法,build方法就会被触发,刷新UI
return MaterialApp(
//设置路由
routes: < String, WidgetBuilder > {
'/a':(_) => PageA(),
'/b':(_) => PageB()},
title: 'Flutter Demo',
home: Scaffold(
backgroundColor: Colors.white70,
appBar: AppBar(
title: Text('hello flutter'),
),
body: Center(
child: Text('hello flutter onclick-count = $_counter'),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
),
);
}
}
值得注意的是MyApp自身是StatelessWidget,是无状态的widget,但由于它内部存在StatefulWidget,所以它是可以通过StatefulWidget来更改UI
flutter触摸事件
flutter中,除了RaisedButton、FlatButton、IconButton等一系列按钮控件外,其余widget是不具备onPressed属性的,但是flutter提供了一个更加强大的手势监听widget:GestureDetector,支持单机、双击、长按等常见触摸事件,当你某个widget需要某些触摸事件时,可在GestureDetector嵌套该widget。
GestureDetector(
//双击
onDoubleTap: (){
},
//长按
onLongPress: (){
},
//单击
onTap: (){
_incrementCounter();
},
child: Text('hello flutter onclick-count = $_counter'),
),
flutter页面跳转
路由分为静态路由和动态路由
静态路由
有两种注册方式
1.修改主方法,用MaterialApp或其他WidgetsApp来包裹MyApp,设置路由
void main() => runApp(MaterialApp(home: MyApp(),
routes: < String, WidgetBuilder > {
'/a':(_) => PageA(),//页面A
'/b':(_) => PageB()//页面B
},
));
2.直接在MyApp的类中设置属性,请参考flutter构建页面这一章节
然后通过
//切换到B页面
Navigator.pushNamed(context, '/b');
动态路由
动态路由则不需要事先注册,灵活度更高,使用方式更多,方便传值以及设置转场动画
Navigator.push(context, PageRouteBuilder(pageBuilder: (BuildContext context, Animation < double > animation,
Animation < double > secondaryAnimation) {
//下一个页面
return Center(
child: GestureDetector(
onTap: () {
//返回上一个页面
Navigator.pop(context);
},
child: Text('haha'),
),
);
//构建转场动画
}, transitionsBuilder: (BuildContext context,
Animation < double > animation,
Animation < double > secondaryAnimation,
Widget child) {
//自定义转场动画
return new SlideTransition(
position: new Tween < Offset > (
begin: const Offset(3.0, 0.0),
end: const Offset(0.0, 0.0),
).animate(animation),
child: child,
).build(context);
}));
如果你想使用系统默认的动画,推荐直接使用MaterialPageRoute
Navigator.push(context,MaterialPageRoute(builder: (context){
//下一个页面
return Center(
child: GestureDetector(
onTap: () {
//返回上一页
Navigator.pop(context);
//返回上一页,并且返回一个200的值,可以是其他值,用于回调场景
//Navigator.pop(context,200);
},
child: Text('haha'),
),
);
//用于接收下一个页面返回的值
})).then((data){
print(data);
});
建议通过自定义StatefulWidget来构建下一个可刷新的页面,更便于传值
Navigator.push(context,MaterialPageRoute(builder: (context){
//Page为StatefulWidget参数即可达到传值的效果
return Page(id:'1023');
}));
flutter与原生交互
Android
首先,在flutter中声名如下方法
Future<Null> _tryConnectAndroid() async {
try {
//注册方法频道
MethodChannel platform = MethodChannel('samples.test/test');
//第一个参数 tryToast为Java/oc中的方法名(后面会讲),第二个参数数组为传参数组
String result= await platform.invokeMethod('tryToast',[{'msg':"flutter connect android"}]);}
//result 为回调的结果
on PlatformException catch (e){
}
}
然后在flutter项目的Android目录找到MainActivity
public class MainActivity extends FlutterActivity {
//需要与flutter的MethodChannel名称对应
static String CHANNEL="samples.test/test";
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
//注册方法
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
//找到对应的方法名
if (call.method.equals("tryToast")) {
//传递过来的参数列表
ArrayList arguments = (ArrayList)call.arguments;
String msg =((Map<String,String>)arguments.get(0)).get("msg");
//回调结果
result.success("hello flutter");
// start();
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_LONG).show();
}
}
});
}
}
iOS
iOS的请参考此链接
flutter打包apk与ipa
apk打包
apk打包相对简单,和以往的Android打包一样,在gradle文件里配置好签名信息等,运行一下指令即可
flutter build apk
IPA的请参考此链接
总结
学习flutter两三个星期,一开始被它多重嵌套的UI写法吓到了,后来习惯下来还是比较得心应手的,虽然写UI的时候不能像Android写xml一样能够即使预览,但是得益于热重载的功能,实际上你一边写UI一边在模拟器和手机上预览UI也是完全没有问题的。flutter提供了大量的UI控件,方便开发者灵活使用,像上文所说,flutter是直接抛弃了原生控件,通过图像引擎利用Android/iOS的画布将UI绘制出来,性能当然要比RN通过JavaScript转换成原生UI控件要高,通过Android手机查看基于flutter缩写APP的UI层级时,会发现APP的UI只有一个层级,它是一个整体的View,不像以往Android需要进一步优化布局层级。
flutter的定义是极速构建漂亮的原生应用,是一套移动UI框架,flutter只是能够帮助开发者更有效率地构建UI,如果APP的业务需要调用大量的手机系统特性时,开发者仍需要转移到原生开发中,所以开发者能够同时掌握Android、iOS开发就最好不过了。
更多关于flutter的文档可查阅此链接