daily-share-20220310

  • 美国2008年次贷危机部分事件时间表
    https://hijiangtao.github.io/2021/09/21/Too-Big-To-Fail/

  • 《向上生长》笔记——2021.09.21
    https://www.gaficat.com/posts/aaa6a1a2.html

  • 从熵的角度分析,为何说: 当你感到过得非常舒服的时候,就是你在急剧走下坡路的时候

    摘录1:任何人走上躺平的姿态都非常容易,比如刷抖音、追剧、打游戏,很快几个小时就过去了。但是背单词,十分钟就会觉得枯燥乏味了。为什么?因为前者顺应“熵增”的自然趋势,后者是给自己提供“负熵流”的,“负熵流”需要人主动吸收能量,获取知识,反抗自然规律,当然不会让人舒服。但,如果我们能和自己的人性做对抗,给到了自己“负熵流”,这难道不是一件非常酷、有成就感的事情吗?


    摘录2:我认为,学习就是一个潜的过程,当你迷茫,对自己现状不满,想要学习的时候,你就请告诉自己:这段过程注定不会很舒适,这本来就是一个很枯燥,很乏味,反人性的过程。这段过程注定不会有太多的明显的收获,也完全不会给你表现自己的机会,这本来就是一段孤单、黑暗、迷茫的过程。但是即使这样,请你相信“厚积薄发”,因为总古至今,从《易经》到《向上生长》都在告诉你,潜得越久,成就越大。
  • 当下与永恒
    https://wiki-power.com/blog/2021/09/19/%E5%BD%93%E4%B8%8B%E4%B8%8E%E6%B0%B8%E6%81%92

    摘录1:「如果每一天都能如此快乐就好了」。但仔细一想,如果每天都一样地快乐着,那还能称之为快乐吗?先前读过一段话,「快乐是生活的点缀,无聊和痛苦才是生活的本质」。

  • 回归本源一一位运算及其应用
    https://www.geekzl.com/bit-operation-and-its-apps-2014-noi-pater.html

  • 称假币问题的变形:无假币与“天平机”
    http://www.matrix67.com/blog/archives/6970
    有点长,有点烧脑

分享-20220306

常用多媒体软件的开源或免费替代
https://www.imaegoo.com/2021/media-soft/

读陌生领域文献,我劝你别读正文(做科研的人可以看一下)
https://kaopubear.top/blog/2021-09-26-dont-read-full-text/

公司融资知识(老板们看看)
https://blog.mikeoperfect.com/posts/32098/
文章比较短,打算入股别人公司的人也可以看看。看看最后一句话,回购,稀释,退出等。

智能合约检测工具
https://www.frank.hk/blog/slither-solidity-scanner/
总所周知,智能合约一旦发布,就无法修改;为此,安全性就显得尤为重要,这个工具提供了一些检测功能。

初来新加坡,一份简单的个人金融事务指南
https://www.zackwu.com/posts/2021-09-22-personal-finance-in-singapore-for-expats/

springboot-2.x-log-system

springboot日志系统的理解

日志归一系统

写代码的时候突然对log感兴趣,想到了springboot之前了解的时候是依赖于sl4j实现的统一api,在编译的时候在决定用哪一个日志框架。但是翻了一下网上的文章。得出了Spring Boot 可以自动的适配日志框架,而且底层使用 SLF4 + LogBack的结论。
20220303131251

从图中可以看出几点

  1. 所有其他日志系统例如,jul ,log4j ,logback 都是实现了和sl4j的桥接。
  2. 其中只有logback实现了sl4j,这个也是得出默认springboot支持logback的原因。

在springboot中,各个日志框架究竟是如何和平相处,并且相安无事的

我们写代码,免不了使用第三方的库,假设第三方库没有实现sl4j的api,那么这个日志岂不是不受到springboot的统一管理了???不是这样的,就类似上面的spring-logging 这个库,一些第三方的流行的库,会有一些工具包来替换接管这些第三方系统的日志。
大致原理,如下,下面是一个sl4j官方的一个图。
20220303132843

