Flutter基础知识小结

256 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

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
    }
}