你们好,我是练习时长1年的Flutter练习生,渣渣法,喜欢写bug,发鸡汤,当吃播。html
一晃眼,入坑Flutter已经一年的时间,Flutter Candies 全家桶也从我一我的到如今有八我的,项目也接近30个,收获颇多,但愿有更多的人能加入咱们,一块儿制造更多好用的Flutter🍬。linux
Flutter Candies QQ群: 181398081,人还很少,可是很热闹。这是一个摆龙门阵的地方;能够求助现场大佬/观众的地方;也是能够互相学习共同进步的地方。ios
加入掘金跟入坑Flutter的时间同样,也是一年了,感恩。单纯的技术平台,让程序猿们都聚在一块儿,互相学习,共同进步。说它单纯呢,它却不那么正经,有各类板块(相亲,摸鱼,翻译等等),我如今都把它当朋友圈用了,@all, 你今天收到了个人鸡汤了吗?git
感恩抱过的大腿们(大部分都是喵头像,是否是巧合),Vadaski ,JarvanMo,debuggerx,恋猫de小郭, wendux,低调,拉面等等等。感谢大佬的帮助,这也是Flutter Candies建立的用意,但愿也能帮助到其余人,为Flutter社区贡献微薄之力。本身从大佬那里学到了,而后能够告诉别人,别人又能够再传递给其余人,这样社区才会愈来愈好。github
这是一个集合了Flutter开发中经常使用的组件/插件🍬的全家桶,你们能够很方便的集成到本身的项目当中,下面我按照做者来介绍Flutter Candies 的各个项目。篇幅会有点长,请准备好瓜子汽水坐好,开车了,滴滴滴滴滴。web
从开始在群里提需求,到能够在群里解答问题 ;从一个养鱼专业的学生,到入行Flutter岗位工做。4月份入群到如今,看到了他的变化,也看到🍬组织的意义。入坑以后就住在了Github上面。 json
精美的校园App,整个应用的完成度很是高,功能完整,由于帐号权限的问题,没法登陆。若是你看到某个功能,能够去找这个功能的实现代码,找不到的话能够来群里问问。 canvas
![]() |
![]() |
![]() |
---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
从0搭建的Flutter实战项目,项目代码继续更新中,感兴趣的小伙能够关注, 掘金文章地址,跟着从0开始写Flutter项目。windows
波纹扩散,而且带高斯模糊,按钮跳动效果,喜欢骚的童鞋能够收藏起来了。掘金文章地址api
最近刚入桶的兄弟,有责任心的开发者,对本身的项目会不断进行优化,达到最完美的状态
主要功能
![]() |
![]() |
![]() |
---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
|
![]() |
![]() |
喜欢的小伙伴赶快收藏起来吧 掘金文章地址
公众号 Flutter笔记做者, Flutter小能手,欢迎关注微信公众号
![]() |
![]() |
![]() |
---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
学习Flutter的一个途径就是模仿现有的App,在Flutter上面进行实现。这是一个从0搭建的网易云音乐。你们能够跟随着做者的思路一步步完成一个完整的Flutter项目。界面很舒服,功能持续更新中,你们快来收藏吧 掘金文章地址
目前最好用的仿微信聊天长按弹出框,喜欢微信风格的小伙伴记得收藏起来掘金文章地址
低调,老乡,不能吃辣的四川人(偷笑.gif), 反正就很牛逼就是了。Flutter 小白鼠,任何新东西他都要去玩一下。我也跟着踩他填好的坑,在Flutter的路上一去不回。Pub 25个。。可怕。。都是高分做品
flutter_image_editor能够说是低调为extended_image量身打造的原生插件,支持旋转裁剪翻转,extended_image负责图片编辑UI,flutter_image_editor提供原生裁剪图片数据能力。因为dart image库在处理图片的效率问题,原生库(期待纯C++库)就有了很大的优点(大图片能够有10倍速度的提高)。正是由于teamwork才能使flutter上面对于图片编辑处理最终达到一个完美的状态。
法法,200,Flutter Candies 🍬 全家桶的楼主。在感觉到大佬们的感化以后,也但愿能帮助到更多的Flutter开发者。pub目前13个,属于项目中比较经常使用的组件。
作项目遇到的第一个遇到的问题就是官方的NestedScrollView,各方求证以及查看源码以后发现应该只是as design。若是你即将使用官方的NestedScrollView,强力建议先看一下,你一定会遇到下面的问题 掘金文章地址
其实官方对这个是有处理的,是经过SliverOverlapAbsorber包裹SliverAppbar,代码不上了,其实NestedScrollView的注释里面就有.
可是问题在,于若是header里面有多个pinned=true的sliver,咱们该怎么处理了?为此我扩展了官方的组件。你能够经过设置pinnedHeaderSliverHeightBuilder回调来解决这个问题,在下面的代码中,pinnedHeaderHeight其实就是SliverAppbar最后折叠起来以后高度=状态栏高度+导航栏高度.若是你header中有其余锁定的sliver,你能够再把它们的高度加进去。
var pinnedHeaderHeight =
//statusBar height
statusBarHeight +
//pinned SliverAppBar height in header
kToolbarHeight;
return NestedScrollView(
pinnedHeaderSliverHeightBuilder: () {
return pinnedHeaderHeight;
},
复制代码
因为NestedScrollView内部里面有一个ScrollController,TabView里面的列表的ScrollPosition都将会attach到这个sc上面,在滚动其中一个的时候,同步所有的ScrollPositions。因为篇幅缘由,我这里直接放以前的文章了。
因为body里面的列表必须共用同一个ScrollController,因此你是不能给列表单独设置ScrollController,这样会致使内部的outer_scroll_controller和inner_scroll_controller没法协同工做。
你们想使用ScrollController无非3点。
1.下拉刷新,已提供demo
2.加载更多,已提供demo
3.控制列表滚动,已将属性暴露出来
import 'package:flutter/widgets.dart' hide NestedScrollView;
复制代码
Flutter上面最能打的图片库(这样说没人打我吧) 掘金文章地址
主要功能
设计原则是,若是你须要重写一个状态,就返回你想要的效果,不然请返回null。下面是一个重写“正在加载”的例子
ExtendedImage.network(
item.imageUrl,
loadStateChanged: (ExtendedImageState state) {
if (state.extendedImageLoadState == LoadState.loading) {
return Container();
}
return null;
},
);
复制代码
不少人由于在重写了completed状态而丢失了手势和裁剪功能,为此我新增了ExtendedImageState.completedWidget。下面是重写completed状态而不丢失裁剪手势功能的例子。
ExtendedImage.network(
item.imageUrl,
loadStateChanged: (ExtendedImageState state) {
if (state.extendedImageLoadState == LoadState.completed) {
return Padding(
padding: EdgeInsets.all(10.0),
child: state.completedWidget,
);
}
return null;
},
);
复制代码
请自行查看issue
extended_image的基础库,若是你只须要网络图片缓存功能,你能够只引用这个库
Image(
image: ExtendedNetworkImageProvider("", cache: true),
);
复制代码
富有中国特点强大功能的富文本 掘金文章地址
主要功能
为了快速构建富文本,好比把 '[love]' 这种文字变成表情图片,提供了SpecialTextSpanBuilder。其原理很简单,就是根据你本身的规则,将文字转换成各类InlineSapn(TextSpan,ImageSpan,WidgetSpan).
这里build方法是用入栈的方式遍历文字,createSpecialText方法是用来根据你本身的规则建立SpecialText的。有一些用户可能以为太复杂了,可是我这样考虑就是为了你们能根据本身业务的需求来自定义本身的规则。耐心看懂demo,你能够快速的自定义本身的富文本
abstract class SpecialTextSpanBuilder {
TextSpan build(String data,
{TextStyle textStyle, SpecialTextGestureTapCallback onTap})
SpecialText createSpecialText(String flag,
{TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index});
}
复制代码
Flutters上面惟一能支持输入内容是WidgetSpan的输入框 掘金文章地址
主要功能
仿掘金推特色赞按钮,带数量滚动动画掘金文章地址
能够在任何滚动场景中使用(包括NestedScrollView)的自定义下拉刷新组件, 只提供了下拉刷新的状态,你能够最大化的自定义本身的效果而不用拘泥于组件自己提供。你能够根据状态距离,构建出任何你想要的效果。demo里面的4种效果只是例子,欢迎你们pr更多更有趣的效果。掘金文章地址
这2个问题均可以经过设置列表的physics来解决,我这里提供了AlwaysScrollableClampingScrollPhysics。
///in case list is not full screen and remove ios Bouncing
class AlwaysScrollableClampingScrollPhysics extends ClampingScrollPhysics {
const AlwaysScrollableClampingScrollPhysics({ScrollPhysics parent})
: super(parent: parent);
@override
AlwaysScrollableClampingScrollPhysics applyTo(ScrollPhysics ancestor) {
return AlwaysScrollableClampingScrollPhysics(parent: buildParent(ancestor));
}
@override
bool shouldAcceptUserOffset(ScrollMetrics position) {
return true;
}
}
复制代码
继承了UWP的加载更多思想的做品,将UI跟数据源的契约完美打通,你只要写过一次,你就会爱上这种方式。掘金文章地址
支持TabBarView的联动,就是说二级TabBarView不能滑动了,就看一级能不能滑动,能滑动就滑动一级的 掘金文章地址
轻巧灵活的路由注解工具,一行命令完成路由映射. 掘金文章地址
使用C#以及Flutter构建的json转换dart实体类工具,提供超级多的平台选择,大气的ui界面(偷笑.gif) 掘金文章地址
平台 | 语言 | 描述 | 代码/安装包地址 |
---|---|---|---|
windows | C# | uwp构建,运行环境windows10,x86/x64 | windows-uwp.zip |
windows | C# | wpf构建,运行环境windows10/windows8/widnows7,x86/x64 | windows-wpf.zip |
windows | dart | flutter构建, 使用官方方式编译,x64 ,debug版本 | windows-x64-flutter.zip |
windows | dart | flutter构建, 使用go-flutter编译,x64 ,debug版本 | windows-x64-go-flutter.zip |
mac | dart | flutter构建,使用go-flutter编译(官方方式,未找到产物) | mac-go-flutter.zip |
web | C# | silverlight构建, 须要安装silverlight插件,有浏览器限制 | 网页地址和带字体文件网页地址 |
web | dart | flutter-web构建 | 网页地址 |
linux | dart | flutter构建, 使用官方方式编译,(没有环境测试,伪装能够用) | 代码地址 |
Flutter中国官方网站,Flutter官方明媒正娶,从入门到深刻,各类资源应有尽有。若是你准备入手Flutter,这应该是你必看的网站。
每一个人都从萌新而来,若是你想开森的写代码,本身解决问题是必须的
英语是很重要的。
问问题的时候,尽可能上代码,或者说明你的意图,由于可能你的想法或者解决方向就是错误的
若是实在没法本身解决,能够求助于大佬,可是请注意提问方式,毕竟好沟通能节约双方的时间,大佬也要工做也要吃饭。
把你的想要效果的插件的名字或者其余平台的组件叫什么名字,转为为英文,到pub 上面搜索,分高的使用的人多,相对就比较稳定更好。
咱们常常运行别人组件的时候,发现各类下载失败,各类下载缓慢 请使用国内镜像,飞通常的赶脚。
google()
jcenter()
替换为下面
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
#distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
#csdn镜像
distributionUrl=https\://downloads.gradle-dn.com/distributions/gradle-5.1.1-all.zip
复制代码
在开发中,咱们发现给组件设置了大小,可是却没有效果。举个栗子,在Appbar的leading/actions中,咱们想直接设置宽高是不可能的。 咱们须要使用UnconstrainedBox来移除父widget对子大小的限制,以下代码
AppBar(
title: Text(widget.title),
leading: UnconstrainedBox(
child: Container(
width: 50.0,
height: 10.0,
color: Colors.red,
),
),
),
复制代码
double keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
复制代码
Column(
children: <Widget>[
///你的布局
Expanded(
child: Container(),
),
///顶起你的布局
Container(
height: keyboardHeight,
)
],
);
复制代码
其实这个我也是在源码里面scaffold.dart中看到的,抄做业很重要
关键代码
中国镜像你在等什么呢,学起来
issue地址 经过设置下面代码解决,全局设置文字主题
textTheme: theme.textTheme.copyWith(
subhead: theme.textTheme.subhead
.copyWith(textBaseline: TextBaseline.alphabetic)),
复制代码
咱们常常听到的就是为何个人文本设置了溢出显示,可是它却显示黄色溢出警告了? 对于文本Text来讲,若是它的父Widget没有给它作大小限制,它默认是无限长的 咱们解决的方法以下。
return Row(
children: <Widget>[
Flexible(
child: Text(
"我是一个很短的文本",
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12),
),
),
Container(
color: Colors.red,
width: 100.0,
)
],
);
复制代码
return Row(
children: <Widget>[
Expanded(
child: Text(
"我是一个很短的文本",
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12),
),
),
Container(
color: Colors.red,
width: 100.0,
)
],
);
复制代码
Expaned/Flexible 二者的区别就在于,Expanded会强制占100剩余的空间,而Flexible能够自适应。固然他们最大也都是占100剩余的空间。
更多的细节,你能够查看文章
因为官方的Appbar增长了对material风格的设置,因此不少地方都有一些限制。其实也不能怪官方,这是一种设计规范。可是咱们就是想本身骚怎么办呢?? 我以前写了个 my_app_bar.dart,以前一直放gists上面,不方便你们查看,如今也移入了🍬。这是一个简单的实现,看明白了代码原理以后,你能够扩展出更多适合本身的appbar。
由于有好几我的问过,因此我写了个简单的demo。主要是靠NotificationListener来监听滚动来控制头部。
不是每一种警告,都是必定要管的。警告只是官方告诉你须要注意这点,这就是为何Release下面不会出现警告。警告不等于错误。
我这里举一个栗子。NestedScrollView的body实际上是SliverFillRemaining包住的,它会跟着一块儿滚动。可是咱们这里布局里面是一个Tabbar,它是一个有固定高度的组件,当它超出屏幕的时候就会出现警告。可是事实上,这种警告并不能影响咱们的使用。
若是你是由于页面从新build就影响你的业务,那应该好好检查下业务逻辑代码。build的缘由是route变化时候的动画,以及NavigatorState中Overlay(实际就是Stack),route位置变化而引发的页面build。
Listview里面嵌套Listview,是我常常看到过的,会报错。而后就会有人说 把这个设置成shrinkWrap 设置成true。下面咱们来看看这个属性的意思。
/// Whether the extent of the scroll view in the [scrollDirection] should be determined by the contents being viewed.
///
/// If the scroll view does not shrink wrap, then the scroll view will expand to the maximum allowed size in the [scrollDirection]. If the scroll view has unbounded constraints in the [scrollDirection], then [shrinkWrap] must be true.
///
/// Shrink wrapping the content of the scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes.
///
/// Defaults to false.
final bool shrinkWrap;
复制代码
设置shrinkWrap为true,scrollview的范围将是所有内容的高度,不然是为viewport的高度。列表或者说ScrollView其实有一个可视区域的概念(Viewport),就是滚动时候的可见的部分,这个区域的大小每每须要你本身告诉他或者它的父亲告诉它,超出这个范围的内容会根据状况进行回收。
咱们这里看到为何直接使用Listview嵌套Listview会报错了。由于Listview自己是无高度限制的,而你把一个Listview放在一个Listview里面,里面的Listview的viewport是无从得知的。那怎么办呢? 那只能使用设置shrinkWrap为true,让里面的Listview的高度其实等于本身所有内容的高度。这样外面Listview就能知道这个孩子的高度了。
设置shrinkWrap为true,更消耗性能。由于在滚动的时候都须要从新去计算高度是否变化。而且不会回收可视区域以外的内容。
使用ListView嵌套Listview的场景每每都能使用Sliver系列来解决,详情请看下一个问题
Sliver系列的东东不少,咱们下面来一一介绍一下。
CustomScrollView 是Sliver组件的老祖宗,所有的Sliver都放在这个里面,你们别看ListView/GridView跟他们不同,其实里面仍是Sliver系列,只是不能将他们直接放到Sliver里面,也不建议这样作。
NestedScrollView这个也是你们常用到的,其实里面是一个CustomScrollView,它的headers是Sliver的数组,body是被包裹在 SliverFillRemaining 中的
SliverList 列表跟ListView用法差很少,跟CustomScrollView一块儿使用
SliverFixedExtentList, 比SliverList多一个就是相同的Extent,这样性能会更好,跟CustomScrollView一块儿使用
SliverPrototypeExtentList 主轴上面有相同的Extent,跟SliverFixedExtentList灵活,不须要设置Extend,而是根据prototypeItem来获取Extent
SliverGrid, 能够设置每行的个数的Grid,跟CustomScrollView一块儿使用
SliverPadding,跟Padding同样的使用,区别是child变成了sliver
SliverPadding(
sliver: SliverList(),
padding: EdgeInsets.all(5.0),
);
复制代码
SliverPersistentHeader 很是好用的组件,SliverAppBar就是用这个实现的。这个组件的特色是能够建立出随着滑动变化的能够Pinned的元素,你们常常用的什么吸顶组件能够用这个很方便的构建,前面讲到的自定义SliverAppbar(my_app_bar.dart)就是利用它实现的。
SliverAppBar 跟Appbar的最大区别就能够根据滚动状态来折叠内容,主要是由状态栏高度+导航栏高度+折叠高度组成
SliverToBoxAdapter 当你想把一个非Sliver的Widget放在CustomScrollview里面的时候,你须要用这个包裹一下。
SliverSafeArea 为了防止各类边界的越界,好比说越过顶部的状态栏
SliverFillRemaining使用这个它会填充完viewport里面的剩余所有空间。NestedScrollView的body就是这个包裹住的。
SliverOverlapAbsorber,SliverOverlapAbsorberHandle 这个是关于NestedScrollView 解决Pinned头部的,这里不赘述,我前面也讲的有。
其实Sliver系列没有那么可怕,若是你弄懂每个Sliver的使用场景,你能够完成其余平台可能须要很费劲才能作出来的效果。下面举一些经常使用的栗子吧。
return CustomScrollView(
slivers: <Widget>[
SliverList(),
SliverList(),
],
);
复制代码
若是你是水平垂直嵌套的话,能够设置内部那个Listview的高度或者宽度
return ListView(
children: <Widget>[
SizedBox(
height: 60.0,
child: ListView.builder(
itemBuilder: (c, index) {}, scrollDirection: Axis.horizontal),
)
],
);
复制代码
注意这个NestedScrollView不是官方的,是我扩展的。详细状况请看上面
///由于SliverAppBar是pinned:true,因此咱们须要算上这部分高度
var pinnedHeaderHeight =
//statusBar height
statusBarHeight +
//pinned SliverAppBar height in header
kToolbarHeight;
return NestedScrollView(
pinnedHeaderSliverHeightBuilder: () {
return pinnedHeaderHeight;
},
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled)
{
return <Widget>[
SliverAppBar(pinned:true),
//但是banner,也能够是广告位之类的
SliverToBoxAdapter(),
//固然能够个列表
SliverList(),
//咱们也能够在这里建立能够吸顶的内容
//若是这个是pinned等于true的,记得把这部分高度增长到pinnedHeaderHeight当中
SliverPersistentHeader()
];
},
body: Column(
children: <Widget>[
///最终Tabbar会被Pinned在SliverAppbar(pinned:true)下面。
///固然,好比说sliverappbar下面 有另一个pinned为ture的 ///sliver。那边tabbar最后会在这个pinned ///true的sliver下面。(总的pinnedHeaderHeight高度应该是(状///态栏高度+导航栏高度=pinned为true的SliverAppbar)+pinne///d为ture的Sliver的高度)
TabBar(),
Expanded(
child: TabBarView(),
)
],
),
);
复制代码
这样写的一个好处,内容能够被回收,性能好。
return CustomScrollView(
slivers: <Widget>[
//分组头部1,
SliverToBoxAdapter(),
//分组1
//分组2
固然咱们在SliverList的第一item里面特殊处理下,增长分组头
SliverList(),
SliverList(delegate: SliverChildBuilderDelegate((c, index) {
///item 内容
Widget item = Container();
if (index == 0) {
item = Column(
children: <Widget>[
///分组2头部
Container(),
item
],
);
}
return item;
})),
],
);
复制代码
固然栗子是举不完的,可是当你学会使用以后,终于有一天,一辈子之敌会变成你的一辈子之爱的。
若是你坚持看到这里,真爱啊,快加入小糖果吧 QQ群: 181398081。咱们这里有吃瓜群众,保安,门卫,秘书,群花,大佬,感谢他们的默默付出。若是你是喜欢分享的,请加入咱们;若是你须要分享的,也请加入咱们。
入坑Flutter的一年,除了工做时间以外,业余时间也付出不少在Flutter上面。有时候作一个东西,思路来了,可能会肝到凌晨4,5点。我倒不是提倡这种,程序猿仍是要注意本身的身体,身体才是写代码的本钱。可是咱们若是天天睡觉以前能挤出1小时来学习下,一年就是365小时=15天,相信收获仍是很大的。给本身定义一个小目标,一步一步的完成。
最后展望一下明年的Flutter。期待热更新,web性能提高,以及对C++更好的支持。