如何替换默认的logback的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>    
<groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>    
<exclusions>           
<exclusion>            
<artifactId>spring-boot-starter-logging</artifactId>            
<groupId>org.springframework.boot</groupId>        
</exclusion>  
</exclusions>
</dependency>

<dependency>    
<groupId>org.springframework.boot</groupId>    
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

fix-macos-big-sur-crash

问题描述

今天本来是用vscode写一个spring的小程序,编译的时候一直提示没有compile provider,百思不得其解。初步怀疑是maven和vscode的配置有关系。但是多番尝试依然无果。为了不浪费时间,还是决定intelj来开发,好久没有打开过intelj了,谁知道一打开就crash….今天真的是见了鬼。

解决思路

1. 一番观察进程之后,排除了我下载的破解插件的原因。
2. 软件兼容性方面,电脑自从上次没有用idea 大概没有安装太多第三方软件,初步排除
3. 查看是否是因为系统资源不够等原因的时候,查看到mac os 系统版本,最近曾经升级过....

茅塞顿开!!!

解决方案

参考intelj 官方的答案:https://www.jetbrains.com/help/idea/directories-used-by-the-ide-to-store-settings-caches-plugins-and-logs.html#config-directory

注意mac上如果直接删除参考如下

1
ls -al ~/Library/Application\ Support/JetBrains   

先查看自己的版本,然后决定是否备份一下配置文件。之后执行删除 JetBrains 下面的相关所有文件即可

chrome浏览器安装Metamask

MetaMask 为何物

最初区块链不是很火,生态还不是很完善的时候,自己的账户(也就是一对公钥和私钥)要和区块链交互,可能就需要程序员用程序来实现。这对于普通人来说是不现实的。于是各种钱包诞生了。所谓的钱包其实也就是管理区块链账户(一对公私钥)的。MetaMask其实也可以理解是一个钱包,只不过呢,这个钱包是大多数的时候被以插件的形式安装在chrome的浏览器上。(说明:chrome也有移动版,这个时候和其他钱包差别不大,今天重点说的是浏览器端metamask)。

要想和区块链交互,例如玩游戏,做交易,都需要钱包来代理我们的交易,所以类似metamask,trust wallet ,imToken这种钱包是非常重要的。

MetaMask的安装

打开chrome浏览器,输入网址:https://metamask.io/(注意,切记对比别跑到钓鱼网站了)。点击download

随后出现如下,安装到chrome中
20220221103028

随后跳转到了https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn ,这个地方应该需要科学上网才行。

MetaMask的使用

  • MetaMask安装完成之后,可以导入或者生成助记词的方式创建一个钱包。注意创建的助记词一定用心保存。否则,一旦丢失, 账户资产全部归零。
  • 类似MetaMask,imtoken这种钱包,一定注意甄别是否是正版。网上有很对李鬼app会盗取你的私钥或者助记词。一旦被盗用,您的财产就没了。

区块链游戏体验之从游戏到代码

环境准备

由于区块链游戏需要连接钱包,所以需要配置浏览器的MetaMask,并创建一个钱包。教程:https://www.memestarter.top/2022/02/21/chrome浏览器安装Metamask . 在说后面的内容之前先说两个概念。区块链和区块链网络。
区块链。只要具有多节点数据同步出块机制的几乎都可以认为它是一个区块链。也就是一个永不停机的数据库。你也可以理解为一个银行。目前已知比较有名的区块链网络有以太坊(eth),币安连(bsc),比特币(btc)等。
区块链网络。用来标记一个区块链网络的一组概念。拿以太坊来说,他需要有一个chainID和rpcPoint来标记这个网络,这两个参数主要是供钱包在发送交易的时候,知道该和谁通信。

有了这个概念之后。我们这次的目的是体验游戏,当然不可能在真实的环境下玩了,真实环境拿以太坊来说,交易一次几十美元,也就是几百人民币(具体多少要看交易的种类,gas等因素去考虑)。

添加以太坊测试网络

打开https://chainlist.org/ ,这个网址汇集了几乎流行的所有区块链的所有正式环境和测试环境的配置。如下所示,选择Rinkeby网络
20220221110337

