Flutter从入门到实战
一共分为23个系列
①(Flutter、Dart环境搭建篇) 共3个内容 已更新
②(Dart语法1 篇) 共4个内容 已更新
③(Dart语法2 篇) 共2个内容 已更新
④(Flutter案例开发篇) 共4个内容 已更新
⑤(Flutter的StatelessWidget 共3个内容 已更新
⑥(Flutter的基础Widget篇) 共2个内容 已更新
⑦(布局Widget篇) 共1个内容 已更新
⑧(Flex、Row、Column以及Flexible、Stack篇) 共1个内容 已更新
⑨(滚动的Widget篇) 共4个内容 已更新
⑩(Dart的Future和网络篇) 共3个内容 已更新
⑪(豆瓣案例-1篇) 共3个内容 已更新
⑫(豆瓣案例-2篇) 共3个内容 已更新

官方文档说明

官方视频教程
Flutter的YouTube视频教程-小部件


⑪、豆瓣案例篇

  • 项目搭建前配置
    • 项目配置其他启动的main.dart
  • ①、Flutter 星星评分Widget
    • Flutter 星星评分Widget 带注释的代码
    • Flutter 星星评分Widget 不带注释的代码
    • Flutter 星星评分Widget使用方式
    • 效果图 - Flutter 星星评分Widget 带注释的代码
  • ②、Flutter 虚线Widget
    • 效果图 Flutter 虚线Widget
  • ③、Flutter TabbarWidget
    • 1.main.dart
    • 2. BottomNavigationBarItem 封装
    • 3. 多Page页面封装
      • 3.1 home.dart
      • 3.2 home_content.dart
      • 3.3 subject.dart
      • 3.4 subject_content.dart
    • 4.初始化配置
    • 效果图 - Tabbar

项目搭建前配置

由于我的工程项目用于学习操作
为了方便管理 我直接在项目里面创建豆瓣项目的案例
但是不能同时启动两个main.dart

项目配置其他启动的main.dart

①、Flutter 星星评分Widget

封装成一个Widget 考虑用的是
StatelessWidget还是StateFulWidget
考虑点

  1. 这个Widget是否可以控制的。比如点击改变状态
  2. 如果是能点击、改变状态的话 就封装成FulWidget
  3. 如果只是单纯做展示的话 就封装成lessWidget

考虑点
需要传递什么

  1. 评分的图片
  2. 评分的评分数 当前分数、最大分数
  3. 评分的数量
  4. 评分的尺寸大小
  5. 评分之间的间距
  6. 评分的颜色 未选中、已选中
  7. 评分的点击事件

需要用到什么系统的Widget
Stack (全部星星的包裹)
Row (每个星星的整体)
Icon (星星的图标)
Text (星星的评分数)
CustomClipper 需要用到系统的裁剪功能 比如 0.2星星的情况

Flutter 星星评分Widget 带注释的代码

// 1.星星评分Widget
class YHStarRating extends StatefulWidget {final double? rating; // 评分数final double maxRating; // 最大评分数final int count; // 评分总数量final double size; // 评分大小final Color unselectedColor; // 未选中颜色final Color selectedColor; // 选中的颜色final Widget unselectedImage; // 未选中图片final Widget selectedImage; // 选中图片YHStarRating({// 必传参数  this.rating 评分数@required this.rating,this.maxRating = 10,this.count = 5,this.size = 30,this.unselectedColor = const Color(0xffbbbbbb),this.selectedColor = const Color(0xffff0000),Widget? unselectedImage,Widget? selectedImage,}): this.unselectedImage  = unselectedImage ?? Icon(Icons.star_border,color: unselectedColor,size: size),this.selectedImage = selectedImage ?? Icon(Icons.star, color: selectedColor, size: size);// 判断有没有图片传递进行。如果没有使用默认的Icon创建的星星// const YHStarRating({Key? key}) : super(key: key);@overrideState<YHStarRating> createState() => _YHStarRatingState();
}class _YHStarRatingState extends State<YHStarRating> {@overrideWidget build(BuildContext context) {return Stack(children: [builderStarRow(buildUnselectedStar()),builderStarRow(buildSelectedStar()),// Row(//   // 由于内容是填充尽可能大 。所以需要设置内容为最小//   mainAxisSize: MainAxisSize.min,//   // 动态决定多少个星星 并且封装函数//   children:buildUnselectedStar(),// ),// Row(//   // 由于内容是填充尽可能大 。所以需要设置内容为最小//   mainAxisSize: MainAxisSize.min,//   children: buildSelectedStar(),// )],);}// 封装函数 提高阅读代码// 默认星星List<Widget> buildUnselectedStar(){return List.generate(widget.count, (index) {return widget.unselectedImage;// return  Icon(Icons.star_border,color: widget.unselectedColor,size: widget.size);});}// 选中星星的函数List<Widget> buildSelectedStar() {// 案例// 比如一共是10分 那么 评分 8分 就是4个满星 1个空星// 比如一共是10分 那么 评分是 5 分 那么就是2个满星 一个半星// 先计算一个星是多少分// 总分数 / 总个数 = 每个星的分数// 10 / 5 = 每个星的分数// 1.创建starsList<Widget> stars = [];// final star = Icon(Icons.star, color: widget.selectedColor, size: widget.size);final star = widget.selectedImage;// 2. 构建满填充的 stardouble oneValue = widget.maxRating / widget.count;int entireCount = (widget.rating! / oneValue).floor(); // 使用向下取整 不管是4.9 都只能是4个for (var i = 0; i < entireCount; i++){stars.add(star);}// 3. 构建部分填充的 star 进行裁剪(ClipRect)// 计算部分填充的值// 总星星个数 - 总整个填充的// 比如总评分数是3.5 - 3 = 0.5// (widget.rating! / oneValue) - entireCount// 然后计算占据的比例// ((widget.rating! / oneValue) - entireCount) *widget.sizedouble leftWidth =  ((widget.rating! / oneValue) - entireCount) * widget.size;final halfStar =  ClipRect(clipper: YHStarClipper(leftWidth),child:star);stars.add(halfStar);// 满分超出范围的处理if(stars.length > widget.count){return stars.sublist(0,widget.count);// 裁剪}return stars;}// Row的函数抽取Row builderStarRow(List<Widget> children){return Row(mainAxisSize: MainAxisSize.min,children:children);}
}// 自定义裁剪
// 我们星星当做一个矩形来进行裁剪 所以需要在CustomClipper后面进行一个声明 Rect
class YHStarClipper extends CustomClipper<Rect>{double width;YHStarClipper(this.width);// 自定义裁剪 必须实现两个抽象方法@overrideRect getClip(Size size) {// TODO: implement getClip// 裁剪的位置return Rect.fromLTRB(0, 0, width, size.height); // size.height 是Widget的高度}// 重新裁剪@overridebool shouldReclip(covariant YHStarClipper oldClipper) {// TODO: implement shouldReclip// 当旧的宽度 和 当前的宽度不一致才需要重新裁剪return oldClipper.width != this.width;}
}

Flutter 星星评分Widget 不带注释的代码

// 1.星星评分Widget
class YHStarRating extends StatefulWidget {final double? rating; // 评分数final double maxRating; // 最大评分数final int count; // 评分总数量final double size; // 评分大小final Color unselectedColor; // 未选中颜色final Color selectedColor; // 选中的颜色final Widget unselectedImage; // 未选中图片final Widget selectedImage; // 选中图片YHStarRating({@required this.rating,this.maxRating = 10,this.count = 5,this.size = 30,this.unselectedColor = const Color(0xffbbbbbb),this.selectedColor = const Color(0xffff0000),Widget? unselectedImage,Widget? selectedImage,}): this.unselectedImage  = unselectedImage ?? Icon(Icons.star_border,color: unselectedColor,size: size),this.selectedImage = selectedImage ?? Icon(Icons.star, color: selectedColor, size: size);@overrideState<YHStarRating> createState() => _YHStarRatingState();
}class _YHStarRatingState extends State<YHStarRating> {@overrideWidget build(BuildContext context) {return Stack(children: [builderStarRow(buildUnselectedStar()),builderStarRow(buildSelectedStar()),],);}// 封装函数 提高阅读代码// 默认星星List<Widget> buildUnselectedStar(){return List.generate(widget.count, (index) {return widget.unselectedImage;// return  Icon(Icons.star_border,color: widget.unselectedColor,size: widget.size);});}// 选中星星的函数List<Widget> buildSelectedStar() {List<Widget> stars = [];final star = widget.selectedImage;double oneValue = widget.maxRating / widget.count;int entireCount = (widget.rating! / oneValue).floor(); for (var i = 0; i < entireCount; i++){stars.add(star);}double leftWidth =  ((widget.rating! / oneValue) - entireCount) * widget.size;final halfStar =  ClipRect(clipper: YHStarClipper(leftWidth),child:star);stars.add(halfStar);// 满分超出范围的处理if(stars.length > widget.count){return stars.sublist(0,widget.count);}return stars;}Row builderStarRow(List<Widget> children){return Row(mainAxisSize: MainAxisSize.min,children:children);}
}// 自定义裁剪
class YHStarClipper extends CustomClipper<Rect>{double width;YHStarClipper(this.width);@overrideRect getClip(Size size) {return Rect.fromLTRB(0, 0, width, size.height);}@overridebool shouldReclip(covariant YHStarClipper oldClipper) {return oldClipper.width != this.width;}
}

Flutter 星星评分Widget使用方式

class YHiOSHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("豆瓣"),),body: Center(// 评分数、最大评分数、星星个数child: YHStarRating(rating: 7,maxRating: 5, count: 5),),);}
}

效果图 - Flutter 星星评分Widget 带注释的代码

②、Flutter 虚线Widget

考虑点

  1. 虚线的方向
  2. 虚线的方向的宽度
  3. 虚线的方向的高度
  4. 虚线的颜色

使用到系统的Widget

  1. 方向
  2. sabox 每一根虚线
class YHiOSHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("豆瓣"),),body: Center(child:Column(mainAxisAlignment: MainAxisAlignment.center,children: [Container(width: 200,child: YHDasheLine(dashedWidth: 8,count: 10),),Container(height: 200,child: YHDasheLine(axis: Axis.vertical, dashedHeight: 5,count: 15),),],),),);}
}// 1.虚线
// 只负责展示 所以直接使用StatelessWidget 即可
class YHDasheLine extends StatelessWidget {// 1.提供的方向final Axis axis;final double dashedWidth; // 虚线的宽度final double dashedHeight; // 虚线的高度final int count; // 虚线的数量final Color color; // 虚线的颜色YHDasheLine({this.axis = Axis.horizontal,this.dashedWidth = 1,this.dashedHeight = 1,this.count = 10,this.color = Colors.red,});@overrideWidget build(BuildContext context) {return Flex(direction: axis,// 间距 使用 主轴对齐方式mainAxisAlignment: MainAxisAlignment.spaceBetween,// 用不上索引 使用 _ tichildren: List.generate(count, ( _ ) {return SizedBox(width: dashedWidth,height: dashedHeight,// SizedBox没有 颜色属性 使用 Child 给SizedBox进行一个装饰child: DecoratedBox(decoration: BoxDecoration(color: color),),);}),);}
}

