IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter基础概述 -> 正文阅读

[移动开发]Flutter基础概述

一、基础概念,参考资料

flutter主要发展方向为移动端跨平台方案。flutter的实现语言是dart,native端可支持的语言是安卓侧java、kotlin,ios侧oc、swift。
参考官网:
https://flutterchina.club/docs/
https://flutter.dev/docs

依赖仓库地址:
https://pub.dev/
这个地址有所有的dart依赖仓库,通知也托管所有的flutter公共依赖。

二、主要模块

  1. 基础语法
    在flutter中一切都是widget,包括基础组件,布局组件,样式组件,全部都用widget定义,这个带来了一些问题,样式和ui混合到了一起,如果自己团队没有设定一些约束,设定一些公用style,工程上显得比较混乱。
  • text
Text("我是一个text", style:TextStyle(fontSize:12,color:Colors(0xff333333)));
  • image
Image(image: AssetImage("images/my_image.png", package: 'my_package_name'));
Image(image: NetworkImage("https://xxx.xxx.xxx.png"));
  • button
Botton(
	onTap:()=>{//dosomething},
	image:Image.asset("xxxx.png"),
	title:Text("xxxx"),
);
  • 样式布局
Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.center,
            children:[
				Text(...),
				Button(...),
				Row(...),
			],
			padding:const EdgeInsets.fromLTRB(20, 30, 20, 20),
);
///	container
///	row
  1. 工程类型
    使用指令flutter create -t,可以创造一个仓库模板,仓库有几种类型,参考flutter create -h的说明,列举为下
  • app (default) Generate a Flutter application.
    主工程
  • module Generate a project to add a Flutter module to an existing Android or iOS application.
    如果想把flutter代码加入已有的Android、iOS工程下,可以使用这个仓库模板
  • puglin Generate a shareable Flutter project containing an API in Dart code with a platform-specific implementation for Android, for iOS code, or for both.
    包含Android或者iOS实现的仓库
  • package Generate a shareable Flutter project containing modular Dart code.
    仅包含dart代码的仓库,这个仓库可以创建.android和.ios两个隐藏文件夹作为运行环境,进行测试
  • skeleton Generate a List View / Detail View Flutter application that follows community best practices.
    未使用过
  1. 状态管理
  • StatelessWidget和StatefulWidget
    不需要做变更的组件,使用StatelessWidget即可。
    可能有状态变化的组件,使用StatefulWidget。
	class VariedWidget extends StatefulWidget {
	  @override
	  State<StatefulWidget> createState() {
	    return VariedState();
	  }
	}
	
	class VariedState extends State<VariedWidget> {
	  String _state = "before";
	
	  @override
	  Widget build(BuildContext context) {
	    return Column(
	      children: [
	        Text(_state),
	        TextButton(
	            onPressed: () => {
	                  setState(() {
	                    _state = "after";
	                  })
	                },
	            child: Text('点击改变状态'))
	      ],
	    );
	  }
	}
  • 共享状态管理Provider
  • 状态管理框架介绍
    Provider是官方解决多个组件共用状态的方案,了解它也可以帮助我们理解其它第三方的状态管理框架
    上述两点一同参考我编写的文档
    https://docs.qq.com/doc/DRUxseWhXQ2FZWHdi
  1. 路由管理
  • navigator
    官方基础方案,查看Navigator.dart了解更多细节。官网示例:
	import 'package:flutter/material.dart';
	
	// ...
	
	void main() => runApp(const MyApp());
	
	// ...
	
	class MyApp extends StatelessWidget {
	  const MyApp({Key? key}) : super(key: key);
	
	  @override
	  Widget build(BuildContext context) {
	    return MaterialApp(
	      title: 'Flutter Code Sample for Navigator',
	      // MaterialApp contains our top-level Navigator
	      initialRoute: '/',
	      routes: <String, WidgetBuilder>{
	        '/': (BuildContext context) => const HomePage(),
	        '/signup': (BuildContext context) => const SignUpPage(),
	      },
	    );
	  }
	}
	
	class HomePage extends StatelessWidget {
	  const HomePage({Key? key}) : super(key: key);
	
	  @override
	  Widget build(BuildContext context) {
	    return DefaultTextStyle(
	      style: Theme.of(context).textTheme.headline4!,
	      child: Container(
	        color: Colors.white,
	        alignment: Alignment.center,
	        child: const Text('Home Page'),
	      ),
	    );
	  }
	}
	
	class CollectPersonalInfoPage extends StatelessWidget {
	  const CollectPersonalInfoPage({Key? key}) : super(key: key);
	
	  @override
	  Widget build(BuildContext context) {
	    return DefaultTextStyle(
	      style: Theme.of(context).textTheme.headline4!,
	      child: GestureDetector(
	        onTap: () {
	          // This moves from the personal info page to the credentials page,
	          // replacing this page with that one.
	          Navigator.of(context)
	            .pushReplacementNamed('signup/choose_credentials');
	        },
	        child: Container(
	          color: Colors.lightBlue,
	          alignment: Alignment.center,
	          child: const Text('Collect Personal Info Page'),
	        ),
	      ),
	    );
	  }
	}
	
	class ChooseCredentialsPage extends StatelessWidget {
	  const ChooseCredentialsPage({
	    Key? key,
	    required this.onSignupComplete,
	  }) : super(key: key);
	
	  final VoidCallback onSignupComplete;
	
	  @override
	  Widget build(BuildContext context) {
	    return GestureDetector(
	      onTap: onSignupComplete,
	      child: DefaultTextStyle(
	        style: Theme.of(context).textTheme.headline4!,
	        child: Container(
	          color: Colors.pinkAccent,
	          alignment: Alignment.center,
	          child: const Text('Choose Credentials Page'),
	        ),
	      ),
	    );
	  }
	}
	
	class SignUpPage extends StatelessWidget {
	  const SignUpPage({Key? key}) : super(key: key);
	
	  @override
	  Widget build(BuildContext context) {
	    // SignUpPage builds its own Navigator which ends up being a nested
	    // Navigator in our app.
	    return Navigator(
	      initialRoute: 'signup/personal_info',
	      onGenerateRoute: (RouteSettings settings) {
	        WidgetBuilder builder;
	        switch (settings.name) {
	          case 'signup/personal_info':
	          // Assume CollectPersonalInfoPage collects personal info and then
	          // navigates to 'signup/choose_credentials'.
	            builder = (BuildContext context) => const CollectPersonalInfoPage();
	            break;
	          case 'signup/choose_credentials':
	          // Assume ChooseCredentialsPage collects new credentials and then
	          // invokes 'onSignupComplete()'.
	            builder = (BuildContext _) => ChooseCredentialsPage(
	              onSignupComplete: () {
	                // Referencing Navigator.of(context) from here refers to the
	                // top level Navigator because SignUpPage is above the
	                // nested Navigator that it created. Therefore, this pop()
	                // will pop the entire "sign up" journey and return to the
	                // "/" route, AKA HomePage.
	                Navigator.of(context).pop();
	              },
	            );
	            break;
	          default:
	            throw Exception('Invalid route: ${settings.name}');
	        }
	        return MaterialPageRoute<void>(builder: builder, settings: settings);
	      },
	    );
	  }
	}