点击connect之后,连接MetaMask,之后如下

20220221110423

然后点击Add to metamask 即可完成添加。
如下图,可以在MetaMask中看到这个网络。
20220221110541

领取测试网络的测试代币

到水龙头网站领取:https://faucet.rinkeby.io/ ,如果领取有问题可以留言,我这有点

体验游戏

找到一个比较简单,而且带源码的游戏

  1. 游戏网址 :https://epic-game-buildspace-a2c4ixjyk-zlayine.vercel.app/
  2. 博客网址:https://betterprogramming.pub/create-a-blockchain-game-with-solidity-web3-and-vue-js-c75eed4b49a6
  3. 代码网址:https://github.com/zlayine/epic-game-buildspace
  • 连接
    20220221110822

  • 切换网络
    20220221110733

  • 选择角色
    20220221110911

  • 领取角色
    20220221111146
    然后点击下方的confirm确定

  • 等待MetaMask把交易发送到区块链,等待区块链确认同步
    20220221111243

  • mint之后自己的角色如下,并给我分配了大boss elon。。。。
    20220221111615

玩游戏

点击攻击elon,图片晃动,这里本来期望,会弹出MetaMask,让把这次攻击的结果提交区块链,或者区块链随机决定胜负的。看来这个游戏还不够完善。

20220221111729

无论如何,大致的区块链游戏也就这样,最简单的。但是也可以通过这个流程大致体会一下,目前区块链游戏发展阶段。正所谓:不完善的地方机会才多。目前区块链游戏大抵如此。更多的是偏向金融属性。例如,我们一开始游戏的时候,就需要mint一个角色,这个角色其实就是一个nft,非同质化代币。在一些游戏中,这些角色是可以买卖的。还有一些游戏中,这些nft,例如装备,角色,宝石,等是可以跨越游戏使用和转移的。这也是和传统游戏区别比较大的地方。

结束语

体验到此结束,只能用一句话形容目前游戏的现状。现实很骨感,理想很丰满。相信未来的人,前仆后继;

分享20220212

flutter中布局类widget组件

widget布局组件原理

flutter中布局从布局树的角度来说,大致分为三类:完全没有子节点,有且只有一个子节点的widget ,可以有多个子节点的widget。只有后两者才能成为布局widget。下班是这三类的说明和举例。

widget名称 说明 举例
LeafRenderObjectWidget 非容器类组件通常继承自这个 Widget树的叶子节点,用于没有子节点的widget,通常基础组件都属于这一类,如Image。
SingleChildRenderObjectWidget 只能容纳单个组件的widget的基类 只能有一个child Widget,如:ConstrainedBox、DecoratedBox等 MultiChildRenderObjectWidget

所有的widget都继承自 RenderObjectWidget,这个类中定义了创建、更新RenderObject的方法,子类必须实现他们,它是最终布局、渲染UI界面的对象的方法,其布局算法都是通过对应的RenderObject对象来实现的。

widget布局组件的两个形式

Flutter 中的整体渲染流程是 Widget -> Element -> RenderObejct -> Layer 这样的过程,而 「Flutter 里的布局和绘制逻辑都在 RenderObejct」,而其中的布局,就是这里要说的。

Flutter 中有两种布局模型:

  • 基于 RenderBox 的盒模型布局。
  • 基于 Sliver ( RenderSliver ) 按需加载列表布局。
    两种布局方式在细节上略有差异,但大体流程相同,布局流程如下:
  1. 上层组件向下层组件传递约束(constraints)条件。
  2. 下层组件确定自己的大小,然后告诉上层组件。注意下层组件的大小必须符合父组件的约束。
  3. 上层组件确定下层组件相对于自身的偏移和确定自身的大小(大多数情况下会根据子组件的大小来确定自身的大小)。

盒模型布局组件

盒模型布局组件有两个特点:

  1. 组件对应的渲染对象都继承自 RenderBox 类。
  2. 在布局过程中父级传递给子级的Constraints(约束) BoxConstraints 描述。

ConstrainedBox用于对子组件添加额外的约束。被ConstrainedBox约束的组件,子组件的宽高以ConstrainedBox中设置的为准
例如以下代码