效果图 Flutter 虚线Widget

③、Flutter TabbarWidget

考虑点
使用系统哪些Widget去实现

  1. Stack 能将内容进行包裹
  2. 使用 IndexedStack 进行包裹page页面
  3. 进行main、初始化配置、多个page页面进行抽取
    总结
    item的封装、页面和页面内容的封装、初始化列表的封装
    如果有网络请求、UI 建议多个文件夹管理(core,UI)

1.main.dart

import 'package:flutter/material.dart';
import 'package:learn_flutter/douban/pages/main/bottom_bar_item.dart';
// import 'package:learn_flutter/douban/pages/main/initialize_item.dart';// 绝对引入
import 'initialize_item.dart';// 相对引入 相当于在main.dart这个文件夹 引入initialize_item.dart  说明 initialize_item.dart和main.dart在同一个文件夹class YHMainPage extends StatefulWidget {@overrideState<YHMainPage> createState() => _YHMainPageState();
}class _YHMainPageState extends State<YHMainPage> {int _currentIndex = 0; // 记录当前tabbar点击的索引@overrideWidget build(BuildContext context) {return Scaffold(body: IndexedStack(index: _currentIndex,children: config_pages),bottomNavigationBar: BottomNavigationBar(// 点击选择默认字体会有一个放大和缩小// 因为系统设置 选中为 14 默认为 12selectedFontSize: 14,unselectedFontSize: 14,// selectedItemColor: Colors.red,// unselectedItemColor: Colors.blue,// item点击 记录切换currentIndex: _currentIndex,// 当item 超过4个就需要设置typetype: BottomNavigationBarType.fixed,items: config_items,onTap: (index){setState(() {_currentIndex = index;});},),);}//1.BottomNavigationBarItem 封装函数BottomNavigationBarItem buildBottomItem(iconName,title){return BottomNavigationBarItem(label: title,icon: Image.asset("assets/images/tabbar/$iconName.png",width: 32),activeIcon: Image.asset("assets/images/tabbar/${iconName}_active.png",width: 32));}
}// 2.BottomNavigationBarItem 封装类

