从零到应用:我的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 中需要展示的文字。

本文同步我的技术文档

相关文章
|
29天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
117 4
|
1月前
|
缓存 监控 前端开发
优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面
本文探讨了优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面,并通过案例分析展示了具体措施和效果,强调了持续优化的重要性及未来优化方向。
54 10
|
1月前
|
存储 调度 数据安全/隐私保护
鸿蒙Flutter实战:13-鸿蒙应用打包上架流程
鸿蒙应用打包上架流程包括创建应用、打包签名和上传应用。首先,在AppGallery Connect中创建项目、APP ID和元服务。接着,使用Deveco进行手动签名,生成.p12和.csr文件,并在AppGallery Connect中上传CSR文件获取证书。最后,配置签名并打包生成.app文件,上传至应用市场。常见问题包括检查签名配置文件是否正确。参考资料:[应用/服务签名](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5)。
65 3
鸿蒙Flutter实战:13-鸿蒙应用打包上架流程
|
29天前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
40 2
|
3月前
|
传感器 缓存 监控
Stream 组件在 Flutter 中的应用场景有哪些?
Stream 组件在 Flutter 中的应用场景有哪些?
192 58
|
2月前
|
移动开发 Dart 搜索推荐
打造个性化安卓应用:从零开始的Flutter之旅
【10月更文挑战第20天】本文将引导你开启Flutter开发之旅,通过简单易懂的语言和步骤,让你了解如何从零开始构建一个安卓应用。我们将一起探索Flutter的魅力,实现快速开发,并见证代码示例如何生动地转化为用户界面。无论你是编程新手还是希望扩展技能的开发者,这篇文章都将为你提供价值。
|
2月前
|
缓存 监控 前端开发
怎样提升 Flutter 应用的性能
【10月更文挑战第4天】
|
1月前
|
存储 Dart
Flutter&鸿蒙next 实现一个计算器应用
本文介绍了如何使用 Flutter 创建一个简单的计算器应用,包括基本的加减乘除运算。文章详细讲解了界面布局、计算逻辑和状态管理的实现步骤,通过具体的代码示例展示了如何构建计算器界面、处理用户输入和显示计算结果。
89 0
|
1月前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
235 0
|
3月前
|
开发框架 搜索推荐 开发工具
打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第51天】本文是一篇面向初学者的Flutter入门教程,旨在通过简单易懂的语言和实际代码示例,引导读者步入跨平台移动应用开发的世界。文章首先介绍了Flutter的基本概念和优势,然后逐步展示了如何搭建开发环境、创建第一个Flutter应用,并实现了一个简单的待办事项列表。最后,文章探讨了Flutter在实现高性能和美观界面方面的潜力,鼓励读者发挥创意,探索更多可能。
91 15