1
2
3
4
5
6
7
ConstrainedBox(
constraints:
const BoxConstraints(maxWidth: 300, minHeight: 40),
child: Container(
height: 1,
decoration: const BoxDecoration(color: Colors.red),
)),

20220211234015

container的高度设置为1实际绘制的高度是40;设置height为100 ,绘制高度也是100

SizedBox用于给子元素指定固定的宽高。

Row和Column

这两个组件比较简单,可以类比安卓开发的时候有一个线性布局。
构造方法:

1
2
3
4
5
6
7
8
9
10
Row({
...
TextDirection textDirection,
MainAxisSize mainAxisSize = MainAxisSize.max,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
VerticalDirection verticalDirection = VerticalDirection.down,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
List<Widget> children = const <Widget>[],
})

  • TextDirection 组件排列方向
  • mainAxisSize 子元素的尺寸。mainAxisSize.max 尽可能的暂用空间。mainAxisSize.min尽可能的小的去占用。
  • mainAxisAlignment :水平空间的对齐方式。MainAxisAlignment.start表示沿textDirection的初始方向对齐,如textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表示左对齐,textDirection取值为TextDirection.rtl时表示从右对齐。而MainAxisAlignment.end和MainAxisAlignment.start正好相反;MainAxisAlignment.center表示居中对齐。读者可以这么理解:textDirection是mainAxisAlignment的参考系。
  • verticalDirection:表示Row纵轴(垂直)的对齐方向,默认是VerticalDirection.down,表示从上到下。
  • crossAxisAlignment:表示子组件在纵轴方向的对齐方式,Row的高度等于子组件中最高的子元素高度,它的取值和MainAxisAlignment一样(包含start、end、 center三个值),不同的是crossAxisAlignment的参考系是verticalDirection,即verticalDirection值为VerticalDirection.down时crossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.end和crossAxisAlignment.start正好相反;

柔性布局Flex

柔性布局和Expand结合可以把元素按照比例分割布局。

流式布局

超出屏幕显示范围会自动折行的布局称为流式布局。Flutter中通过Wrap和Flow来支持流式布局
wrap组件重要的属性

  • spacing:主轴方向子widget的间距
  • runSpacing:次轴方向的间距
  • runAlignment:次轴方向的对齐方式

绝对布局Stack和Positioned

绝对布局、Android 中的 Frame 布局是相似的。子组件可以根据距父容器四个角的位置来确定自身的位置。Stack允许子组件堆叠,而Positioned用于根据Stack的四个角来确定子组件的位置。

stack重要属性

  • alignment:Alignment.center , //指定未定位或部分定位widget的对齐方式;这个决定原点
  • fit: StackFit.expand, //未定位widget占满Stack整个空间

Positioned构造函数

1
2
3
4
5
6
7
8
9
10
11
const Positioned({
Key? key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
required Widget child,
})

left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离。width和height用于指定需要定位元素的宽度和高度。

容器类组件

Padding
可以给其子节点添加填充(留白),和边距效果类似。
EdgeInsets
EdgeInsets提供的api

  • fromLTRB(double left, double top, double right, double bottom):分别指定四个方向的填充。
  • all(double value) : 所有方向均使用相同数值的填充。
  • only({left, top, right ,bottom }):可以设置具体某个方向的填充(可以同时指定多个方向)。
  • symmetric({ vertical, horizontal }):用于设置对称方向的填充,vertical指top和bottom,horizontal指left和right。

DecoratedBox

可以在其子组件绘制前(或后)绘制一些装饰(Decoration),如背景、边框、渐变等。

Container

Container是一个组合类容器,它本身不对应具体的RenderObject,它是DecoratedBox、ConstrainedBox、Transform、Padding、Align等组件组合的一个多功能容器,所以我们只需通过一个Container组件可以实现同时需要装饰、变换、限制的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Container({
this.alignment,
this.padding, //容器内补白,属于decoration的装饰范围
Color color, // 背景色
Decoration decoration, // 背景装饰
Decoration foregroundDecoration, //前景装饰
double width,//容器的宽度
double height, //容器的高度
BoxConstraints constraints, //容器大小的限制条件
this.margin,//容器外补白,不属于decoration的装饰范围
this.transform, //变换
this.child,
...
})

