首页 > 其他分享 >Flutter开发中的一些Tips

Flutter开发中的一些Tips

时间:2023-09-28 18:00:42浏览次数:35  
标签:插件 使用 IOS 开发 Android child Tips Flutter


学习Flutter也有一阵子了。闲着没事,用了公司一个已经凉凉的App设计图来练手。当然了接口不可能用的了,所以都是些死数据,实现效果可以说是很完美了(得到了设计的认可。。。)。当然自己也是边查边写,也借鉴了许多Github上优秀的Flutter项目。现在开源出来(附带设计图),供大家交流学习。希望多多Star、Fork支持,有问题可以Issue。附上链接:https://github.com/simplezhli…

Flutter开发中的一些Tips_数据

本篇主要分享一下自己在此项目中遇到的问题及心得,希望对你有所帮助!

1.部件溢出

异常大致如下:

A RenderFlex overflowed by 22 pixels on the bottom.

导致的原因就是在水平或者垂直方向上的内容超过了父部件的大小。一般来说我们的页面不存在这样的问题,因为根据页面的设计,事先可以预料到是否超出。不过要注意到有输入法弹出的页面。比如我下面的这个例子:

<img src="…; width=“380”/> <img src="…; width=“380”/>

可以看到底部溢出了22个像素,可能在18:9的手机以上不太会出现这种问题,因为屏幕的高度足够。但是这种16:9的手机可能会暴露出来。解决的方法有两种:

  1. 包一层SingleChildScrollView,让你的页面可以滑动起来。
  2. Scaffold中设置resizeToAvoidBottomInset为false。默认为ture,防止部件被遮挡。如果使用了这个方法,如果底部有输入框,则会造成遮挡。

大家可以根据实际需求选择。

2.输入框的遮挡

页面如下:

<img src="…; width=“380”/>

底部有输入框,同时“提交”的按钮固定在底部。一开始觉得既然固定在底部,那就使用Stack配合Positioned来实现,然而就导致输入法弹出时,发生遮挡。

<img src="…; width=“380”/>

上图中,我选中了最后一个输入框,但因为输入法默认都是在输入框的下方弹出,然而上面盖着这个“提交”按钮,发生了遮挡。

最终我的解决方法就是使用Column配合Expanded来实现。修复后如下:

<img src="…; width=“380”/>

3.SafeArea

一旦有部件固定在顶部或者底部(严谨点的话可以说是在屏幕的四边)。那我我们最好使用SafeArea来包一下。因为Android 和 IOS都有状态栏,甚至IOS还有叫做“HomeIndicator”的横条。所以一不留神就会出现适配问题。

我们在Flutter中常使用的BottomNavigationBarAppBar 其实就在内部处理了此类问题。以 AppBar源码为例:

class _AppBarState extends State<AppBar> {

  @override
  Widget build(BuildContext context) {
    
    if (widget.primary) {
      appBar = SafeArea(  // <--- 1
        top: true,
        child: appBar,
      );
    }

    return Semantics(
      container: true,
      child: AnnotatedRegion<SystemUiOverlayStyle>(
        value: overlayStyle,
        child: Material( // <--- 2
          color: widget.backgroundColor
            ?? appBarTheme.color
            ?? themeData.primaryColor,
          child: Semantics(
            explicitChildNodes: true,
            child: appBar,
          ),
        ),
      ),
    );
  }
}

所以使用方法为:

Material( // 需要颜色填充到边界区域可以使用
  color: Colors.white,
  child: SafeArea(
    child: Container(),
  ),
)

还是上面的页面,我们对比一下处理前后的效果:

<img src="…; width=“380”/> <img src="…; width=“380”/>

4.善用Theme

Flutter 在开发中,让人诟病的就是大量的嵌套,而我们只能尽量避免。比如将一些部件、属性进行封装,避免重复的书写。不过封装也讲究使用场景。如果这种样式的部件仅仅只是某一两处使用,封装显得有点小题大做。并且封装的大而全也会增加使用的复杂度。那么这时就可以使用Theme这种办法。

举一个例子,在下图中圈起来的部分有三个按钮,它们的高度相同,文字、圆角大小也相同。如果每一个都去设定这些属性,未免太过麻烦。

<img src="…; width=“380”/>

