从零到应用:我的Flutter项目开发之旅

简介: Flutter是一种流行的跨平台移动应用开发框架,由Google推出。它使用Dart编程语言,通过单一代码库可以同时构建iOS和Android应用。Flutter具有许多吸引力的特性,如快速的渲染性能、漂亮的用户界面、丰富的组件库以及热重载等。通过阅读这篇文章,你将获得一些关于Flutter项目开发的实际指导,可以帮助你更有效地构建高质量的移动应用程序。无论你是初学者还是有一定经验的开发者,希望这些笔记能够为你提供一些有用的思路和技巧,让你在Flutter项目开发中取得更好的成果。

前情提要

初次使用 Flutter 页面布局或者其他问题,多多少少可能都会有一点。如遇到并解决,会及时更新。

我经常去的几个网站330 多个组件使用介绍Flutter 入门介绍学习。这两个网站我个人感觉,前者偏向组件使用和语法介绍,而后者更适合新手来学习比较重要的概念。组件并不是很全。建议配合“食用”。

建议:我下文提到的任何组件 API 都可以通过以上两个网站去寻找学习!!!!!!!!官网个人觉得新人看起来稍有不妥,特别是我这种英语很垃圾的人,机翻根本看不懂。


先看蓝湖设计图

cars组件

下面是我初次分解的结构。

cars组件

我觉得前期页面结构基础不想好,画的时候会出现很多很多问题,有一些样式结构不生效,那么很有可能是你的页面结构有问题!亲身经历,改一下结构样式全生效了。

如果绘画页面有出现黑黄警告条纹的时候,那么代表你的像素溢出了。它不像 HTML,溢出了也很难发觉。而 Flutter 会警告你,这个时候你只需要打开 Android Studio 的 Flutter DevTools 功能。查看你的结构问题。基本改改高宽就能解决。再不济结构改变下。

像素溢出错误