Sliver(薄片布局)

通常可滚动组件子组件比较多,如果一次性渲染和加载所有组件,需要消耗比较大的系统资源,严重影响系统性能。并且随着手势滑动的时候,需要不停的计算。Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。

通过这个机制,只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView。

Flutter 中的可滚动主要由三个角色组成:Scrollable、Viewport 和 Sliver:

  1. Scrollable :用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport 。
  2. Viewport:显示的视窗,即列表的可视区域;
  3. Sliver:视窗里显示的元素。

这几个的关系大致如下
20220211162027
说明:

  1. Scrollable 、 Viewport 和 Sliver 所占用的空间都是白色区域,也就是说,这部分是重合的。
  2. 从上到下的层级关系是scrollview ,viewPort ,silver
  3. 按需加载需要最下层的silver来实现
  4. 图中的cacheExtent区域是为了让滑动更丝滑而存在的,这部分不显示在可见区域,只是在即将出现在可见区域的提前绘制。默认值是250大小。可以被改变

绘制过程
具体布局过程:

  1. Scrollable 监听到用户滑动行为后,根据最新的滑动偏移构建 Viewport 。
  2. Viewport 将当前视口信息和配置信息通过 SliverConstraints 传递给 Sliver。
  3. Sliver 中对子组件(RenderBox)按需进行构建和布局,然后确认自身的位置、绘制等信息,保存在 geometry 中(一个 SliverGeometry 类型的对象)。

    SingleChildScrollView

    SingleChildScrollView类似安卓的ScrollView ,只有一个子组件。需要注意的是SingleChildScrollView不支持silver的按需加载。如果有比较多的待滑动内容的时候,不要使用这个组件。

滑动组件

ListView

ListView是一个列表展示组件。它的构造方法可以传入一组widget

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(10),
children: const [
Text("data1"),
Text("data2"),
Text("data3"),
Text("data4"),
Text("data5"),
Text("data6"),
Text("data7"),
Text("data8"),
Text("data9"),
Text("data10"),
])
]),

通常如果列表数量比较少,可以这么样做。如果列表数量比较多,这样就会消耗性能。

20220211170603

ListView.builder适合批量创建列表元素

1
2
3
4
5
6
7
Expanded(
child: ListView.builder(
itemCount: 100,
itemExtent: 60,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("ListViwe $index"));
}))

20220211171356

ListView.separated

ListView.separated可以在生成的列表项之间添加一个分割组件,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割组件生成器。使用场景,例如需要在每一个item之间添加分隔条的时候。

ListVIew的性能

  1. 如果列表数据多,尽量使用listVIew.build或者listVIew.separated来构建列表。
  2. 尽量给列表指定 itemExtent 或 prototypeItem ,这样会减少引擎的计算时间

GridVIew

GridView 有着非常有用的应用场景。如下
20220211174838

GridView构造方法

1
2
3
4
5
6
7
8
9
10
11
12
GridView({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required this.gridDelegate,
double cacheExtent,
List<Widget> children = const <Widget>[],
})

这么多参数中,重点需要关注的是gridDelegate这个参数。它其实是GridView组件如何控制排列子元素的一个委托
他的的类型是SliverGridDelegate。fultter中主要由两个实现类:

  1. SliverGridDelegateWithFixedCrossAxisCount:用于固定列数的场景;
  2. SliverGridDelegateWithMaxCrossAxisExtent:用于子元素有最大宽度限制的场景;

SliverGridDelegateWithFixedCrossAxisCount

主要用于横轴方向有固定元素的场景,构造方法

1
2
3
4
5
6
SliverGridDelegateWithFixedCrossAxisCount({
@required this.crossAxisCount,
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.childAspectRatio = 1.0,
})

参数解释

  • crossAxisCount:列数,即一行有几个子元素;
  • mainAxisSpacing:主轴方向上的空隙间距;这里主轴是x轴
  • crossAxisSpacing:次轴方向上的空隙间距;这里次轴是y轴
  • childAspectRatio:子元素的宽高比例。

