Flutter 之 Widget 部件体验
Flutter 与 React Native 的对比
React Native
React Native
是在原生 UI
的基础上进行了包装,把原生的 UIKit
框架中的 UI
控件包装成 React Native
中的控件,然后调用 React Native
也就是调用 js
代码,然后通过 js
代码调用 React Native
框架,然后通过 React Native
再调用原生的 UI
并进行加载。这样的话相对于 flutter
,React Native
的渲染速度会慢了很多,但是 React Native
也做了很多的优化。最主要的弊端是它是基于原生 UI
进行包装的,如果原生 UI
更新了,React Native
也要进行更新,进行兼容,这样的话对原生的依赖就会非常大。还有就是因为 React Native
是通过 js
分别调用 iOS
跟安卓的原生 UI
进行渲染,所以虽然是一套代码,但是没法保证 UI
的展示效果一致。Weex
也会有类似问题。
Flutter
Flutter
能同时运行在 iOS
跟安卓上的原因是因为它们都安装了渲染引擎。Flutter
不是基于原生 UI
进行展示的,而是把渲染引擎安装到手机上,这里有个弊端就是每个基于 Flutter
开发的 App
都需要安装一个渲染引擎,就会导致 App
包会比较大。渲染引擎负责解析 dart
代码,然后展示渲染的界面。但是它的优点是效率高,而且不依赖原生 UI
。而且都是依赖渲染引擎渲染,所以可以做到多端的 UI
高度统一。
React Native
具有热更新功能,相对这点来说 Flutter
就会比较麻烦,Flutter
具有热重载功能,但是只是限于 debug
版本下。relase
版本下开发者可以自定义开发。这里就需要涉及到渲染引擎,可以通过这种方式实现自己的热重载,实现了热重载也就实现了热更新,但是实现起来会比较复杂。谷歌之所以没有定义一套统一的标准供所有的开发者进行使用是因为苹果对这一块是禁止的,所以在苹果的生态下这种技术没有生存的空间,可能这也是谷歌没有这样去做的原因。
我们实现的 dart
代码通过渲染引擎的底层去解析,解析完成之后进行界面展示。但是渲染引擎在 iOS
跟安卓系统下执行的时候需要依赖各自的开发语言,iOS
下可以选择 swit
或者 oc
,安卓下可以选择 java
或者 kotlin
。同时 flutter
还能支持 macOS
,windows
,linux
,web
。支持桌面系统的话需要到官网下载不同的 sdk
版本。
Flutter 小部件之 Text
void main() {
// 对于不变的控件建议用 const 修饰
runApp(const Center(
child: Text(
'hello flutter',
// textDirection 代表文字的阅读方向
textDirection: TextDirection.ltr,
),
));
}
在 Flutter
中如果要显示一个控件,需要在 main
函数中执行 runApp
方法,并在此方法中添加要显示的控件,这里 Center
也是一个 Widget
,添加到 Center
中的子部件会居中显示。这里 Text
是一个文字显示部件,textDirection
代表文字的阅读方向。Flutter
中对于不会变的控件建议用 const
修饰,这样回提高渲染效率。因为 Flutter
是增量渲染,只会渲染改变的控件,用 const
修饰代表这个节点不会改变。
自定义 Widget
void main() => runApp(MyWidget());
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'hello flutter',
// textDirection 代表文字的阅读方向
textDirection: TextDirection.ltr,
),
);
}
}
Widget
分为有状态 StatefulWidget
与无状态 StatelessWidget
两种,无状态的 Widget
如果需要改变的话只能替换一个新的 Widget
,而有状态的 Widget
可以修改里面的子部件。代码示例中我们自定义了一个继承与 无状态 StatelessWidget
的 Widget
。
Text 部件文字样式
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'hello flutter',
// textDirection 代表文字的阅读方向
textDirection: TextDirection.ltr,
style: TextStyle(
// 文字颜色
color: Colors.red,
// 文字大小
fontSize: 40.0,
// 粗体
fontWeight: FontWeight.bold
),
),
);
}
}
这里我们设置了文字的大小,颜色跟样式,更多的属性设置大家也可以点进入看或者看下官方文档。
MaterialApp
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: MyWidget(),
),
);
}
}
ListView
class Car {
const Car({this.name, this.imageUrl});
final String? name;
final String? imageUrl;
}
final List<Car> datas = [
const Car(
name: '保时捷918 Spyder',
imageUrl:
'https://img.haomeiwen.com/i2990730/7d8be6ebc4c7c95b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '兰博基尼Aventador',
imageUrl:
'https://img.haomeiwen.com/i2990730/e3bfd824f30afaac?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '法拉利Enzo',
imageUrl:
'https://img.haomeiwen.com/i2990730/a1d64cf5da2d9d99?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: 'Zenvo ST1',
imageUrl:
'https://img.haomeiwen.com/i2990730/bf883b46690f93ce?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '迈凯伦F1',
imageUrl:
'https://img.haomeiwen.com/i2990730/5a7b5550a19b8342?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '萨林S7',
imageUrl:
'https://img.haomeiwen.com/i2990730/2e128d18144ad5b8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '科尼赛克CCR',
imageUrl:
'https://img.haomeiwen.com/i2990730/01ced8f6f95219ec?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '布加迪Chiron',
imageUrl:
'https://img.haomeiwen.com/i2990730/7fc8359eb61adac0?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '轩尼诗Venom GT',
imageUrl:
'https://img.haomeiwen.com/i2990730/d332bf510d61bbc2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '西贝尔Tuatara',
imageUrl:
'https://img.haomeiwen.com/i2990730/3dd9a70b25ae6bc9?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
)
];
import 'package:demo/Model/car_model.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatelessWidget {
Widget _itemForRow(BuildContext context, int index) {
return Container(
color: Colors.white,
margin: EdgeInsets.all(10),
child: Column(
children: [
Image.network(datas[index].imageUrl ?? ''),
SizedBox(height: 10),
Text(datas[index].name ?? '')
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('list Demo'),
),
body: ListView.builder(
itemBuilder: _itemForRow,
itemCount: datas.length,
),
);
}
}
这里我们用 ListView
部件实现一个列表,创建 ListView
的时候需要实现两个属性 itemBuilder
跟 itemCount
,itemBuilder
是 IndexedWidgetBuilder
类型,typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index)
。我们定义了一个私有方法 _itemForRow
返回列表中的每一个视图,相当于 UITableView
中的 tableView:cellForRowAtIndexPath:
方法,返回一个 cell
。itemCount
代表列表中数据的条数。