2. BottomNavigationBarItem 封装

import 'package:flutter/material.dart';class YHBottomBarItem extends BottomNavigationBarItem {YHBottomBarItem(String iconName,String title):super(label: title,icon: Image.asset("assets/images/tabbar/$iconName.png",width: 32),activeIcon:  Image.asset("assets/images/tabbar/${iconName}_active.png",width: 32),);
}

3. 多Page页面封装

3.1 home.dart

import 'package:flutter/material.dart';
import 'home_content.dart';class YHHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页"),),body: YHHomeContent(),);}
}

3.2 home_content.dart

import 'package:flutter/material.dart';class YHHomeContent extends StatefulWidget {@overrideState<YHHomeContent> createState() => _YHHomeContentState();
}class _YHHomeContentState extends State<YHHomeContent> {@overrideWidget build(BuildContext context) {return Center(child: Text("首页内容",style: TextStyle(fontSize: 30,color: Colors.red)),);}
}

3.3 subject.dart

import 'package:flutter/material.dart';
import 'subject_content.dart';class YHSubjectPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页"),),body: YHSubjectContent(),);}
}

3.4 subject_content.dart

import 'package:flutter/material.dart';class YHSubjectContent extends StatefulWidget {@overrideState<YHSubjectContent> createState() => _YHHomeContentState();
}class _YHHomeContentState extends State<YHSubjectContent> {@overrideWidget build(BuildContext context) {return Center(child: Text("书影音内容",style: TextStyle(fontSize: 30,color: Colors.red)),);}
}