下图说的比较清楚
20220211175521

其他

GridView使用方法主要有以下几种

  • GridView默认构造函数可以类比于ListView默认构造函数,适用于有限个数子元素的场景,因为GridView组件会一次性全部渲染children中的子元素组件;
  • GridView.builder构造函数可以类比于ListView.builder构造函数,适用于长列表的场景,因为GridView组件会根据子元素是否出现在屏幕内而动态创建销毁,减少内存消耗,更高效渲染;
  • GridView.count构造函数是GrdiView使用SliverGridDelegateWithFixedCrossAxisCount的简写(语法糖),效果完全一致;
  • GridView.extent构造函数式GridView使用SliverGridDelegateWithMaxCrossAxisExtent的简写(语法糖),效果完全一致。

flutter组件widget系列-基础组件

文本组件

文本组件基本属性

Text是最基本的文本组件,它的构造方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const Text(
String this.data, {
Key? key,
this.style,
this.strutStyle,
this.textAlign,
this.textDirection,
this.locale,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines,
this.semanticsLabel,
this.textWidthBasis,
this.textHeightBehavior,
})

可以看出,有几个属性可以直接设置,例如:textAlign,textDirection,locale,overflow等。下边是一个例子

1
2
3
4
5
6
7
8
9
const Text(
"You have pushed many timesYou have pushed many timesYou have pushed many timesYou have pushed many times:",
textAlign: TextAlign.left, //对其
overflow: TextOverflow
.ellipsis, //截取部分展示:clip:直接截取 fade:渐隐 ellipsis:省略号,省略的部分是以单词为单位,而不是字母
textScaleFactor: 1, //设置字体大小的一种快捷方式
maxLines: 2, //最多允许几行
textDirection: TextDirection.ltr
)

textStyle主要核心是设置文字的属性,粒度更加细

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const Text(
"You have pushed many timesYou have pushed many timesYou have pushed many timesYou have pushed many times:",
textAlign: TextAlign.left, //对其
overflow: TextOverflow
.ellipsis, //截取部分展示:clip:直接截取 fade:渐隐 ellipsis:省略号,省略的部分是以单词为单位,而不是字母
textScaleFactor: 1, //设置字体大小的一种快捷方式
maxLines: 2, //最多允许几行
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.blue,
fontSize: 28.0,
fontWeight: FontWeight
.bold, //字体粗细 一般使用的属性:FontWeight normal(默认) 、FontWeight bold(粗体)
letterSpacing: -1, //字母间距,默认0,负数间距越小,正数 间距越大
wordSpacing:
1, //单词 间距,默认0,负数间距越小,正数 间距越大,注意和letterSpacing的区别,比如hello,h、e、l、l、o各是一个字母,hello是一个单词
height: 2, //会乘以fontSize做为行高
//阴影shadows://
fontFamily: "Courier",
decorationColor: Colors.red, //划线颜色
decoration: TextDecoration.underline, //文字划线:下划线、上划线、中划线
decorationStyle: TextDecorationStyle.dotted),
),

运行效果
20220210181013

TextSpan

如果要实现同一段文字的不同部分有不同的样式,就要用到TextSpan了

看一下它的定义

1
2
3
4
5
6
7
const TextSpan({
TextStyle style,
Sting text,
List<TextSpan> children,
GestureRecognizer recognizer,
});

在使用的时候,可以分别使用Text.rice和RichText两种方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
children: <Widget>[
const Text(
"You have many times:",
textAlign: TextAlign.left, //对其
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
const Text.rich(
TextSpan(text: "hello Text.rich ", children: [
TextSpan(
text: "red text span",
style: TextStyle(fontSize: 16.0, color: Colors.red),
),
TextSpan(
text: "red text span",
style: TextStyle(fontSize: 16.0, color: Colors.green),
),
]),
),
RichText(
text: const TextSpan(
text: "hello RichText TextSpan ",
style: TextStyle(fontSize: 16.0, color: Colors.black),
children: [
TextSpan(
text: "red text span",
style: TextStyle(fontSize: 16.0, color: Colors.red),
),
TextSpan(
text: "yello text span",
style: TextStyle(fontSize: 16.0, color: Colors.yellow),
)
]),
),
],
),

