公眾號(hào)「AndroidTraveler」首發(fā)。
1. width 屬性
對(duì)于設(shè)置控件寬度填充父控件這件事情,在 Android 里面嚷量,只需要設(shè)置 MATCH_PARENT 即可镇饮。
但是在 Flutter 里面卻不是這樣,因?yàn)?Flutter 要具體的數(shù)值耗绿。
所以我們可以這樣考慮苹支,假設(shè)我這個(gè)值非常大,比所有市面上的設(shè)備寬度還要大误阻,那么是不是表現(xiàn)出來就是充滿父控件了债蜜。
所以這邊的做法是設(shè)置為無限,即 double.infinite
我們以一個(gè)常用場景來說明究反。
比如設(shè)置圖片填充屏幕寬度寻定。
剛開始沒有設(shè)置的代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Flutter'),
),
body: Center(
child: Image.asset('assets/images/example.jpeg'),
),
)
);
}
}
效果:
可以看到?jīng)]有設(shè)置的情況下,顯示會(huì)根據(jù)圖片自身的寬高顯示精耐。
這個(gè)時(shí)候如果設(shè)置 width 為無窮大狼速,修改代碼如下:
child: Image.asset('assets/images/example.jpeg', width: double.infinity,),
效果
什么情況,沒起作用卦停?
這個(gè)時(shí)候不要慌向胡,我們來給大家分析分析。
以后大家遇到類似問題也可以這樣分析惊完。
我們通過給 Image 外面套上一層 Container捷枯,然后設(shè)置背景顏色來對(duì)比一下。
代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Flutter'),
),
body: Center(
child: Container(
color: Colors.blue,
//left
// child: Image.asset('assets/images/example.jpeg',),
//right
child: Image.asset('assets/images/example.jpeg', width: double.infinity,),
),
),
));
}
}
效果如下:
可以看到专执,設(shè)置寬度之后淮捆,Image 確實(shí)是填充了寬度,只不過由于圖片本身沒有那么寬本股,因此看起來就以為是沒有起作用攀痊。
那么如何讓圖片可以填充寬度呢?
這個(gè)就涉及到圖片的填充模式了拄显。
2. fit 屬性
點(diǎn)擊 Image 的 fit 屬性進(jìn)入源碼可以看到如下:
/// How to inscribe the image into the space allocated during layout.
///
/// The default varies based on the other fields. See the discussion at
/// [paintImage].
final BoxFit fit;
我們?cè)冱c(diǎn)一下 BoxFit苟径,可以看到如下:
/// How a box should be inscribed into another box.
///
/// See also [applyBoxFit], which applies the sizing semantics of these values
/// (though not the alignment semantics).
enum BoxFit {
/// Fill the target box by distorting the source's aspect ratio.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fill.png)
fill,
/// As large as possible while still containing the source entirely within the
/// target box.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_contain.png)
contain,
/// As small as possible while still covering the entire target box.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_cover.png)
cover,
/// Make sure the full width of the source is shown, regardless of
/// whether this means the source overflows the target box vertically.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fitWidth.png)
fitWidth,
/// Make sure the full height of the source is shown, regardless of
/// whether this means the source overflows the target box horizontally.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fitHeight.png)
fitHeight,
/// Align the source within the target box (by default, centering) and discard
/// any portions of the source that lie outside the box.
///
/// The source image is not resized.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_none.png)
none,
/// Align the source within the target box (by default, centering) and, if
/// necessary, scale the source down to ensure that the source fits within the
/// box.
///
/// This is the same as `contain` if that would shrink the image, otherwise it
/// is the same as `none`.
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_scaleDown.png)
scaleDown,
}
相信大家看到源碼的注釋應(yīng)該很清楚每個(gè)值的意義了。
如果你還不清楚躬审,可以點(diǎn)擊注釋里面對(duì)應(yīng)的鏈接去查看示意圖棘街。
比如以我們這個(gè)實(shí)際應(yīng)用場景填充寬度為例蟆盐,那么我們可以看到 fitWidth 應(yīng)該是符合我們要求的,我們點(diǎn)擊注釋的鏈接遭殉,跳轉(zhuǎn)可以看到圖片如下:
很形象的做了幾種情況的示意石挂。我們?cè)O(shè)置了 Image 的 fit 屬性如下:
child: Image.asset('assets/images/example.jpeg', width: double.infinity, fit: BoxFit.fitWidth,),
效果:
可以看到已經(jīng)滿足我們的需求了。
溫馨提示:測試完之后不要忘記去掉測試的 Container 以及對(duì)應(yīng)顏色哦~
3. print
我們知道在 Android 里面险污,當(dāng)我們 try catch 之后痹愚,我們打印異常基本會(huì)寫出類似下面代碼:
Log.e(TAG, "exception="+e);
在 Flutter 也有異常捕獲蛔糯。
你可能會(huì)習(xí)慣的寫出如下代碼:
print('exception='+e);
但是切記拯腮,不要使用上面的寫法。
因?yàn)楫?dāng) e 為 null 時(shí)蚁飒,上面的 print 不會(huì)執(zhí)行打印动壤。
這可能會(huì)誤導(dǎo)你。因?yàn)槟阍诔晒Φ臅r(shí)候加上打印語句淮逻,異常捕獲也加上打印語句琼懊。但是程序就是沒有打印。你就會(huì)覺得很奇怪弦蹂。
實(shí)際上當(dāng) e 為 null 時(shí),print 語句會(huì)報(bào)錯(cuò)强窖,+ 號(hào)連接的左右不能是 null凸椿,所以不會(huì)正常打印。因此請(qǐng)避免上面的寫法翅溺∧月可以用下面的替換寫法:
//替換寫法一
print('exception=');
print(e);
//替換寫法二
print('exception='+(e ?? ''));
//替換寫法三
var printContent = e ?? '';
print('exception='+printContent);
4. GestureDetector
我們知道如果要給一個(gè) Widget 增加點(diǎn)擊事件,最簡單的方法就是套一層 GestureDetector咙崎。
但是有時(shí)候你這樣做了优幸,卻發(fā)現(xiàn)有些“隱患”,或者說褪猛,有些你意料不到的事情网杆。
這里用一個(gè)場景來告訴你,你平時(shí)可能沒有發(fā)現(xiàn)的細(xì)節(jié)伊滋。
微博里面有點(diǎn)贊這個(gè)小組件碳却,我們寫下如下代碼:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Flutter'),
),
body: Row(
children: <Widget>[
Image.asset('assets/images/2.0x/like.png', width: 20, height: 20,),
SizedBox(width: 5,),
Text('30')
],
),
));
}
}
效果如下:
假設(shè)我們要求給這個(gè)點(diǎn)贊組件加上點(diǎn)擊事件,那么我們直接給 Row 套上 GestureDetector Widget笑旺。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Flutter'),
),
body: GestureDetector(
onTap: (){
print('onTap');
},
child: Row(
children: <Widget>[
Image.asset('assets/images/2.0x/like.png', width: 20, height: 20,),
SizedBox(width: 5,),
Text('30')
],
),
),
));
}
}
點(diǎn)擊點(diǎn)贊組件確實(shí)會(huì)打印 onTap昼浦,但是如果你點(diǎn)擊了點(diǎn)贊圖標(biāo)和數(shù)字中間的白色區(qū)域,你會(huì)發(fā)現(xiàn)點(diǎn)擊事件沒有回調(diào)筒主,沒有打印关噪。
這個(gè)時(shí)候有兩種解決方法:
1. 給空白組件設(shè)置 color 屬性鸟蟹,顏色值設(shè)置透明
對(duì)于 Container 設(shè)置的 padding 可以直接設(shè)置,對(duì)于我們這里例子的 SizeBox 需要改為如下:
SizedBox(width: 15, child: Container(color: Colors.transparent,),),
為了方便測試使兔,這邊將寬度改為 15建钥。
所以對(duì)于設(shè)置 GestureDetector 的 Container,如果沒有設(shè)置 color 屬性火诸,那么點(diǎn)擊空白不會(huì)回調(diào)锦针。
2. 設(shè)置 GestureDetector 的 behavior 屬性(推薦方式)
其實(shí)如果你需要空白區(qū)域也響應(yīng)點(diǎn)擊,只需要設(shè)置一下 GestureDetector 的 behavior 屬性即可置蜀。
behavior 默認(rèn)值為 HitTestBehavior.deferToChild奈搜,我們這里將其設(shè)置為 HitTestBehavior.translucent。
代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Flutter'),
),
body: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: (){
print('onTap');
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset('assets/images/2.0x/like.png', width: 20, height: 20,),
SizedBox(width: 15),
Text('30')
],
),
),
));
}
}
這里的點(diǎn)贊圖片我直接從網(wǎng)上獲取的盯荤,你測試可以用隨便一張圖片代替驗(yàn)證馋吗。或者用兩個(gè)文本來驗(yàn)證也是可以的秋秤。