这时我们使用Theme去统一修改它们的样式,就会很方便了。

Theme( 
              data: Theme.of(context).copyWith(
                buttonTheme: ButtonThemeData(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  minWidth: 64.0,
                  height: 30.0,
                  materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  shape:RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(4.0),
                  )
                ),
                textTheme: TextTheme(
                  button: TextStyle(
                    fontSize: 14.0,
                  )
                )
              ),
              child: Row(
                children: <Widget>[
                  FlatButton(
                    color: Color(0xFFF6F6F6),
                    onPressed: (){},
                    child: Text("联系客户"),
                  ),
                  ......
                  FlatButton(
                    color: Color(0xFFF6F6F6),
                    onPressed: (){},
                    child: Text("拒单"),
                  )
                ],
              ),
            )

同时使用Theme还可以修改许多默认的设置,比如FlatButton的默认宽度为88,高度为36,但是FlatButton中没有直接修改的属性,网上好多的方法都是通过包一层Container去修改,不仅增加的嵌套,有些需求还不能达到。所以善用Theme可以让你省时省力,不过缺点就是你需要去翻翻源码,寻找使用这些Theme的地方。

5.注意平台差异

注意部分组件在Android与IOS平台之间的差异。

  1. ScaffoldAppBarAppBar中默认的title在Android中靠左显示,IOS中居中显示。如果需要两个平台效果统一,需要设置在AppBar中主动设置centerTitle属性。同时AppBar的返回箭头图标也不相同,统一的话需要自定义leading

Flutter开发中的一些Tips_android_02

  1. 页面跳转如果使用MaterialPageRoute来做过渡效果,注意Android中新的页面会从屏幕底部滑动到屏幕顶部,IOS中新的页面会从屏幕右侧滑动到屏幕左侧。

如果需要两个平台效果统一,我们不使用自带效果,可以自定义一个。

Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
  pageBuilder: (context, animation, secondaryAnimation){
    return new FadeTransition( //使用渐隐渐入过渡,
      opacity: animation,
      child: TestPage(),
    );
  })
);

要么修改Theme,统一两平台的实现。:

class MyApp extends StatelessWidget {

  static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
    TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
    TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
  };
  
  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      theme: ThemeData(
        pageTransitionsTheme: PageTransitionsTheme(
          builders: _defaultBuilders
        )
      ),
      ...
    );
  }
}
  1. ScrollPhysics效果,可以滑动的部件都有一个physics属性。滑动到边界时,Android平台为边缘阴影的效果ClampingScrollPhysics,IOS为回弹效果BouncingScrollPhysics。如果需要统一,可以指定physics属性。
  2. 状态栏方面,Android平台默认是半透明的效果,IOS则是透明效果。比如Android要实现IOS的效果,可以设置状态栏为透明。不过IOS要实现Android的效果则不行。。。,难道只能自定义?有知道方法的可以分享一下。
void main(){
  runApp(MyApp());
  // 透明状态栏
  if (Platform.isAndroid) {
    SystemUiOverlayStyle systemUiOverlayStyle = 
    SystemUiOverlayStyle(statusBarColor: Colors.transparent);
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  }
}
  1. 输入键盘

TextFieldkeyboardType属性设置为TextInputType.phoneTextInputType.number时,IOS系统弹出的数字输入键盘没有"完成"按钮,导致输入法无法关闭。当然了Android不存在这个问题。

比较成熟有效的方案是在键盘弹出的上方悬浮一个按钮,点击可以关闭键盘。当然了,这种问题也有对应的库可以解决,我使用的是flutter_keyboard_actions来解决了这个问题。因为在Android端我发现了部分输入法的兼容问题,所以只针对IOS做了处理。大家可以看一下前后对比图,具体实现代码可以参考flutter_keyboard_actions的文档和我的项目代码:

<img src="…; width=“380”/> <img src="…; width=“380”/>

当然平台差异不仅仅是这么多,比如IOS自带侧滑返回等。具体我们可以去查看调用TargetPlatform枚举类的代码。

如果你觉得这样真麻烦,我给你支个大招,修改ThemeDataplatform,指定一个平台。

class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      theme: ThemeData(
        platform: TargetPlatform.android
      ),
      ...
    );
  }
}