运行效果如下

20220210184244

按钮

Material 组件库中提供了多种按钮组件如ElevatedButton、TextButton、OutlineButton等,它们都是直接或间接对RawMaterialButton组件的包装定制,所以他们大多数属性都和RawMaterialButton一样。在介绍各个按钮时我们先介绍其默认外观,而按钮的外观大都可以通过属性来自定义,我们在后面统一介绍这些属性。另外,所有 Material 库中的按钮都有如下相同点:

按下时都会有“水波动画”(又称“涟漪动画”,就是点击时按钮上会出现水波扩散的动画)。
有一个onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。

  • 按下时都会有“水波动画”(又称“涟漪动画”,就是点击时按钮上会出现水波扩散的动画)。
  • 有一个onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。

各种按钮

  • ElevatedButton
    即”漂浮”按钮,它默认带有阴影和灰色背景。按下后,阴影会变大。

  • TextButton即文本按钮,默认背景透明并不带阴影。按下后,会有背景色。

  • OutlineButton默认有一个边框,不带阴影且背景透明。按下后,边框颜色会变亮、同时出现背景和阴影(较弱)。

  • IconButton是一个可点击的Icon,不包括文字,默认没有背景,点击后会出现背景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
children: <Widget>[
const Text(
"You have many times:",
textAlign: TextAlign.left, //对其
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
ElevatedButton(
onPressed: () {}, child: const Text("ElevatedButton")),
TextButton(onPressed: () {}, child: const Text("TextButton")),
OutlinedButton(
onPressed: () {}, child: const Text("OutlinedButton")),
IconButton(onPressed: () {}, icon: const Icon(Icons.abc))
]),

效果如下
20220210185953

带图标的按钮

ElevatedButton、TextButton、OutlineButton都有一个icon 构造函数,通过它可以轻松创建带图标的按钮。

1
2
3
4
5
6
TextButton.icon(
icon: const Icon(Icons.add_a_photo),
label: const Text(""),
onPressed: () {},
),
]),

如下
20220210190540

Image图像显示组件

Image在显示图片时定义了一系列参数,通过这些参数我们可以控制图片的显示外观、大小、混合效果等。 Image 的主要参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const Image({
Key? key,
required this.image,
this.frameBuilder,
this.loadingBuilder,
this.errorBuilder,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width,
this.height,
this.color,//图片的混合色值
this.opacity,//透明度
this.colorBlendMode,//混合模式
this.fit,//缩放模式
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.isAntiAlias = false,
this.filterQuality = FilterQuality.low,
})
  • width、height
    用于设置图片的宽、高,当不指定宽高时,图片会根据当前父容器的限制,尽可能的显示其原始大小,如果只设置width、height的其中一个,那么另一个属性默认会按比例缩放,但可以通过下面介绍的fit属性来指定适应规则。
  • fit
    该属性用于在图片的显示空间和图片本身大小不同时指定图片的适应模式。适应模式是在BoxFit中定义,它是一个枚举类型,有如下值:
  1. fill:会拉伸填充满显示空间,图片本身长宽比会发生变化,图片会变形。
  2. cover:会按图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间部分会被剪裁。
  3. contain:这是图片的默认适应规则,图片会在保证图片本身长宽比不变的情况下缩放以适应当前显示空间,图片不会变形。
  4. fitWidth:图片的宽度会缩放到显示空间的宽度,高度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁。
  5. fitHeight:图片的高度会缩放到显示空间的高度,宽度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁。
  6. none:图片没有适应策略,会在显示空间内显示图片,如果图片比显示空间大,则显示空间只会显示图片中间部分。

图片数据源

在Image的构造函数中有一个this.image ,这个就是一个 ImageProvider 的实现。

加载assets下面的图片

在pubspec.yml中添加图片

1
2
assets:
- images/ic_launcher.png

在代码中添加如下代码