4.初始化配置

import 'package:flutter/cupertino.dart';
import 'package:learn_flutter/douban/pages/home/home.dart';
import '../subject/subject.dart';
import 'bottom_bar_item.dart';// 初始化抽取// 1. tabbar item
List<YHBottomBarItem> config_items = [YHBottomBarItem("home", "首页"),YHBottomBarItem("subject", "书影音"),YHBottomBarItem("group", "小组"),YHBottomBarItem("mall", "市集"),YHBottomBarItem("profile", "我的"),
];// 1. 每个tabbar的页面
List<Widget> config_pages = [YHHomePage(),YHSubjectPage(),YHHomePage(),YHSubjectPage(),YHHomePage(),];

效果图 - Tabbar

【Flutter从入门到实战】⑪、豆瓣案例-1、星星评分Widget、虚线Widget、TabbarWidget、BottomNavigationBarItem的封装、初始化配置抽取相关推荐

  1. 【Flutter从入门到实战】 ⑨、滚动的Widget-ListView、GridView、SliverWidget、滚动的Widget的滚动监听的方式

    Flutter从入门到实战 一共分为23个系列 ①(Flutter.Dart环境搭建篇) 共3个内容 已更新 ②(Dart语法1 篇) 共4个内容 已更新 ③(Dart语法2 篇) 共2个内容 已更新 ...

  2. 【Flutter从入门到实战】 ⑧、FlexWidget、Flex的主轴和交叉轴、Row和Column的使用、Expanded的FlexFit和flex的使用、Stack、Positioned的使用

    Flutter从入门到实战 一共分为23个系列 ①(Flutter.Dart环境搭建篇) 共3个内容 已更新 ②(Dart语法1 篇) 共4个内容 已更新 ③(Dart语法2 篇) 共2个内容 已更新 ...

  3. 新书推荐 | Flutter技术入门与实战(第2版)

    新书推荐 <Flutter技术入门与实战(第2版)> 长按二维码 了解及购买 从实战角度出发,手把手教会Flutter,案例丰富,实操性强. 编辑推荐 本书在上一版的基础上,根据Flutt ...

  4. Flutter+Dart入门与实战套餐(含电子商城系统)

    套餐(全): https://ke.qq.com/course/package/23970?tuin=2c77f7f0 课程目标 掌握Dart语言及Flutter跨平台开发技术 适用人群 零基础,小白 ...

  5. PyTorch深度学习入门与实战(案例视频精讲)

    作者:孙玉林,余本国 著 出版社:中国水利水电出版社 品牌:智博尚书 出版时间:2020-07-01 PyTorch深度学习入门与实战(案例视频精讲)

  6. Flutter从入门到实战(一)之环境搭建(Mac版)

    Flutter从入门到实战(一)之环境搭建(Mac版) Flutter官网镇楼 Flutter SDK 下载 镜像使用 运行 flutter doctor iOS环境配置 Android环境配置 下载 ...

  7. Jetson Nano 从入门到实战(案例:Opencv配置、人脸检测、二维码检测)

    目录 1. Jetson Nano简介 2. Jetson Nano环境配置 2.1 开箱配件介绍 2.2 烧录系统 2.3 开机和基本设置 2.4 开发环境配置 2.4.1 更新源和软件 2.4.2 ...

  8. python编程入门与案例详解pdf-Flutter技术入门与实战 PDF 清晰版

    给大家带来的一篇关于Flutter相关的电子书资源,介绍了关于Flutter入门.Flutter实战.Flutter技术方面的内容,本书是由机械工业出版社出版,格式为PDF,资源大小162.5 MB, ...

  9. 从入门到实战,Netty多线程篇案例集锦

    从入门到实战,Netty多线程篇案例集锦 原创 2015-09-10 李林峰 InfoQ Netty案例集锦系列文章介绍 1|Netty的特点 Netty入门比较简单,主要原因有如下几点: Netty ...

