flutter项目实用技术整理01

1.替换APP启动图标。

在这里插入图片描述
IOS的图标目录。
——————————

在这里插入图片描述
安卓启动图标的目录地址:
如果放入的图片自己重新命名了需要更改配置名称,不用写图片后缀格式:
在这里插入图片描述

——————————————————

2,应用程序启动名称

在这里插入图片描述
安卓的应用名称修改
————————————————————————
在这里插入图片描述
在这里插入图片描述

ios启动名称修改需要额外开启XCOD
————————————————

3,启动页面设置

3.1冷启动自带白屏处理,安卓版:

在这里插入图片描述
指向自己添加的图片名就可以启动的时候显示图片而不是白色底。注意下面各个分辨率显示文件都要建设一份,因为不知道你手机具体调用哪个的文件夹图片,按手机分辨率对应来。
还有这个文件也要处理一下:
在这里插入图片描述

插入的背景图片无法铺满白底可以加上这个设置
在这里插入图片描述

——————————————————————————————

具体解释如下:

在这里插入图片描述
这里加载了一个启动主题样式
在这里插入图片描述
这里是启动主题样式的定义,其中一句话
在这里插入图片描述

指向了下面文件的背景白色定义:如果为空指向背景色
在这里插入图片描述
释放下面的注释就可以指向图片启动了。

3.2冷启动自带白屏处理,ios版:

需要启动ios XCOD
在这里插入图片描述
在这里插入图片描述
点加号添加一个图片组件拖进去
在这里插入图片描述
设置属性就可以了

4,配置静态图片资源文件,本地目录

在这里插入图片描述
直接可以使用本地图片文件了:
在这里插入图片描述

设置android状态栏为透明的沉浸

在这里插入图片描述

SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);

13,getX 基于第三方插件的数据共享,路由导航,弹窗等简化Provider 操作

中文文档https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md#%E5%85%B3%E4%BA%8Eget

另一篇参考文档http://liujunmin.com/tags/getx/

采坑:他是数据层独立项目外,可以任意页面上传,也可以任意页面下载数据。所以不存在传统路由带值传输的需要、当然你可以结合之前传统路由传参综合使用,并不相互干扰。

13.1基本配置
在这里插入图片描述
引入插件后,首页开始的风格MaterialApp改成使用GetMaterialApp,它里面配置好了路由等依赖,省去了手动配置。
在这里插入图片描述
在这里插入图片描述
安装IDE插件
在这里插入图片描述

13.2生成GEXT代码模板
新建了个文件夹getx专门放状态数据。点击右键用插件生成代码文件。
在这里插入图片描述
在这里插入图片描述

13.3,编写全局数据层
在这里插入图片描述
13.4调用全局数据

案例直接写在生成的视图文件了,便于测试。

注意视图引用文件引入了库文件import ‘package:get/get.dart’;使其可以支持Get.put和 Get.to()路由跳转等。

首先引入全局依赖,
在这里插入图片描述
然后从依赖里调取数据,可以通过Obx()自动监控刷新
在这里插入图片描述
通过floatingActionButton按钮调用全局函数增加数值
在这里插入图片描述

函数取自之前GETX定义
在这里插入图片描述

13.5 GETX 自带信息提示框显示效果 Get.snackbar()
在这里插入图片描述