参考api:https://api.flutter.dev/flutter/widgets/Navigator-class.html,基本上大多数常用的路由需求都可以解决,不过有一个缺点就是每一次使用都需要传入context,部分框架可以解决这个问题。

  • 路由框架介绍
    GetX可以作为一个比较快速的路由封装工具,建议可以加上跳转native页面的封装。
  1. 网络请求
  • http
  • dio框架介绍
  1. 国际化、主题管理
  • 基础用法
    国际化:https://flutterchina.club/tutorials/internationalization/
    主题管理:使用Provider即可
  • 使用框架GetX
    GetX也具有国际化和主题管理能力。参考:https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md
  1. 自定义组件
  1. 代码规范
  • 命名规范
  • 分包规范
  • 引用规范
    参考:https://github.com/alibaba/flutter-go/blob/master/Flutter_Go%20%E4%BB%A3%E7%A0%81%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md
    https://dart.cn/guides/language/effective-dart/style
  1. 单元测试
  • dart测试
  • widget测试
  • 集成测试
    参考:https://flutterchina.club/testing/
  1. 构建打包
    参考:https://flutterchina.club/android-release/

三、空安全介绍

dart空安全是一种约束,如果某个依赖不支持空安全,那么整个项目也无法使用空安全的形式构建。所以为了让项目可以使用空安全特性,就要求整个项目所有依赖,都遵循空安全约束。

四、dart带来的一些特点和约束

  1. 拓展方法
    extension关键字可以给已有的类,添加新的方法
  2. 因为flutter为了减少构建包的体积,所以未直接建立依赖关系的类,都会在构建中剔除,而反射可以引用到所有的类,flutter做的取舍就是禁用了dart的mirror库。
  3. 类型推断的疑问
    使用泛型时,如果某个参数要求使用指定的t extends xxx,那么直接传入xxx,似乎也会报错,很奇怪的特点
  4. 资源路径的管理
    image加载资源图片时,最好不要用绝对路径,而是用package指定包名,然后使用相对路径。不然在不同的路径引用,会显示不出图片。

五、flutter开发带来的感受

因为热加载可以实时刷新页面显示,所以开发页面非常的快速。
但是不是所有代码的调整都支持热加载,比如嵌套根App widget类的变更(这点和rn一样),比如资源的变更。

flutter没法使用反射,所以解析json类,显得格外繁琐。一般都是利用插件或者工具,自动生成解析代码。

flutter和rn一样解决了跨平台的问题。写一遍业务,可以应用到两端,减少了开发时间和测试压力。

但是我觉得rn对比flutter是有优势的。
两个方案实现的原理不一样,
RN是利用虚拟dom,映射成native组件页面来实现跨平台。
flutter是dart引擎下,自己渲染所有的页面实现跨平台。

  1. rn对原生的兼容性更好,做native的自定义组件时非常有优势。可以完美兼容所有的native组件。
    而flutter嵌入原生view,还存在很多bug,比如软键盘没法监控弹出等。

  2. 而且rn社区应该更加庞大,因为react只要是前端就很容易掌握书写。而flutter需要单独学习dart语法,虽然dart很简单,但是dart中也有很多反直觉的约束,比如泛型的问题。

如果让我自己写项目,快速开发可能会选择flutter,但是作为一个想要长期支持的项目,不想出问题的项目,我会选择rn。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:24:09  更:2021-09-29 10:26:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:38:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码