1
const Image(image: AssetImage('images/ic_launcher.png')),

效果如下
20220210192802

从网络上加载图片

 const Image(
                  image: NetworkImage(
                      "https://docs.flutter.dev/assets/images/dash/dash-fainting.gif")),

效果如下,gif图也很好的显示
20220210193559

flutter开发之Dart语言和java语言区别

为何要说java语法

当然了,编程语言都是互通的;如果会java或者其他语法学起来会相对轻松。由于之前对java语法比较熟悉。这里就和java做一个对比

java语法和dart语法的对比和区别

  1. 主函数

    • 没有public static
    • 命令参数List args
      函数体类似
      1
      2
      void main() {
      }
  2. 没有public, private, protected关键字

  3. 创建对象,new可选

  4. class中属性默认public,若声明私有,只需在属性名前加_

  5. getter/setter方法
    java中是有函数定义getter和setter的,dart通过关键字get set 来声明,如下

    1
    2
    //返回值类型/get/外部可访问属性/方法体
    int get speed => _speed
  6. 变量必须初始化,未初始化的变量值均为null

  7. 字符串可用单引号或者双引号,这点和JavaScript又有点类似

  8. dart中没有interface关键字,每个类都可以做接口

  9. 函数无需声明可能抛出的异常类型,java中需要用关键字throws声明

  10. 捕获异常的时候dart有一个on关键字

    1
    2
    3
    4
    5
    6
    7
    8
    try {
    // ···
    } on Exception catch (e) {
    print('Exception details:\n $e');
    } catch (e, s) {
    print('Exception details:\n $e');
    print('Stack trace:\n $s');
    }
  11. dart语言是前面加一个下划线来实现变量或者方法为私有属性或者私有方法。

  12. dart所独有的特征:mixins

    mixins(混入)的定义是

    Mixins are a way of reusing a class’s code in multiple class hierarchies.
    从目的看Mixins要解决的就是代码复用的问题
    维基百科的解释
    在面向对象的语言中,mixins类是一个可以把自己的方法提供给其他类使用,但却不需要成为其他类的父类。

    1
    2
    3
    4
    5
    **注意**
    - mixins类只能继承自object
    - mixins类不能有构造函数
    - 一个类可以mixins多个mixins类
    - 可以mixins多个类,不破坏Flutter的单继承
  13. 变量的定义

    1. var用来定义类型不变的变量。
      1
      var x = 10;//x是整数,之后x就不能赋值其他类型,这个和java一样
    2. dynamic和object
      DART语言中 所有对象包括Function和null 都是object的子类型。这两个声明的变量,在后边可以改变类型。
      二者的区别在于,dynamic声明的变量在编写代码的时候,可以动态的去写,编译器会默认你有这个变量或者方法,而不去报错。基于这个特点,就需要小心使用。如下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      dynamic a;
      Object b = "";
      main() {
      a = "";
      printLengths();
      }

      printLengths() {
      // 正常
      print(a.length);
      // 报错 The getter 'length' is not defined for the class 'Object'
      print(b.length);
      }

      例子引用:https://book.flutterchina.club/chapter1/dart.html#_1-4-1-%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E

  14. final 和const 修饰的变量
    两个都可以修饰变量,而且修饰的变量在运行时不可以改变。区别在于final修饰的值在定义变量的时候已经知道了变量的值。但是,const修饰的值在编译器运行的时候是可以计算的。例如

    1
    2
    3
    4
    const bar = 1000000;       // 定义常量值
    // bar =13; // 出现异常,const修饰的变量不能调用setter方法,即:不能设值,只能在声明处设值
    const atm = 1.01325 * bar; // 值的表达式中的变量必须是编译时常量(bar);

  15. dart中的函数

    1. 包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面。例如
      1
      2
      3
      String say(String from, String msg, [String device]) {
      ///
      }
    2. 可选的命名参数
      函数定义:
      1
      2
      3
      void testFunction({string params1, bool params2}) {
      // ...
      }
      函数使用,必须指定变量名称
      1
      testFunction(params1: "1111", params2: true);
  • Copyrights © 2020-2022 zzj
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信