13.6 GETX 自带弹窗显示框显示效果 Get.defaultDialog()
在这里插入图片描述
13.7 GETX 呼出弹窗按钮事件触发 Get.bottomSheet()
在这里插入图片描述
13.8 GETX 页面路由传参跳转 Get.to(()=>CotrollerPage()
在这里插入图片描述
一般使用路由名称

,CotrollerPage()页面接受参数,页面传值也是同样接收
在这里插入图片描述
13.9 getX 命名路由 带参跳转
9.1定义路由
在这里插入图片描述
9.2使用路由带参
在这里插入图片描述
9.2调用参数
在这里插入图片描述

注意需要GET的引用要使用import ‘package:get/get.dart’;

9.3补充导航命令

导航到下一个页面

Get.toNamed("/NextScreen");

浏览并删除前一个页面。

Get.offNamed("/NextScreen");

浏览并删除所有以前的页面。

Get.offAllNamed("/NextScreen");

9.3.2使用异步路由回调传值 结合GETX路由
1.设置变量接收回值在这里插入图片描述
2.发送在这里插入图片描述
3.下面是返回上一页,对应的路由页面返回页面值
在这里插入图片描述

9.4 GETX 生命周期 数据初始化时按需执行事件监听

9.5 不需更新只需加上任意ID就可以
在这里插入图片描述

9.6GetUtils GETX监测数据格式
GetUtils是getx为我们提供一些常用的工具类库,包括值是否为空、是否是数字、是否是视频、图片、音频、PPT、Word、APK、邮箱、手机号码、日期、MD5、SHA1

参考资料http://liujunmin.com/flutter/getx/getx_newss.html

在这里插入图片描述

注意页面还是需要引入import ‘package:get/get.dart’;这个是使用GET . 的关键。

5,APP权限请求

权限包含文件储存权限,摄像头权限等根据需要配置。
在这里插入图片描述
5.1引入权限请求的库。

(不应该去官方库选择最新的版本号,应该搜索此版本库的教程文章https://www.jianshu.com/p/35b37c012351,找一篇写了最新版本库的对应学习引入,因为官网新版往往兼容有问题,所以这里没有加^版本号而是规定了9.2.0固定板)

5.2配置具体权限清单
在这里插入图片描述

具体字符看https://www.jianshu.com/p/35b37c012351

<!--
    Internet permissions do not affect the `permission_handler` plugin, but are required if your app needs access to
    the internet.
    -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <!-- Permissions options for the `contacts` group -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>

    <!-- Permissions options for the `storage` group -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <!-- Permissions options for the `camera` group -->
    <uses-permission android:name="android.permission.CAMERA"/>

    <!-- Permissions options for the `sms` group -->
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
    <uses-permission android:name="android.permission.RECEIVE_MMS"/>

    <!-- Permissions options for the `phone` group -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
    <uses-permission android:name="android.permission.USE_SIP"/>
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
    <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
    <uses-permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"/>

    <!-- Permissions options for the `calendar` group -->
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />

    <!-- Permissions options for the `location` group -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!-- Permissions options for the `microphone` or `speech` group -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- Permissions options for the `sensors` group -->
    <uses-permission android:name="android.permission.BODY_SENSORS" />

    <!-- Permissions options for the `accessMediaLocation` group -->
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />

    <!-- Permissions options for the `activityRecognition` group -->
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

    <!-- Permissions options for the `ignoreBatteryOptimizations` group -->
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

    <!-- Permissions options for the `bluetooth` group -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- Permissions options for the `manage external storage` group -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <!-- Permissions options for the `system alert windows` group -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <!-- Permissions options for the `request install packages` group -->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <!-- Permissions options for the `access notification policy` group -->
    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>

5.3其他设置
在 gradle.properties 中添加

android.useAndroidX=true
android.enableJetifier=true

在这里插入图片描述

把android/app/build.gradle 改成31
在这里插入图片描述

`android {   compileSdkVersion 31   ... }`

5.3.1判断网页版跳过加载
在这里插入图片描述
引用了工具文件定义如下,工具文件自己创建
在这里插入图片描述

import 'dart:io';
import 'package:flutter/foundation.dart';
判断是什么终端的设备打开地
class PlatformUtils {
  static bool _isWeb() {
    return kIsWeb == true;
  }

  static bool _isAndroid() {
    return _isWeb() ? false : Platform.isAndroid;
  }

  static bool _isIOS() {
    return _isWeb() ? false : Platform.isIOS;
  }

  static bool _isMacOS() {
    return _isWeb() ? false : Platform.isMacOS;
  }

  static bool _isWindows() {
    return _isWeb() ? false : Platform.isWindows;
  }

  static bool _isFuchsia() {
    return _isWeb() ? false : Platform.isFuchsia;
  }

  static bool _isLinux() {
    return _isWeb() ? false : Platform.isLinux;
  }

  static bool get isWeb => _isWeb();

  static bool get isAndroid => _isAndroid();

  static bool get isIOS => _isIOS();

  static bool get isMacOS => _isMacOS();

  static bool get isWindows => _isWindows();

  static bool get isFuchsia => _isFuchsia();

  static bool get isLinux => _isLinux();
}

5.3.2下面紧跟权限申请页面PermissionRequestWidget调用,根据页面返回值判断操作
在这里插入图片描述

  //开始权限申请判断
    Future.delayed(Duration.zero, () {
      //因为initState时间没有context,所以定义延时执行等待加载完成
      Navigator.of(context).push(
        PageRouteBuilder(
          /打开装载了申请的页面
            opaque: false,//路由透明
            pageBuilder: (BuildContext context, Animation<double> animation,
                Animation<double> secondaryAnimation) {
              return const PermissionRequestWidget(/装载了申请的页面
                  Permission.storage);
            }),
      ).then((value) {
        if (value == null || !value) {
          //权限请求不通过
        } else {
          //权限请求通过
          // Navigator.push(
          //   context,
          //   MaterialPageRoute(
          //     builder: (context) {
          //       return const HomePageWidget();
          //     },
          //     maintainState: false,
          //   ),
          // );

          // Get.offAll(const HomePageWidget());

          Get.offAllNamed("/WelcomePage", arguments: '我是命名路由传过来的数据');
          //命名路由方式Get在这里接受任何东西,无论是一个字符串,一个Map,一个List,甚至一个类的实例。
          // 接受方可print(Get.arguments);其他参考print(Get.parameters['id']);
        }
      });
    });

延时的秒和毫秒设置

Future.delayed(Duration.zero, () {。。。延时0await Future.delayed(Duration(seconds: 1)).then((_){。。。。。延时1await Future.delayed(Duration(milliseconds: 500)).then((_){。。。。。延时500毫秒

5.3.4PermissionRequestWidget页面的具体定义
在这里插入图片描述

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';

//权限申请功能页
class PermissionRequestWidget extends StatefulWidget {
  const PermissionRequestWidget(this.permission,
      {this.isCloseApp = false, this.leftButtonText = "再考虑一下", Key? key})
      : super(key: key);
  final Permission permission;

  final bool isCloseApp;
  final String leftButtonText;

  
  State<PermissionRequestWidget> createState() =>
      _PermissionRequestWidgetState();
}

class _PermissionRequestWidgetState extends State<PermissionRequestWidget>
    with WidgetsBindingObserver {
  //WidgetsBindingObserver : 检测页面生命周期
  //页面初始化函数
  List<String> permissionList = [
    "需要获取您的手机文件储存权限,以保存您的一些偏好设置",
    "您已拒绝权限,所以无法保存您的一些偏好设置,将无法使用App",
    "您已拒绝权限,请在设置中心中同意APP的权限请求",
    "其他错误",
  ];
  bool _isGoSetting = false;
  
  void initState() {
    super.initState();
    checkPermisson();
    WidgetsBinding.instance.addObserver(this); //注册观察者
  }
  //生命周期变化时回调
//  resumed:应用可见并可响应用户操作
//  inactive:用户可见,但不可响应用户操作
//  paused:已经暂停了,用户不可见、不可操作
//  suspending:应用被挂起,此状态IOS永远不会回调

  
  void didChangeAppLifecycleState(AppLifecycleState state) {
    //由后台返回主屏幕 数据刷新时
    //根据挂起状态申请
    super.didChangeAppLifecycleState(state);
    //print(state);//  ==resumed:应用可见并可响应用户操作
    if (state == AppLifecycleState.resumed && _isGoSetting) {
      checkPermisson(); //自定义的权限申请函数
    }
  }

  
  void dispose() {
    WidgetsBinding.instance.addObserver(this); //注销观察者
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.transparent,//设置背景透明
        );
  }

//关闭应用
  void closeApp() {
    //关闭应用的方法
    SystemChannels.platform.invokeMethod("SystemNavigator.pop");
  }

//函数 申请弹窗
  void showPermissonAlert(
      String message, String rightString, Permission permission,
      {isGoSetting = false}) {
    showCupertinoDialog(
        //用于弹出ios风格对话框
        builder: (BuildContext context) {
          return CupertinoAlertDialog(
            title: Text("温馨提示"),
            content: Container(
              padding: EdgeInsets.all(12),
              child: Text(message),
            ),
            actions: [
              //左边按钮
              CupertinoDialogAction(
                child: Text("${widget.leftButtonText}"),
                onPressed: () {
                  if (widget.isCloseApp) {
                    closeApp(); //关闭APP
                  } else {
                    Navigator.of(context).pop(false); //返回上一页面
                  }
                },
              ),
              //右边按钮
              CupertinoDialogAction(
                child: Text("$rightString"),
                onPressed: () {
                  if (isGoSetting) {
                    _isGoSetting = true;
                    openAppSettings();
                  } else {
                    requestPermiss(permission);
                  } //关闭弹窗
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        },
        context: context);
  }

//###############################################
  //函数 申请权限
  void requestPermiss(Permission permission) async {
    //发起权限申请

    PermissionStatus status =
        await permission.request(); //呼出窗口让用户选择权限,返回所选择结果状态

    checkPermisson(status: status);
  }

//##############################################
//函数 权限申请审批
  void checkPermisson({PermissionStatus? status}) async {
    //权限读取
    Permission permission =
        widget.permission; // widget.permission== Permission.storage拿取储存权限
    if (status == null) {
      //权限状态
      status = await permission.status;
    }

    if (status.isGranted) {
      //通过
      Navigator.of(context).pop(true);
      print("通过了");
    } else if (status.isLimited) {
      //无效!似乎进入不了
      //用户第一次申请拒绝
      print("用户第一次申请拒绝");
      showPermissonAlert(permissionList[1], "重试", permission);
    } else if (status.isPermanentlyDenied) {
      //第二次申请 用户拒绝
      print("第二次申请申请拒绝");
      showPermissonAlert(permissionList[2], "去设置中心", permission,
          isGoSetting: true);
    } else if (status.isDenied) {
      //第一次申请
      print("第1次申请");
      showPermissonAlert(permissionList[0], "同意", permission);
    }
  }
}

5.4开始代码使用权限申请(补充完善解释)

在这里插入图片描述
下面是具体的函数定义
48行(48#) …=Permission.storage;//储存权限

在这里插入图片描述

此图片中的状态类型53行开始,不是很好用应该是插件版本不同判断类型变化了,第一次申请状态最好是isDenied建议参考下面更详细的操作代码

其中48#.storage就是权限清单中的storage在这里插入图片描述
表示的是储存权限。
更详细的操作代码:在这里插入图片描述
权限对象Permission.storage中自带状态属性.status

6,APP弹窗showCupertinoDialog,打开手机设置权限,关闭APP,返回上一页

showCupertinoDialog()弹窗
CupertinoAlertDialog()iOS风格的对话框
CupertinoDialogAction()按钮

详细资料参考https://www.jianshu.com/p/f2447dedb155
在这里插入图片描述

在这里插入图片描述

7,延时执行,任务延迟进行

await Future.delayed(const Duration(milliseconds: 1000));//这里等待了1秒
在这里插入图片描述

8,自定义路由,打开页面背景为透明,页面跳转

Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return new DetailPage();
}))//页面跳转
在这里插入图片描述

9,检测用户操作:按下瞬间、按压、长按、轻击、快速滑屏、拖动

在这里插入图片描述

10,移除焦点

在这里插入图片描述

11, WidgetsBindingObserver : 监测页面生命周期

生命周期参考资料https://www.jianshu.com/p/ab3cd84f624c

11.1添加 with WidgetsBindingObserver
在这里插入图片描述
11.2添加观测者

在这里插入图片描述
11.3屏幕切换执行监测,输出状态。根据状态判断执行对应代码。

在这里插入图片描述

其他监测类型:用户本地设置变化时调用,如系统语言改变///低内存回调///应用尺寸改变时回调,例如旋转 //文字系数变化请参考资料https://www.jianshu.com/p/a556a7a46e4f

11.4销毁观察者
在这里插入图片描述

12,颜色和主题样式,设置整体样式主题

12.1第一种写法:在这里插入图片描述

在线编辑生成网站https://m3.material.io/theme-builder#/custom

生成样式文件放入项目中

在这里插入图片描述
main函数的主引用首页RootApp()里添加了新样式属性:theme 白天主题,darkTheme夜晚主题,使整个后续页面都有了样式。切换手机系统的深色模式就会看到暗色调。

12.2第二种写法,按钮手动样式换肤

参考资料https://www.bilibili.com/video/BV1aT4y1S7pB/?spm_id_from=333.999.0.0&vd_source=27b88e2428d8b67a4013c8ec833c13d7

去掉darkTheme配置,保留theme。theme:里面的配置改成可以切换darkTheme的内容,就是两种切换。要是切换按钮全局存在,需要配合使用全局GetX储存。请查看上面参考资料。

12.3在全局色上特别使用自定义的:在这里插入图片描述

参考资料https://book.flutterchina.club/chapter7/theme.html#_7-4-2-%E4%B8%BB%E9%A2%98-theme

14获取元素的大小SchedulerBinding.instance.addPostFrameCallback

参考资料https://www.jianshu.com/p/6c214a054f90

addPostFrameCallback 是 StatefulWidget 渲染结束的回调,只会被调用一次,之后 StatefulWidget 需要刷新 UI 也不会被调用,
addPostFrameCallback 的使用方法是在 initState 里添加回调:

void initState() {
  super.initState();
  SchedulerBinding.instance.addPostFrameCallback((_) => {});
}

这个方法在一帧的最后调用,并且只调用一次,使用这个方法就可以在判断渲染完成,并获取到元素的大小。


  void didChangeDependencies() {
    WidgetsBinding.instance.addPostFrameCallback(_onAfterRendering);
    super.didChangeDependencies();
  }

  
  void didUpdateWidget(T oldWidget) {
    WidgetsBinding.instance.addPostFrameCallback(_onAfterRendering);
    super.didUpdateWidget(oldWidget);
  }


  void _onAfterRendering(Duration timeStamp){
      //这里编写获取元素大小和位置的方法
  }

获取元素大小和位置:

//获取元素大小
RenderObject renderObject = context.findRenderObject();
Size size = renderObject.paintBounds.size;
//获取元素位置:
Vector3 vector3 = renderObject.getTransformTo(null)?.getTranslation();
//位置(vector3.x,vector3.y)

关闭应用

15用户隐私与协议

下面需要引入几个插件分别是网页插件,本地数据储存插件,可以先看一下引入。另外插件需要更高版本的安卓SDK先这样设置一下:
在这里插入图片描述在这里插入图片描述
检查一下SDK包在这里插入图片描述

去掉之前的权限通过跳转,改成执行初始弹窗函数在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
下面是完成用户协议主体文本内容显示
在这里插入图片描述
利用手势识别监控点击打开网页在这里插入图片描述
上面的定义如下:
在这里插入图片描述

打开网页链接,需要引入第三方插件,WebViewpage是自己定义的页面部件里面有读取网页展示部分在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

15.2用户隐私与协议,数据本地化保存通过签名(使用插件)
在这里插入图片描述
需要引入封装函数具体定义看码库
在这里插入图片描述
码库里展示具体封装定义SPUtil()

https://github.com/csliwenzhu/flutter-ho/blob/main/lib/src/utils/sp_utils.dart

在这里插入图片描述
用户协议弹窗部分修改认证

16设置打开页面透明

第一步:路由透明
在这里插入图片描述
第二步:打开的页面也设置背景透明
在这里插入图片描述

17Future无限调用的起始写法

在这里插入图片描述
在这里插入图片描述

await会阻塞流程,等待紧跟着的的Future执行完毕之后,再执行下一条语句,而如果用了Future.then这个api,那么就不会等待,直接执行下面的语句,等Future执行完了,再调用then这个方法。例如下面的代码是不等待继续往下执行代码 print(“_loadUserInfo:${new DateTime.now()}”);的:

Future _loadUserInfo() async{
    print("_loadUserInfo:${new DateTime.now()}");
    _getUserInfo().then((info){
      print(info);
    });
    print("_loadUserInfo:${new DateTime.now()}");
  }

18文本字段调用变量取值方法

 label: Text("获取:${Get.arguments}"),
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值