全部代码

    return Container(
      decoration: BoxDecoration(
        color: Color(0xfff2f2f2),
      ),
      width: 345.w,
      // height: 389.h,
      child: Column(
        children: [
          Image.network(
            "http://yz-shigongli.oss-accelerate.aliyuncs.com/2022-03/1648094119154-7b280bbf63105a8e90299e2d79c8c6ee.jpeg",
            width: 345.w,
            height: 230.h,
            fit: BoxFit.cover,
          ),
          Container(
            padding: EdgeInsets.fromLTRB(15, 20, 0, 0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              verticalDirection: VerticalDirection.up,
              children: <Widget>[
                Container(
                  child: Text(
                    item.name,
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                ),
              ],
            ),
          ),
          Container(
            padding: const EdgeInsets.fromLTRB(19, 0, 0, 0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              verticalDirection: VerticalDirection.up,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Container(
                  child: RichText(
                    text: const TextSpan(children: <InlineSpan>[
                      TextSpan(
                          text: '8555元/',
                          style: TextStyle(
                              color: Color(0xffce3800),
                              fontSize: 22,
                              fontWeight: FontWeight.bold)),
                      TextSpan(
                          text: '公顷',
                          style: TextStyle(
                              color: Color(0xffce3800),
                              fontSize: 10,
                              fontWeight: FontWeight.bold)),
                    ]),
                  ),
                ),
                Align(
                  widthFactor: 1.2,
                  heightFactor: 1.2,
                  alignment: Alignment(1.2, -5),
                  child: Container(
                    margin: EdgeInsets.only(right: 13),
                    width: 86.w, //+6
                    height: 44.h, //+10
                    child: ElevatedButton(
                      onPressed: () {
   
   
                        print('点我去预约${item.name}');
                      },
                      child: const Text(
                        "预约",
                        style: TextStyle(
                            fontSize: 19,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                      style: ButtonStyle(
                        backgroundColor:
                            MaterialStateProperty.all(const Color(0xFFFF703B)),
                        shape: MaterialStateProperty.all(
                            const RoundedRectangleBorder(
                                //这个0像素圆角style如果删掉的话,按钮会变成默认样式,自带圆角
                                borderRadius:
                                    BorderRadius.all(Radius.circular(0)))),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
// 地址信息 进入地图
          Container(
              padding: EdgeInsets.fromLTRB(19, 20, 0, 10),
              child: Row(
                children: [
                  Image.asset(
                    "images/gpsImgae.png",
                    width: 11.w,
                    height: 13.h,
                    fit: BoxFit.cover,
                  ),
                  Container(
                      padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
                      width: 300.w,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(
                            '距离当前位置2.6公里',
                            style: TextStyle(
                                fontSize: 15, fontWeight: FontWeight.bold),
                          ),
                          GestureDetector(
                            child: Text(
                              '进入地图 >>',
                              style: TextStyle(
                                  fontSize: 15, fontWeight: FontWeight.bold),
                            ),
                            onTap: () {
   
   
                              print('进入地图');
                            },
                          )
                        ],
                      )),
                ],
              )),
        ],
      ),
    );

整体布局解释

这里面的结构布局还是有点乱的。基本就是使用 Container 包裹一个 Column 或者 Row,以我新手理解。垂直多元素布局使用 Column。想有 CSS 里面那种 Flex 布局的话使用 Row 就足够了。Flutter 里面也有 Flex 组件,但我用的少,感觉上面两个就够用了。下面是官方介绍。

Row

Row可以沿水平方向排列其子 Widget。

Column

Column可以在垂直方向排列其子组件。参数和Row一样,不同的是布局方向为垂直,主轴纵轴正好相反。

Container

感觉Container像是一个万能组件,什么都可以。这边我说一下他指定边框线条的样式写法。(百度了好多才找到!其他都是写四条边框的。而我需要的是单独一条边框。)

参考资料视频:https://ninghao.net/video/6441#info

代码

//首先定义一个Container 然后给他加上decoration (修饰器属性)

Container(
  decoration: const BoxDecoration(
      border: Border(
        //同理,需要上边框就写top
          bottom:
              BorderSide(width: 0.5, color: Color(0x20000000)
                  ))),

  child:<省略>
)

预约按钮

预约按钮这边也是费劲了心思,一开始我选择用padding,发现会撑起其他元素,后来又选择用margin,还是一样的问题,会顶起其他元素。苦思冥想,选择使用StackPositioned组件,奈何我页面布局写的太拉。Positioned总是出问题,有时候还没效果。最后!我选择了使用Align,因为他正好适合我这种只想简单的调整一个子元素在父元素中的位置

 Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment(2,0.0),
  child: FlutterLogo(
    size: 60,
  ),
)

Alignment他有两个属性 x、y,分别表示在水平和垂直方向的偏移。

注意:widthFactor,heightFactor 这两个参数一定要大于 1.0 哪怕 1.1 也好,因为Alignment是要和他们俩相乘的(Alignment.xchildWidth/2+childWidth/2, Alignment.ychildHeight/2+childHeight/2) 这是他的公式。


进入地图文字点击

这个布局很简单了就,我上面提到Row他能支持多种布局。详情请移步至官网 API。我这里用到的是crossAxisAlignment: CrossAxisAlignment.start, 就是两个元素,一左一右布局。Text 文本点击我用的是GestureDetector 组件。它是手势识别的组件,可以识别点击、双击、长按事件、拖动、缩放等手势。这里我用到了点击。

  GestureDetector(
    child: Text(
      '进入地图 >>',
    style: TextStyle(
      fontSize: 15, fontWeight: FontWeight.bold),
    ),
    onTap: () {
   
   
      print('进入地图');
     },
    )

列表上下刷新加载的使用

简介

这个是一个上拉加载,下拉刷新的列表。本来是想自己写的,但是遇到很多难题,时间不太够。还是选择使用第三方组件 flutter_easyrefresh 组件只是提供了刷新加载的功能和 UI,至于一次几页,一页多少条这个自己定义。 使用非常简单,单纯记一下语法。

引入方法

pubspec.yaml文件里面添加如下代码,然后执行 Pub get。

flutter_easyrefresh: ^0.0.0 #版本请移步上述地址。懒人可用2.2.1

页面使用

创建一个 Dart 文件,创建一个StatefulWidget类。import 插件

import 'package:flutter_easyrefresh/easy_refresh.dart';

然后实例化一个_controller用来触发刷新和加载动作。

  EasyRefreshController _controller = EasyRefreshController();

剩下就是自由发挥的地方了。根据业务需求来写,我这边只简单的用到了刷新加载,所以我定义俩数组和其余参数就可以。代码如下:

  final jobList = Rx<List<Job>>([]);
  final newJobList = Rx<List<Job>>([]);
  var pageIndex = 1; //页数
  var count = 10; //每页10条
  late  int maxSum;//最多条数
  Map<String, dynamic> map = {
   
   'pageNum': 1};

  void getNewData() {
   
   
    pageIndex = 1;
    map['pageNum'] = pageIndex;
    requestXXXX(map).then((value) {
   
   
      maxSum=value['total'];
      List<Job> list = [];
      value['records'].forEach((item) {
   
   
        list.add(Job.fromJson(item));
      });
      jobList(list);
      newJobList(list);//首次获取刷新,我把最新的数据拿出去,等待加载的时候合并。
    });
  }

  void getMoreData() {
   
   
    pageIndex++;
    map['pageNum'] = pageIndex;
    requestXXXX(map).then((value) {
   
   
      maxSum=value['total'];
      List<Job> list = [];
      List<Job> Newlist = [];
      value['records'].forEach((item) {
   
   
        list.add(Job.fromJson(item));
      });
      newJobList.value.addAll(list);//拿到加载的数据,和我之前第一次刷新的数据合并下。
      Newlist.addAll(newJobList.value);//存放到局部变量。
      jobList(Newlist);//这里用的是GTEX 要覆盖整个数组,才能触发widget的Obx刷新。

    });
  }

  int _count = 0;

Widge 里使用

这里建议先看一下官方文档的使用教程,他有三种方法,我这个是比较基础的。写的有点乱。对着官网写法看,会比较容易些。

官方写法:

 // 方式一
  EasyRefresh(
    child: ScrollView(),
    onRefresh: () async{
   
   
      ....
    },
    onLoad: () async {
   
   
      ....
    },
  )

我的写法:

EasyRefresh(
        controller: _controller,
        firstRefresh: true,
        onRefresh: () async {
   
   
          await Future.delayed(Duration(seconds: 2), () {
   
   
            print("下拉刷新-----");
            getNewData();
            _count = jobList.value.length;
            print("最新条数" + _count.toString());
            _controller.resetLoadState();
          });
        },
        onLoad: () async {
   
   
          await Future.delayed(Duration(seconds: 2), () {
   
   
            print("上拉加载-----");
            getMoreData();
            _count = jobList.value.length;
            print("加载更多条数" + _count.toString());

            _controller.finishLoad(noMore: _count >= maxSum); //这是用来防止多次上拉加载的。
          });
        },
        child: Obx(
          () => Column(
              children: 这里直接map你的数据。
              ),
        ));

关于国际化的问题,官方原话:不提供自带国际化支持,请自行设置 ClassicalHeader 和 ClassicalFooter 中需要展示的文字。

本文同步我的技术文档

相关文章
|
1月前
|
iOS开发 UED
Flutter 动态修改应用图标功能指南
探索Flutter中动态应用图标的实现方法,了解如何为用户提供独特体验,促进用户升级和应用内购买。
Flutter 动态修改应用图标功能指南
|
1天前
|
存储 自然语言处理 API
Flutter应用的国际化支持:实现多语言环境的优雅策略
【4月更文挑战第26天】Flutter提供强大的国际化(i18n)和本地化(l10n)支持,使开发者能轻松实现应用多语言特性。通过定义`.arb`文件来管理字符串资源,使用`LocalizationsDelegate`加载资源,设置应用语言环境,以及在UI中使用`S.of(context).someString`访问字符串。进阶技巧包括字符串格式化、复数形式、双向文本和Unicode支持。充分测试确保所有语言正确显示。随着全球化需求增长,Flutter的国际化支持成为应用开发关键。
|
1月前
|
运维 监控 安全
应用研发平台EMAS常见问题之sophix ios flutter热更新如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
79 0
|
1月前
|
运维 监控 定位技术
应用研发平台EMAS常见问题之flutter插件不支持自定义图标如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
76 0
|
2月前
|
开发框架 开发者 UED
跨平台开发框架Flutter在移动应用开发中的应用与前景
【2月更文挑战第3天】本文将探讨跨平台开发框架Flutter在移动应用开发中的应用价值和未来发展前景。通过分析Flutter的特点和优势,以及其在实际项目中的应用案例,展示了Flutter在提升开发效率、降低成本、增强用户体验等方面的优势。同时,对Flutter在未来移动应用开发领域的发展趋势进行了展望,指出了其在日益激烈的市场竞争中的巨大潜力。
|
3月前
|
容器
Flutter笔记:Box协议的布局约束原理与应用
Flutter笔记:Box协议的布局约束原理与应用
48 0
|
3月前
|
Linux 开发者 iOS开发
Flutter笔记:桌面端应用多窗口管理方案
Flutter笔记:桌面端应用多窗口管理方案
122 0
|
3月前
|
SQL Dart 数据库
Flutter笔记: 在Flutter应用中使用SQLite数据库
Flutter笔记: 在Flutter应用中使用SQLite数据库
198 0
|
3月前
|
Dart 前端开发
Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用
Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用
78 0
|
3月前
|
编解码 缓存 调度
Flutter笔记:Flutter的应用生命周期状态(lifecycleState)管理
Flutter笔记:Flutter的应用生命周期状态(lifecycleState)管理
76 0