其次就是使用TextInputType.number在IOS中弹起的键盘没有小数点符号。在输入金额类型数据时,需要将keyboardType属性设置为TextInputType.numberWithOptions(decimal: true)

6.keyboardType

keyboardType属性主要含义为弹起的键盘类型,并不代表输入数据的类型

而在Android开发中,在EditText中设置android:inputType不仅可以指定弹起的键盘类型,同时也确定了输入数据的类型,也就是内置了数据的格式校验。Flutter中并没有后者,所以可能一开始你是TextInputType.number,但是在输入法中切换成中文键盘,一样可以输入中文字符。所以数据的校验需要我们使用inputFormatters自己处理。

比如TextInputType.phone时可以使用WhitelistingTextInputFormatter 白名单校验,只允许输入0~9:

TextField(
      keyboardType: TextInputType.phone,
      inputFormatters: [WhitelistingTextInputFormatter(RegExp("[0-9]"))]
    )

输入密码时可以使用BlacklistingTextInputFormatter 黑名单校验,除去中文字符:

TextField(
      keyboardType: TextInputType.text,
      inputFormatters: [BlacklistingTextInputFormatter(RegExp("[\u4e00-\u9fa5]"))]
    )

输入小数时,可以自定义TextInputFormatter来限制输入小数格式:

TextField(
      keyboardType: TextInputType.numberWithOptions(decimal: true),
      inputFormatters: [UsNumberTextInputFormatter()]
    )

//来源:
class UsNumberTextInputFormatter extends TextInputFormatter {
  static const defaultDouble = 0.001;
  static double strToFloat(String str, [double defaultValue = defaultDouble]) {
    try {
      return double.parse(str);
    } catch (e) {
      return defaultValue;
    }
  }

  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    String value = newValue.text;
    int selectionIndex = newValue.selection.end;
    if (value == ".") {
      value = "0.";
      selectionIndex++;
    } else if (value != "" && value != defaultDouble.toString() && strToFloat(value, defaultDouble) == defaultDouble) {
      value = oldValue.text;
      selectionIndex = oldValue.selection.end;
    }
    return new TextEditingValue(
      text: value,
      selection: new TextSelection.collapsed(offset: selectionIndex),
    );
  }
}

7.InkWell

InkWell有的叫溅墨效果,有的叫水波纹效果。使用场景是给一些无点击事件的部件添加点击事件时使用(也支持长按、双击等事件),同时你也可以去修改它的颜色和形状。

InkWell(
  borderRadius: BorderRadius.circular(8.0), // 圆角
  splashColor: Colors.transparent, // 溅墨色(波纹色)
  highlightColor: Colors.transparent, // 点击时的背景色(高亮色)
  onTap: () {},// 点击事件
  child: Container(),
);

不过有时你会发现并不是包一层InkWell就一定会有溅墨效果。主要原因是溅墨效果是在一个背景效果,并不是覆盖的前景效果。所以InkWell中的child一旦有设置背景图或背景色,那么就会遮住这个溅墨效果。如果你需要这个溅墨效果,有两种方式实现。

  1. 包一层 Material,将背景色设置在 Material中的color里。
Material(
  color: Colors.white,
  child: InkWell(),
)
  1. 使用Stack布局,将InkWell放置在上层。这种适用于给图片添加点击效果,比如Banner图的点击。
Stack(
            children: <Widget>[
              Positioned.fill(
                child: Image(),
              ),
              Positioned.fill(
                child: Material(
                  color: Colors.transparent,
                  child: InkWell(
                    splashColor: Color(0X40FFFFFF),
                    highlightColor: Colors.transparent,
                    onTap: () {},
                  ),
                ),
              )
            ],
          )

8.保持页面状态

比如点击导航栏来回切换页面,默认情况下会丢失原页面状态,也就是每次切换都会重新初始化页面。这种情况解决方法就是PageViewBottomNavigationBar结合使用,同时子页面State中继承AutomaticKeepAliveClientMixin并重写wantKeepAlive为true。代码大致如下:

class _TestState extends State<Test> with AutomaticKeepAliveClientMixin{

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }

  @override
  bool get wantKeepAlive => true;
}

详细的可以看这篇文章:Flutter 三种方式实现页面切换后保持原页面状态

9.依赖版本问题

