4

第二次尝试Flutter

 2 years ago
source link: https://mrleidesen.github.io/posts/flutter_try_second/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第二次尝试Flutter

2021-03-11 13:53:48 · MrLeiDeSen

前言#

学了几天flutter,感觉写起来还是很香的,比原生开发速度快很多,不过以前没接触过安卓开发,思维还在Web开发上,记录一下

布局#

一般是使用ColumnRow以及Container来布局比较多,还有Expanded,类似与flex: 1这个效果,能把剩余的空间补充满。

在使用的时候还遇到了按钮宽度需要100%的情况,2.0废弃了1.0一些组件,按钮一般使用ElevatedButton,但是没法设置宽高。网上查了一下用SizedBox来当它的父容器,这样它就会跟着父容器的宽高走了,需要宽度100%的话就是double.infinity

如何设置width:100%#

目前发现有double.infinityMediaQuery.of(context).size.width。后续发现的话继续补充

路由#

路由的话一般定义在MaterialApp里面,如下:

return MaterialApp(
    title: 'title',
    initialRoute: "/home", // 默认的路由
    routes: {
        "/home": (context) => MyHome(), // 每个路由需要默认传参context
        "/login": (context) => MyLogin()
    },
);

导航的话常用以下几个

Navigator.pushNamed(context, "/login"); // 跳转到/login页面
Navigator.pop(context); // 返回上一级,可传第二个参数携带回上一级
Navigator.pushReplacementNamed(context, "/login"); //重定向至/login页面,就没法返回到上一级页面了

父子组件传参#

  • 父组件调用子组件
// 定义一个全局key
GlobalKey<_MyMapState> mapKey = GlobalKey();

// 子组件
class MyMap extends StatefulWidget {
  MyMap({Key key}) : super(key: key);
  @override
  _MyMapState createState() => _MyMapState();
}
class _MyMapState extends State<MyMap> {
    // ...
    void getItem() {
        print('get');
    }
}

// 父组件
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
        children: [
            TextButton(
                child: Text('Click'),
                onPressed: () {
                    // 调用子组件方法
                    mapKey.currentState.getItem();
                }
            ),
            // 在引入子组件时,传入全局key
            MyMap(key: mapKey)
        ]
    );
  }
}
  • 子组件调用父组件
// 子组件
// 父组件通过传参传入方法,子组件调用
class MyMap extends StatefulWidget {
  final changeParent;
  MyMap({Key key, this.changeParent}) : super(key: key);
  @override
  _MyMapState createState() => _MyMapState();
}
class _MyMapState extends State<MyMap> {
    // ...
    void getItem() {
        // 调用父组件
        widget.changeParent();
    }
}

滚动监听#

在Flutter中使用滚动监听,首先在定义一个ScrollController以及监听

ScrollController _controller = new ScrollController();

@override
void initState() {
super.initState();
    // 在init生命周期中
    // controller添加监听
    _controller.addListener(_listenController);
}

@override
void dispose() {
    // 在dispose生命周期中销毁controller
    _controller.dispose();
    super.dispose();
}

// 监听方法
void _listenController() {
    // 获取当前滚动组件的最大高度
    final maxHeight = _controller.position.maxScrollExtent;
    // 当前滚动的高度
    final nowScrollPosition = _controller.offset;
    // 根据需要进行判断
    // 此处计算百分比超过95,则加载下一页内容
    if ((nowScrollPosition / maxHeight) * 100 >= 95) {
      pageNum += 1;
      _fetchImages();
    }
}

之后将Controller传给ListView,记住ListView嵌套在Scrollbar

return Scrollbar(
    child: ListView.builder(
        padding: EdgeInsets.all(16),
        // 加入controller
        controller: _controller,
        itemExtent: 230,
        itemCount: _images.length,
        itemBuilder: (context, index) {
            final item = _images[index];
            final id = item["id"];
            final author = item['author'];
            final url = "https://picsum.photos/id/$id/200/200";

            return Container(
            width: 300,
            height: 230,
            child: Column(
                children: [
                Image.network(
                    url,
                    width: 300,
                    height: 200,
                    fit: BoxFit.cover,
                ),
                Text(author)
                ],
            ),
            );
        }));

文本#

输入框的话是通过TextField这个Widget来的

return TextField(
    onChanged: (text) {
        // 获取每次更改的值
        print(text);
    },
    decoration: InputDecoration(), // 修改输入框样式
);

如果我们需要清空文本框,可能就要用到controller

final _controller = TextEditingController();

// 清空输入框
void _clearTextField() {
    _controller.clear();
}

// 获取输入框的内容
void _getTextField() {
    print(_controller.text);
}

// 生命周期结束时销毁controller
@override
void dispose() {
    _controller.dispose();
    super.dispose();
}

return TextField(
    controller: _controller
);

总结#

如果是Web开发,可能思想上会有点不一样,多写写就能领悟到了。用Flutter进行快速开发的话还是很香的,毕竟只是为了出成品,速度足够快。不过在原生操作上还是有不少问题,毕竟只是节约成本的一个方法,如果真正投入使用,可能最终还得转到原生开发上去。
如果有时候代码写得正确,但是莫名其妙报错,有可能是flutter热更新的问题,试着重新启动一下,可能就好了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK