Flutter项目初学记 二

130 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

pubspec.yaml

name: life
description: A new Flutter project.

environment:
  sdk: ">=2.17.0-0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  flutter_screenutil: ^5.4.0+1				* 屏幕适配工具
  flutter_picker: ^2.0.3							* 底部弹出选择器
  dotted_border: ^2.0.0+2							* 虚线边框
  flutter_swipe_action_cell: ^2.2.0		* 滑动操作
  images_picker: ^1.2.11							* 图片选择器,允许相机拍照
  flutter_easyloading: ^3.0.3					* 弹出提示组件
  keyboard_dismisser: ^2.0.1					* 键盘自动收起
  dio: ^4.0.6													* 网络请求
  get: ^4.6.1													* 状态管理、路由管理
  get_storage: ^2.0.3									* 内部存储管理
  flutter_swiper: ^1.1.6							* 轮播组件
  webview_flutter: ^3.0.4							* webview组件
  photo_view: 												* 图像预览组件(git仓库版本解决了某些bug)
    git:
      url: https://github.com/bluefireteam/photo_view
      ref: master
  fluwx_no_pay: ^3.8.5								* 微信互动
  scan: ^1.6.0												* 扫码组件
  jpush_flutter: ^2.2.9								* 极光推送
  

dev_dependencies:
  flutter_test:
    sdk: flutter

  assets:
    - assets/images/tabbar/home.png

  fonts:
    - family: IconFont
      fonts:
        - asset: assets/font/iconfont.ttf
  • 项目依赖:dependencies\
    • 尽量制定最新版本引用,避免使用仓库地址引用\
    • 富逻辑插件,在utils做一层包装,确定使用逻辑后,避免更新组件
  • 图片:assets
    • 必须完整路径引用
    • 删除引用必须删除assets目录下对应文件
  • 字体: fonts
    • iconfont字体在此处使用

编码

组件

Flutter 中所有的显示均由组件构成,框架本身提供了包含Material和Cupertino两种风格200+组件

Flutter组件大概可以分为布局、图文、事件、装饰等几个大类

自定义组件

  • 有状态组件

有相应的生命周期,可以响应数据变化,较之无状态组件开销更大的内存,因为我们的项目引入了GetX,所以不建议使用

如果需要响应数据,之后会有说明

class MyWidget extends StatefulWidget {
  const MyWidget({Key? key}) : super(key: key);
  
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String title;
  
  @override
  void initState() {
    super.initState();
    setState(() {
      title = '有状态';
    });
  }
  
  @override
  void didChangeDependencies() {
    // 调用initState会调用
    // 从其他对象中依赖一些数据发生改变时
    super.didChangeDependencies();
  }
  
  @override
  void didUpdateWidget(state) {
    // 当父组件触发rebuild
    super.didUpdateWidget(state);
  }
  
  @override
  Widget  build(BuildContext context) {
    return Text(title);
  }
  
  @override
  void dispose() {
    //组件销毁时
    super.dispose();
    print('组件被销毁');
  }
}
  • 无状态组件

组件创建完成不能再被更新

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  final title = '无状态';

  @override
  Widget build(BuildContext context) {
    return Text(title);
  }
}

//函数式组件
Widget myWidget(title){
   return Text(title);
}

组件传参

组件之间常用的参数传递方法

class Fa extends StatelessWidget {
  const Fa({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Son(title:'标题',
               valChanged:(val){
                  print(val);
                }
           )
  }
}
↓↓↓			↑↑↑
class Son extends StatelessWidget {
  const Son({Key? key,
             this.title='暂无标题',//非必填,需要默认赋值
             required this.valChanged //回调子传父
            }}) : super(key: key);
	const Son({Key? key,required this.title}) : super(key: key);//必填,声明加上required
  final String title;
  final ValueChanged valChanged;
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      			onTap: (val) =>valChanged(val),//子传父调用
    				child: Text(title)//父组件传过来的
    			)
  }
}

GetX的使用

GetX是一个由开源社区发布的Flutter状态管理与路由管理及其他工具的一个集合插件

  • 数据的双向绑定
class Logic extends GetxController {
  RxList<dynamic> msgList = [].obs;

  void getMsgList() {
    msgList.value = [
      {'name': '周生', 'num': 25},
      {'name': '王生', 'num': 24}
    ];
    update();
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
      final logic = Logic();
      logic.getMsgList();
    	return Obx(()=>Text(logic.msgList[0].name));//添加点击事件不需要setState就可以改变msgList并反应在视图
  }
}
  • 路由管理

Getx路由相较于flutter自带的路由略去了上下文,可以更方便的随处调用,同时也更简单的提供了中间件的实现,详见utils/router

常用组件

以下仅是简单示例,属性繁多,请查看官方文档

Container

创建一个指定宽高、对齐方式、装饰属性的容器(只指定宽高可替代为SizedBox)

Container(
    margin: EdgeInsets.only(top: 20.h,left: 20.w),
    width: double.infinity,//匹配父组件宽度(父组件需固定宽度)
    height: 200.h,
    alignment: Alignment.center,
    decoration: BoxDecoration(
      border: Border.all(color: Colors.red, width: 1),
    ),
  )
  
  //margin/padding属性常用取值
  * EdgeInsets.all(10.r)//统一距离
  * EdgeInsets.only(top: 20.h,left: 20.w)//指定方向
	* EdgeInsets.symmetric(horizontal: 36.w,vertical: 20.h)//指定轴向

Flex、Row、Column

创建一个制定轴向的排列容器(Flex需要通过属性定义轴向)

 Row/Column(
    mainAxisAlignment:MainAxisAlignment.spaceBetween,
    children: [
      A(),B()
    ],
  )