
老孟導讀:Flutter 1.20 更新了 Slider、RangeSlider、日期選擇器組件、時間選擇器組件的樣式,新增了交換組件:InteractiveViewer,下面詳細介紹其用法,
滑塊
Flutter 1.20 版本將 Slider 和 RangeSlider 小部件更新為最新的 Material 準則,新的滑塊在設計時考慮到了更好的可訪問性:軌道更高,滑塊帶有陰影,并且值指示器具有新的形狀和改進的文本縮放支持,
Slider
基礎用法:
class SliderDemo extends StatefulWidget {
@override
_SliderDemoState createState() => _SliderDemoState();
}
class _SliderDemoState extends State<SliderDemo> {
double _sliderValue = https://www.cnblogs.com/mengqd/p/0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('值:$_sliderValue'),
Slider(
value: _sliderValue,
onChanged: (v){
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
],
),
),
);
}
}
- value:當前值,
- onChanged:滑塊值改變時回呼,
看看 Flutter 1.20 版本以前的樣式(我的珍藏):
明顯的感覺就是滑塊軌道變粗了,滑塊變的更有立體感(加了陰影)了,
Slider 默認滑動范圍是 0-1,修改為 1-100:
Slider(
value: _sliderValue,
min: 1,
max: 100,
onChanged: (v){
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
設定滑塊的滑動為 離散的,即滑動值為 0、25 、50、75 100:
Slider(
value: _sliderValue,
min: 0,
max: 100,
divisions: 4,
onChanged: (v){
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
設定標簽,滑動程序中在其上方顯示:
Slider(
value: _sliderValue,
label: '$_sliderValue',
min: 0,
max: 100,
divisions: 4,
onChanged: (v){
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
看看 Flutter 1.20 版本以前的樣式(依然是我的珍藏):
個人感覺以前的更好看,
下面是官方給的 Slider 結構圖:
- 1 :軌道(Track),1 和 4 是有區別的,1 指的是底部整個軌道,軌道顯示了可供用戶選擇的范圍,對于從左到右(LTR)的語言,最小值出現在軌道的最左端,而最大值出現在最右端,對于從右到左(RTL)的語言,此方向是相反的,
- 2:滑塊(Thumb),位置指示器,可以沿著軌道移動,顯示其位置的選定值,
- 3:標簽(label),顯示與滑塊的位置相對應的特定數字值,
- 4:刻度指示器(Tick mark),表示用戶可以將滑塊移動到的預定值,
自定義滑塊 激活的顏色 和 未激活的顏色:
Slider(
activeColor: Colors.red,
inactiveColor: Colors.blue,
value: _sliderValue,
label: '$_sliderValue',
min: 0,
max: 100,
divisions: 4,
onChanged: (v){
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
這個自定義比較籠統,下面來一個更細致的自定義:
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Color(0xff404080),
thumbColor: Colors.blue,
overlayColor: Colors.green,
valueIndicatorColor: Colors.purpleAccent),
child: Slider(
value: _sliderValue,
label: '$_sliderValue',
min: 0,
max: 100,
divisions: 4,
onChanged: (v) {
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
),
)
這個基本可以完全自定義樣式了,
如何在 Flutter 1.20 版本使用以前的標簽樣式呢?
SliderTheme(
data: SliderTheme.of(context).copyWith(
valueIndicatorShape: PaddleSliderValueIndicatorShape(),
),
child: Slider(
value: _sliderValue,
label: '$_sliderValue',
min: 0,
max: 100,
divisions: 4,
onChanged: (v) {
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
),
)
RectangularSliderValueIndicatorShape 表示矩形樣式:
RangeSlider
RangeSlider 和 Slider 幾乎一樣,RangeSlider 是范圍滑塊,想要選擇一段值,可以使用 RangeSlider,
RangeValues _rangeValues = RangeValues(0, 25);
RangeSlider(
values: _rangeValues,
labels: RangeLabels('${_rangeValues.start}','${_rangeValues.end}'),
min: 0,
max: 100,
divisions: 4,
onChanged: (v) {
setState(() {
_rangeValues = v;
});
},
),
滑塊狀態
ios風格的 Slider
ios風格的 Slider,使用 CupertinoSlider:
double _sliderValue = https://www.cnblogs.com/mengqd/p/0;
CupertinoSlider(
value: _sliderValue,
onChanged: (v) {
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
當然也可以根據平臺顯示不同風格的Slider,ios平臺顯示CupertinoSlider效果,其他平臺顯示Material風格,用法如下:
Slider.adaptive(
value: _sliderValue,
onChanged: (v) {
setState(() {
_sliderValue = https://www.cnblogs.com/mengqd/p/v;
});
},
)
Material風格日期選擇器
Flutter 1.20 版本更新了 日期 類組件的樣式,加入了新的緊湊設計以及對日期范圍的支持,
showDatePicker
結構圖
- 標題
- 選中的日期
- 切換到輸入模式
- 年選擇選單
- 月份分頁
- 當前時間
- 選中日期
輸入模式 結構圖:
- 標題
- 選中日期
- 切換 日歷模式
- 輸入框
基礎用法
點擊按鈕彈出日期組件:
RaisedButton(
child: Text('彈出日期組件'),
onPressed: () async {
await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
);
- initialDate:初始化時間,通常情況下設定為當前時間,
- firstDate:表示開始時間,不能選擇此時間前面的時間,
- lastDate:表示結束時間,不能選擇此時間之后的時間,
設定日期選擇器對話框的模式:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
initialEntryMode: DatePickerEntryMode.input,
);
直接顯示 輸入模式,默認是日歷模式,
設定日歷日期選擇器的初始顯示,包含 day 和 year:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
initialDatePickerMode: DatePickerMode.year,
);
和以前的版本對比:
設定頂部標題、取消按鈕、確定按鈕 文案:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
helpText: '選則日期',
cancelText: '取消',
confirmText: '確定',
);
修改 輸入模式 下文案:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
errorFormatText: '錯誤的日期格式',
errorInvalidText: '日期格式非法',
fieldHintText: '月/日/年',
fieldLabelText: '填寫日期',
);
設定可選日期范圍
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
selectableDayPredicate: (date) {
return date.difference(DateTime.now()).inMilliseconds < 0;
},
);
今天以后的日期全部為灰色,不可選狀態,
設定深色主題
設定深色主題使 builder ,其用于包裝對話框視窗小部件以添加繼承的視窗小部件,例如Theme,設定深色主題如下:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
builder: (context,child){
return Theme(
data: ThemeData.dark(),
child: child,
);
}
);
獲取選中的日期
showDatePicker 方法是 Future 方法,點擊日期選擇控制元件的確定按鈕后,回傳選擇的日期,
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
);
print('$result');
result 為選擇的日期,
CalendarDatePicker
日期組件直接顯示在頁面上,而不是彈出顯示:
CalendarDatePicker(
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
onDateChanged: (d) {
print('$d');
},
)
其引數和 showDatePicker 一樣,
范圍日期
選擇范圍日期使用 showDateRangePicker:
RaisedButton(
child: Text('范圍日期'),
onPressed: () async {
var date = showDateRangePicker(context: context, firstDate: DateTime(2010), lastDate: DateTime(2025));
},
),
其引數和 showDatePicker 一樣,
范圍日期結構圖:
- 標題
- 選定的日期范圍
- 切換到輸入模式
- 月和年標簽
- 當前時間
- 開始時間
- 選中時間范圍
- 結束時間
國際化
國際化都是一個套路,下面以 showDatePicker 為例:
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在頂級組件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('zh'),
const Locale('en'),
],
...
彈出日期組件:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
);
此時將系統語音調整為中文:
此組件只支持中文,不管系統設定語言:
var result = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2025),
locale: Locale('zh')
);
Material風格時間選擇器
Flutter 1.20 版本更新了 時間 類組件的樣式,
基礎使用
彈出時間組件:
RaisedButton(
child: Text('彈出時間選擇器'),
onPressed: () async {
var result =
showTimePicker(context: context, initialTime: TimeOfDay.now());
},
)
1.20 版以前的效果:
設定 互動模式,互動模式包含 時鐘模式(默認)和 輸入模式,
var result = showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
initialEntryMode: TimePickerEntryMode.input);
時鐘模式(TimePickerEntryMode.dial):
輸入模式(TimePickerEntryMode.input):
設定頂部標題、取消按鈕、確定按鈕 文案:
var result = showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
initialEntryMode: TimePickerEntryMode.input,
helpText: '選擇時間',
cancelText: '取消',
confirmText: '確定');
24小時 制:
var result = showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget child) {
return MediaQuery(
data: MediaQuery.of(context)
.copyWith(alwaysUse24HourFormat: true),
child: child,
);
},
);
黑暗模式
var result = showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.dark(),
child: child,
);
},
);
國際化
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在頂級組件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('zh'),
const Locale('en'),
],
...
彈出時間組件:
RaisedButton(
child: Text('彈出時間選擇器'),
onPressed: () async {
var result =
showTimePicker(context: context, initialTime: TimeOfDay.now());
},
)
切換系統語言為中文:
不跟隨系統語言,直接指定,比如當前系統語言為中文,指定為英文:
var result = showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget child) {
return Localizations(
locale: Locale('en'),
delegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
child: child,
);
},
);
iOS風格日期選擇器
基礎使用
CupertinoDatePicker 是 iOS風格的日期選擇器,
class CupertinoDatePickerDemo extends StatefulWidget {
@override
_CupertinoDatePickerDemoState createState() => _CupertinoDatePickerDemoState();
}
class _CupertinoDatePickerDemoState extends State<CupertinoDatePickerDemo> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
height: 200,
color: Colors.grey.withOpacity(.5),
child: CupertinoDatePicker(
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
),
),
),
);
}
}
設定最大/小時間:
CupertinoDatePicker(
initialDateTime: DateTime.now(),
minimumDate: DateTime.now().add(Duration(days: -1)),
maximumDate: DateTime.now().add(Duration(days: 1)),
onDateTimeChanged: (date) {
print('$date');
},
)
最大時間為明天,最小時間為昨天:
設定模式為時間:
CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
)
設定模式為日期:
CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
)
設定模式為日期和時間:
CupertinoDatePicker(
mode: CupertinoDatePickerMode.dateAndTime,
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
)
- time:只顯示時間,效果:
4 | 14 | PM - date:只顯示日期,效果:
July | 13 | 2012 - dateAndTime:時間和日期都顯示,效果:
Fri Jul 13 | 4 | 14 | PM
使用24小時制:
CupertinoDatePicker(
use24hFormat: true,
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
)
國際化
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在頂級組件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('zh'),
const Locale('en'),
],
...
組件使用:
CupertinoDatePicker(
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
)
組件語言跟隨系統語言,當前系統語言為英文,效果:
不跟隨系統語言,直接指定,比如當前系統語言為英文,指定為中文:
Localizations(
locale: Locale('zh'),
delegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
child: CupertinoDatePicker(
initialDateTime: DateTime.now(),
onDateTimeChanged: (date) {
print('$date');
},
),
)
iOS風格時間選擇器
基礎使用
CupertinoTimerPicker 是 iOS風格的時間選擇器,
CupertinoTimerPicker(onTimerDurationChanged: (time) {
print('$time');
})
設定顯示模式:
- CupertinoTimerPickerMode.hm:顯示 小時 | 分鐘,英文效果
16 hours | 14 min - CupertinoTimerPickerMode.ms: 顯示 分鐘 | 秒,英文效果
14 min | 43 sec - CupertinoTimerPickerMode.hms:顯示 小時 | 分鐘 | 秒,英文效果
16 hours | 14 min | 43 sec
CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hm,
onTimerDurationChanged: (time) {
print('$time');
})
默認情況下,CupertinoTimerPicker顯示0:0:0,設定顯示當前時間:
CupertinoTimerPicker(
initialTimerDuration: Duration(
hours: DateTime.now().hour,
minutes: DateTime.now().minute,
seconds: DateTime.now().second),
onTimerDurationChanged: (time) {
print('$time');
})
設定 分/秒 的間隔:
CupertinoTimerPicker(
minuteInterval: 5,
secondInterval: 5,
onTimerDurationChanged: (time) {
print('$time');
})
國際化
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在頂級組件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('zh'),
const Locale('en'),
],
...
組件使用:
CupertinoTimerPicker(onTimerDurationChanged: (time) {
print('$time');
})
組件語言跟隨系統語言,當前系統語言為英文,效果:
不跟隨系統語言,直接指定,比如當前系統語言為英文,指定為中文:
Localizations(
locale: Locale('zh'),
delegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
child: CupertinoTimerPicker(onTimerDurationChanged: (time) {
print('$time');
}),
)
InteractiveViewer
InteractiveViewer 是 Flutter 1.20 新增的組件,用戶可以通過拖動以平移、縮放和拖放子組件,
InteractiveViewer(
child: Image.asset('assets/images/go_board_09x09.png'),
)
alignPanAxis 引數表示是否只在水平和垂直方向上拖拽,默認為false,設定為true,無法沿著對角線(斜著)方向移動,
InteractiveViewer(
alignPanAxis: true,
child: Image.asset('assets/images/go_board_09x09.png'),
)
maxScale 、minScale、scaleEnabled 是縮放相關引數,分別表示最大縮放倍數、最小縮放倍數、是否可以縮放:
InteractiveViewer(
maxScale: 2,
minScale: 1,
scaleEnabled: true,
child: Image.asset('assets/images/go_board_09x09.png'),
)
constrained 引數表示組件樹中的約束是否應用于子組件,默認為true,如果設為true,表示子組件是無限制約束,這對子組件的尺寸比 InteractiveViewer 大時非常有用,比如子組件為滾動系列組件,
如下的案例,子組件為 Table,Table 尺寸大于螢屏,必須將constrained設定為 false 以便將其繪制為完整尺寸,超出的螢屏尺寸可以平移到視圖中,
class InteractiveViewerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
const int _rowCount = 20;
const int _columnCount = 10;
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
height: 300,
width: 300,
child: InteractiveViewer(
constrained: false,
child: Table(
columnWidths: <int, TableColumnWidth>{
for (int column = 0; column < _columnCount; column += 1)
column: const FixedColumnWidth(100.0),
},
children: <TableRow>[
for (int row = 0; row < _rowCount; row += 1)
TableRow(
children: <Widget>[
for (int column = 0; column < _columnCount; column += 1)
Container(
height: 50,
color: row % 2 + column % 2 == 1
? Colors.red
: Colors.green,
),
],
),
],
),
),
),
),
);
}
}
回呼事件:
- onInteractionStart:當用戶開始平移或縮放手勢時呼叫,
- onInteractionUpdate:當用戶更新組件上的平移或縮放手勢時呼叫,
- onInteractionEnd:當用戶在組件上結束平移或縮放手勢時呼叫,
InteractiveViewer(
child: Image.asset('assets/images/go_board_09x09.png'),
onInteractionStart: (ScaleStartDetails scaleStartDetails){
print('onInteractionStart:$scaleStartDetails');
},
onInteractionUpdate: (ScaleUpdateDetails scaleUpdateDetails){
print('onInteractionUpdate:$scaleUpdateDetails');
},
onInteractionEnd: (ScaleEndDetails endDetails){
print('onInteractionEnd:$endDetails');
},
)
通過 Matrix4 矩陣對其進行變換,比如左移、放大等,添加變換控制器:
final TransformationController _transformationController =
TransformationController();
InteractiveViewer(
child: Image.asset('assets/images/go_board_09x09.png'),
transformationController: _transformationController,
)
放大變換:
var matrix = _transformationController.value.clone();
matrix.scale(1.5, 1.0, 1.0);
_transformationController.value = https://www.cnblogs.com/mengqd/p/matrix;
完整代碼:
import 'dart:math';
import 'package:flutter/material.dart';
///
/// desc:
///
class InteractiveViewerDemo extends StatefulWidget {
@override
_InteractiveViewerDemoState createState() => _InteractiveViewerDemoState();
}
class _InteractiveViewerDemoState extends State<InteractiveViewerDemo> {
final TransformationController _transformationController =
TransformationController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Center(
child: InteractiveViewer(
child: Image.asset('assets/images/go_board_09x09.png'),
transformationController: _transformationController,
),
),
),
Expanded(
child: Container(),
),
Row(
children: [
RaisedButton(
child: Text('重置'),
onPressed: () {
_transformationController.value = https://www.cnblogs.com/mengqd/p/Matrix4.identity();
},
),
RaisedButton(
child: Text('左移'),
onPressed: () {
var matrix = _transformationController.value.clone();
matrix.translate(-5.0);
_transformationController.value = https://www.cnblogs.com/mengqd/p/matrix;
},
),
RaisedButton(
child: Text('放大'),
onPressed: () {
var matrix = _transformationController.value.clone();
matrix.scale(1.5, 1.0, 1.0);
_transformationController.value = https://www.cnblogs.com/mengqd/p/matrix;
},
),
],
),
],
),
);
}
}
交流
老孟Flutter博客地址(330個控制元件用法):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/5948.html
標籤:Dart