首先这里建议凡是Flutter的插件在填写版本号时不要使用^符号。

Flutter开发中的一些Tips_Android_03

^符号意味着你可以使用此插件的最新版本(大于等于当前版本)。这会导致什么问题呢?可能你前一天代码还能跑起来,今天就编译出错了。因为这些插件中包括Android、IOS的所用依赖环境配置,常见的就是新版本使用了AndroidX的依赖,但是还有些插件并没有使用AndroidX,导致了两者的冲突。

我之前在看flutter-go的代码时,就是因为webview的插件突然升级了,导致了安装失败。具体问题可以看这里。所以在代码稳定的情况下不建议使用^符号。

发生了这种问题,有以下几个解决方法:

  1. 使用非AndroidX的版本插件。(优点就是见效快。缺点就是此插件后续的更新无法使用)
  2. 手动修改插件的冲突,因为Flutter插件的代码是可以直接修改的,所以你可以手动修改掉这些冲突,统一插件的版本(优点就是可以使用最新的版本。缺点就是这种方法首先麻烦,其次不利于团队开发使用)

我偏好使用第二种,只要做好修改的相关记录就行,算是一劳永逸。

10.Flutter Android 打包

打包本身流程没有问题,配置好签名文件,执行flutter build apk 命令。但是发现打包后没有将插件中的AndroidManifest.xml文件合并。比如我有使用image_picker插件,它的AndroidManifest.xml文件如下:

Flutter开发中的一些Tips_Android_04

可以看到有权限的及Android 7.0FileProvider的声明。诸如此类的信息没有打包进去(但是引用xml中的flutter_image_picker_file_paths文件却在),导致我实际使用这些功能时没有反应,但是在平时的调试过程中却是好的。

中间我发现打包后的App名称也是之前的,怀疑是缓存问题,所以我手动删除了项目根目录的build.gradle文件夹,重新打包就好了。所以打包后最好检查一下AndroidManifest.xml文件,避免此类缓存造成的问题。