最新文章

  1. EXTJS布局示例(panel,Viewport,TabPanel)
  2. .NET Core开发实战(第7课:用Autofac增强容器能力)--学习笔记(下)
  3. MATLAB图像中添加标记
  4. 《软件需求分析(第二版)》第 14 章——需求管理的原则和实践 重点部分总结
  5. 利用SSL协议配置web服务器,基于windows2008平台配置实现利用SSL协议的安全IISWeb服务器汇总.doc...
  6. informix sybase数据库下载地址
  7. 红巨星转场特效预设AE插件 Red Giant Universe 6.0.1 WIN
  8. 百度离线地图瓦片图制作
  9. 大学计算机音乐一起学,和学生一起学音乐
  10. 土巴兔CEO王国彬:这五点,决定了你事业的上限
  11. Educational Codeforces Round 123 (Rated for Div. 2)(ABCDE)
  12. 并行与分布式计算导论(七)MPI Collective Communication
  13. latex制作三线表
  14. 微信小程序云开发-内容管理系统(CMS)小案例
  15. Android APP开发框架选择——JSBridge既个人心得和技巧
  16. CAcls命令在提权中的使用
  17. win10linux远程命令,IT之家学院:在Win10下管理远程命令行
  18. java蓝桥杯——矩形面积交
  19. VCIP 2020:面向VVC的自适应分辨率改变
  20. office2003稿纸加载项的删除解决方法

热门文章

  1. 流程设计建模方法:流程的需求梳理之活动属性梳理
  2. ZCMU - 1931: wjw的剪纸
  3. move_uploaded_file()移动文件失败?
  4. 前端PDF文件转图片方法(你值得收藏)
  5. java教学视频毕向东_集合3--毕向东java基础教程视频学习笔记
  6. 定额人工费调整差额的几个解决方案
  7. 数码博主自用五款高性价比蓝牙耳机分享,双11不想踩雷选什么蓝牙耳机好?
  8. 漫画:什么是蓝绿部署?
  9. C/C++找工作这点事
  10. (最新整理)国内网页设计网站网址大全(转)