公眾號「AndroidTraveler」首發。
1. width 屬性
對於設定控制元件寬度填充父控制元件這件事情,在 Android 裡面,只需要設定 MATCH_PARENT 即可。
但是在 Flutter 裡面卻不是這樣,因為 Flutter 要具體的數值。
所以我們可以這樣考慮,假設我這個值非常大,比所有市面上的裝置寬度還要大,那麼是不是表現出來就是充滿父控制元件了。
所以這邊的做法是設定為無限,即 double.infinite
我們以一個常用場景來說明。
比如設定圖片填充螢幕寬度。
剛開始沒有設定的程式碼如下:
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'),
),
)
);
}
}
複製程式碼
效果:
可以看到沒有設定的情況下,顯示會根據圖片自身的寬高顯示。
這個時候如果設定 width 為無窮大,修改程式碼如下:
child: Image.asset('assets/images/example.jpeg', width: double.infinity,),
複製程式碼
效果
什麼情況,沒起作用?
這個時候不要慌,我們來給大家分析分析。
以後大家遇到類似問題也可以這樣分析。
我們通過給 Image 外面套上一層 Container,然後設定背景顏色來對比一下。
程式碼如下:
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,),
),
),
));
}
}
複製程式碼
效果如下:
可以看到,設定寬度之後,Image 確實是填充了寬度,只不過由於圖片本身沒有那麼寬,因此看起來就以為是沒有起作用。
那麼如何讓圖片可以填充寬度呢?
這個就涉及到圖片的填充模式了。
2. fit 屬性
點選 Image 的 fit 屬性進入原始碼可以看到如下:
/// 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;
複製程式碼
我們再點一下 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,
}
複製程式碼
相信大家看到原始碼的註釋應該很清楚每個值的意義了。
如果你還不清楚,可以點選註釋裡面對應的連結去檢視示意圖。
比如以我們這個實際應用場景填充寬度為例,那麼我們可以看到 fitWidth 應該是符合我們要求的,我們點選註釋的連結,跳轉可以看到圖片如下:
很形象的做了幾種情況的示意。我們設定了 Image 的 fit 屬性如下:
child: Image.asset('assets/images/example.jpeg', width: double.infinity, fit: BoxFit.fitWidth,),
複製程式碼
效果:
可以看到已經滿足我們的需求了。
溫馨提示:測試完之後不要忘記去掉測試的 Container 以及對應顏色哦~
3. print
我們知道在 Android 裡面,當我們 try catch 之後,我們列印異常基本會寫出類似下面程式碼:
Log.e(TAG, "exception="+e);
複製程式碼
在 Flutter 也有異常捕獲。
你可能會習慣的寫出如下程式碼:
print('exception='+e);
複製程式碼
但是切記,不要使用上面的寫法。
因為當 e 為 null 時,上面的 print 不會執行列印。
這可能會誤導你。因為你在成功的時候加上列印語句,異常捕獲也加上列印語句。但是程式就是沒有列印。你就會覺得很奇怪。
實際上當 e 為 null 時,print 語句會報錯,+ 號連線的左右不能是 null,所以不會正常列印。因此請避免上面的寫法。可以用下面的替換寫法:
//替換寫法一
print('exception=');
print(e);
//替換寫法二
print('exception='+(e ?? ''));
//替換寫法三
var printContent = e ?? '';
print('exception='+printContent);
複製程式碼
4. GestureDetector
我們知道如果要給一個 Widget 增加點選事件,最簡單的方法就是套一層 GestureDetector。
但是有時候你這樣做了,卻發現有些“隱患”,或者說,有些你意料不到的事情。
這裡用一個場景來告訴你,你平時可能沒有發現的細節。
微博裡面有點贊這個小元件,我們寫下如下程式碼:
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')
],
),
));
}
}
複製程式碼
效果如下:
假設我們要求給這個點贊元件加上點選事件,那麼我們直接給 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')
],
),
),
));
}
}
複製程式碼
點選點贊元件確實會列印 onTap,但是如果你點選了點贊圖示和數字中間的白色區域,你會發現點選事件沒有回撥,沒有列印。
這個時候有兩種解決方法:
1. 給空白元件設定 color 屬性,顏色值設定透明
對於 Container 設定的 padding 可以直接設定,對於我們這裡例子的 SizeBox 需要改為如下:
SizedBox(width: 15, child: Container(color: Colors.transparent,),),
複製程式碼
為了方便測試,這邊將寬度改為 15。
所以對於設定 GestureDetector 的 Container,如果沒有設定 color 屬性,那麼點選空白不會回撥。
2. 設定 GestureDetector 的 behavior 屬性(推薦方式)
其實如果你需要空白區域也響應點選,只需要設定一下 GestureDetector 的 behavior 屬性即可。
behavior 預設值為 HitTestBehavior.deferToChild,我們這裡將其設定為 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')
],
),
),
));
}
}
複製程式碼
這裡的點贊圖片我直接從網上獲取的,你測試可以用隨便一張圖片代替驗證。或者用兩個文字來驗證也是可以的。