11.其他

  1. Container 功能强大,设置宽高、padding、margin、背景色、背景图、圆角、阴影等都可以使用它。
  2. 有些widget 自带padding 属性,所以不必多套一层Padding部件。(比如ListViewGridViewContainerScrollViewButton
  3. 尽量使用const来定义常量。比如paddingcolorstyle 这些地方:
class Colours {
  static const Color text_dark = Color(0xFF333333);
}

Padding(
  padding: const EdgeInsets.all(8.0),
  child: Text(
      "Test",
      style: TextStyle(
      fontSize: 26.0,
      color: Colours.text_dark
    )
  )
)
  1. Dart2中的new 关键字可选,所以就不要选了,哈哈!!

其实我在这中间遇到的小问题还有很多,有的暂时还没有找到好的方法去解决。

更多的Flutter学习资料可以扫码免费领取!

Flutter技术解析与实战,全家桶学习资料(含Flutter进阶学习笔记、入门与实战和完整开发实战详解)

Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

在这里为了方便大家系统的学习Flutter,这里特意联合了阿里P7架构师和谷歌技术团队共同整理了一份Flutter全家桶学习资料。

内容概要:Flutter技术解析与实战、Flutter进阶学习笔记、Flutter入门与实战和Flutter完整开发实战详解。

内容特点:条理清晰,含图像化表示更加易懂。


《Flutter技术解析与实战》

目录

Flutter开发中的一些Tips_android_05

第一章 混合工程

● Flutter工程体系

● 混合工程改造实战

● 混合工程与持续集成

● 快速完成混合工程搭建

● 使用混合栈框架开发

Flutter开发中的一些Tips_Android_06

第二章 能力增强

● 基于原生能力的插件扩展

● 基于外接纹理的同层渲染

● 多媒体能力扩展实践

● 富文本能力应用实践

Flutter开发中的一些Tips_数据_07

第三章 业务架构设计

● 应用框架设计实践

● 轻量级动态化渲染引擎的设计

● 面向切面编程的设计实践

● 高性能的动态模板渲染实践

Flutter开发中的一些Tips_数据_08

第四章 数据统计与性能

● 数据统计框架的设计

● 性能稳定性监控方案的设计

● 高可用框架的设计与实践

● 跨端方案性能对比实践

Flutter开发中的一些Tips_ios_09

第五章 企业级应用实战

● 基于Flutter的端结构演进与创新

● Flutter与FaaS云端一体化架构

Flutter开发中的一些Tips_ios_10


标签:插件,使用,IOS,开发,Android,child,Tips,Flutter
From: https://blog.51cto.com/u_16163480/7641465

相关文章

  • ChatGPT 重磅更新可进行实时网络搜索;OpenAI 将构建新的“AI 硬件”丨RTE开发者日报 Vo
    开发者朋友们大家好:这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(RealTimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点,欢迎大家留......
  • 基于Java开发的企业人力资源管理系统(招聘、绩效、考勤、酬薪管理)
    前言:企业人力资源管理系统是企业管理中不可或缺的一部分,它涵盖了招聘管理、人员管理、绩效管理、考勤管理、社保管理、酬薪管理等多个方面。这些模块相互关联,协同工作,为企业的人力资源优化和管理提供了强有力的支持。系统介绍:1、招聘管理是企业引进人才的重要环节,其主要目的是......
  • 如何选择米尔基于STM32MP1系列核心板和开发板
    一款合适的处理器,是每个工程师在开发设计前期调研必须面对的难题。而如何挑选一款符合产品开发的处理器呢?今天我们就以ST公司的STM32MP1系列处理器进行分析比较。ST公司目前已经发布了两款不同类型的MPU芯片,分别是STM32MP15系列和STM32MP13系列。这两款芯片的特点十分鲜明:STM32MP......
  • VS 2017 MFC开发最化小安装
    适用范围用于仅开发调试C++与MFC程序且硬盘空间不够的用户。安装步骤从vs官网找到在线安装器exe,记住选择15.0版本在组建选择中,按照如下进行选择。安装后启动即可。......
  • web前端tips:js继承——寄生式继承
    上篇文章给大家分享了js继承中的原型式继承web前端tips:js继承——原型式继承今天给大家分享一下js继承中的寄生式继承寄生式继承寄生式继承(ParasiticInheritance)是一种基于原型式的继承方式,它通过创建一个仅用于封装继承过程的函数,该函数在内部调用原型式继承创建......
  • 【Android 开发】 面试官喜欢一直问到底?教你如何避免翻车沟通表达能力
    在信息爆炸的时代,Android开发领域的知识日新月异,如何提升自己的能力和找到适合自己的学习资源是一个常见的问题。自我介绍是面试的必备环节之一时长通常在三分钟以内。在自我介绍时,候选人应该简明扼要地介绍自己的经历和能力,突出自己的优势和特点,以及为什么适合这个职位。基础知识......
  • 国外盲盒系统源码系统开发
      盲盒系统源码系统开发  盲盒系统定制开发,有多种玩法模式,可以是开箱,也可以是商城模式,它是以用户在商城购买盲盒,直接开箱。不知道如何选择盲盒可以玩随机的模式,输入自己想要东西,用户在选择他们想要的商品时,系统也会尽可能的满足的,系统会随机选择一个物品放入盲盒中,然后将......
  • 养猪农场源码系统开发
      智慧养猪农场软件app是结合线上线下的养殖系统,开发人员在开发时需要对相关的软件程序化,序列化的算进行计算,软件开发还需要有多种语言的技术和实现,其中最常见的是php开发、Java和C++等。  智慧养猪农场软件开发需求先确定好,用户都想要什么样的功能,用户需要一个领养的功能......
  • 在Flutter中制作指纹认证应用程序
    本文主要展示如何在Flutter中为android应用程序实现指纹认证系统现在许多手机都配备了指纹传感器,这使得用户登录和本地身份验证更容易,而且比使用密码更安全。设置我们的项目在我们开始编写应用程序之前,我们需要先设置一些东西。我们需要做的第一件事是在我们的pubspec.yaml文......
  • 【fgolang代码分享】golang如何连接oracle进行业务开发
    在我们的开发场景下虽然大部分我们都使用mysql就可以满足我们日常的开发任务,但是总有一些开发场景是需要我们是用oracle数据库的,今天我给大家带来golang的俩种连接oracle的方式。oracle简介oracle也是出自甲骨文公司,和mysql同门,也是全球最大的信息管理软件及服务供应商,Oracle开......