本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Flutter基础知识小结
基本组件
Flutter有着万物皆为Widget的思想,那么学习路径首要的当然是要学习一些基本的Wiget了,下面是在项目中使用到的一些Wiget,大概介绍一下用法和适用场景。
ListView
适合用于列表项较少且已知数量的情况。
ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: <Widget>[
const Text('apple'),
const Text('banana'),
const Text('lemon'),
],
);
ListView.builder
适合用于列表项较多或者数量不确定的情况,ListTile用于构建列表项,实际项目中列表项可以自定位为需要的Widget。
ListView.builder(
itemCount: 100,
itemExtent: 50.0, // 指定列表项高度
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
}
);
ListView.separated
相比于ListView.builder多了个separatorBuilder参数,用于在列表项之间添加分割线。
ListView.separated(
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
},
itemCount: 20,
separatorBuilder: (BuildContext context, int index) =>
const Divider(
height: 0.5,
color: Colors.blue
)
);
SmartRefresher
用于实现上拉加载和下拉刷新列表,常配合ListView使用。
使用前需要在pubspec.yaml中添加组件依赖
pull_to_refresh: 2.0.0
来看一下具体实现,实现细节已经添加了较为详细的注释:
/// 列表刷新控制器
final RefreshController _refreshController = RefreshController(initialRefresh: false);
SmartRefresher(
enablePullDown: true, // 启动下拉刷新
enablePullUp: true, // 启动上拉加载
controller: _refreshController, // 刷新控制器
// 下拉刷新时顶部显示内容
header: WaterDropHeader(
waterDropColor: Color.blue,
refresh: SpinKitFadingCircle(
color: Color.grey,
size: 20.w,
),
complete: Text('刷新成功', style: idleTextStyle),
failed: Text('刷新失败', style: idleTextStyle),
),
// 上拉加载时底部显示内容
footer: CustomFooter(
height: 30.w,
builder: (BuildContext context, LoadStatus? mode) {
Widget? footer;
if (mode == LoadStatus.canLoading) {
footer = Text(_isEnd ? '没有更多了' : '松手开始加载',
style: idleTextStyle);
} else if (mode == LoadStatus.failed) {
footer = Text('加载失败,请重试', style: idleTextStyle);
} else if (mode == LoadStatus.noMore) {
footer = Text('没有更多了', style: idleTextStyle);
} else {
footer = null;
}
return SizedBox(
height: 30.w,
child: Center(
child: footer,
),
);
},
),
// 下拉刷新方法
onRefresh: _onRefresh,
// 上拉加载方法
onLoading: _onLoading,
// 列表内容,这里使用了带分割线的ListView
child: ListView.separated(
itemBuilder: (BuildContext context, int index) {
return _buildItem;
},
itemCount: _totalItems,
separatorBuilder: (BuildContext context, int index) =>
const Divider(
height: 0.5,
color: Colors.blue,
)
)
);
手势监听
GestureDetector
Flutter中针对某个组件的点击滑动事件,需要使用GestureDetector进行监听,针对不同手势有不同的监听方法,具体可以参考链接
使用方法:
return GestureDetector(
onTap() {
print("click the container");
},
child: Container(
// TODO
);
);
动画
Animation
以下示例是实现一个组件渐现动画:
(1)初始化AnimationController和Animation
AnimationController controller = AnimationController(duration: Duration(milliseconds: 500), vsync: this);
Animation animation = Tween<double>(begin: 0, end: 200.0).animate(controller)
..addListener((){
setState((){});
});
(2)在组件定义处使用动画值
return Container(
height: amimation.value;
// TODO
);
Hero
Hero可以实现组件跨页面"飞跃"的动画,实现方法非常简单,只需要在两个页面的组件上层用Hero包装一层,并且使用同一个tag即可
return Hero(
tag: "tagName"
child: Image.asset("../test.png");
);
平台通道Channel
Flutter中通过Channel建立与IOS和Android平台之间的连接
-
BasicMessageChannel:字符串和半结构化数据传递 -
MethodChannel:方法调用 -
EventChannel:消息流通信 -
MethodChannel用法实例 1.在Flutter平台的
main.dart中创建Channel,并调用获取电池状态的方法
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel("com.example.alvintube/getBatteryLevel");
String _batteryLevel = "unknown battery level.";
Future<Null> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod("getBatteryLevel");
batteryLevel = "Battery level at $result % .";
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level ${e.message} ";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
2.添加ui控件,给点击时间注册响应方法,并将返回的电池状态显示出来
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: new Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel)
],
),
)
);
}
3.Android项目中注册Channel,并实现获取电池状态的方法
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.alvintube/getBatteryLevel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getBatteryLevel() : Int {
val batteryLevel: Int;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
}