
老孟导读: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 = 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 = v;
});
},)
],),);
}
}
-
value:当前值。
-
onChanged:滑块值改变时回调。

看看 Flutter 1.20 版本以前的样式(我的珍藏):

明显的感觉就是滑块轨道变粗了,滑块变的更有立体感(加了阴影)了。
Slider 默认滑动范围是 0-1,修改为 1-100:
Slider(
value: _sliderValue,min: 1,max: 100,onChanged: (v){
setState(() {
_sliderValue = v;
});
},)

设置滑块的滑动为 离散的,即滑动值为 0、25 、50、75 100:
Slider(
value: _sliderValue,min: 0,divisions: 4,)

设置标签,滑动过程中在其上方显示:
Slider(
value: _sliderValue,label: '$_sliderValue',)

看看 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,)

这个自定义比较笼统,下面来一个更细致的自定义:
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Color(0xff404080),thumbColor: Colors.blue,overlayColor: Colors.green,valueIndicatorColor: Colors.purpleAccent),child: Slider(
value: _sliderValue,onChanged: (v) {
setState(() {
_sliderValue = v;
});
},)

这个基本可以完全自定义样式了。
如何在 Flutter 1.20 版本使用以前的标签样式呢?
SliderTheme(
data: SliderTheme.of(context).copyWith(
valueIndicatorShape: PaddleSliderValueIndicatorShape(),)

RectangularSliderValueIndicatorShape 表示矩形样式:

RangeSlider
RangeSlider 和 Slider 几乎一样,RangeSlider 是范围滑块,想要选择一段值,可以使用 RangeSlider。
RangeValues _rangeValues = RangeValues(0,25);
RangeSlider(
values: _rangeValues,labels: RangeLabels('${_rangeValues.start}','${_rangeValues.end}'),onChanged: (v) {
setState(() {
_rangeValues = v;
});
},

滑块状态

ios风格的 Slider
ios风格的 Slider,使用 CupertinoSlider:
double _sliderValue = 0;
CupertinoSlider(
value: _sliderValue,onChanged: (v) {
setState(() {
_sliderValue = v;
});
},)

当然也可以根据平台显示不同风格的Slider,ios平台显示CupertinoSlider效果,其他平台显示Material风格,用法如下:
Slider.adaptive(
value: _sliderValue,)
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,initialEntryMode: DatePickerEntryMode.input,);

直接显示 输入模式,默认是日历模式。
设置日历日期选择器的初始显示,包含 day 和 year:
var result = await showDatePicker(
context: context,initialDatePickerMode: DatePickerMode.year,);

和以前的版本对比:

设置顶部标题、取消按钮、确定按钮 文案:
var result = await showDatePicker(
context: context,helpText: '选则日期',cancelText: '取消',confirmText: '确定',);

修改 输入模式 下文案:
var result = await showDatePicker(
context: context,errorFormatText: '错误的日期格式',errorInvalidText: '日期格式非法',fieldHintText: '月/日/年',fieldLabelText: '填写日期',);


设置可选日期范围
var result = await showDatePicker(
context: context,selectableDayPredicate: (date) {
return date.difference(DateTime.now()).inMilliseconds < 0;
},);

今天以后的日期全部为灰色,不可选状态。
设置深色主题
设置深色主题使 builder ,其用于包装对话框窗口小部件以添加继承的窗口小部件,例如Theme ,设置深色主题如下:
var result = await showDatePicker(
context: context,builder: (context,child){
return Theme(
data: ThemeData.dark(),child: child,);
}
);

获取选中的日期
showDatePicker 方法是 Future 方法,点击日期选择控件的确定按钮后,返回选择的日期。
var result = await showDatePicker(
context: context,);
print('$result');
result 为选择的日期。
CalendarDatePicker
日期组件直接显示在页面上,而不是弹出显示:
CalendarDatePicker(
initialDate: DateTime.now(),onDateChanged: (d) {
print('$d');
},)

其参数和 showDatePicker 一样。
范围日期
选择范围日期使用 showDateRangePicker:
RaisedButton(
child: Text('范围日期'),onPressed: () async {
var date = showDateRangePicker(context: context,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,);
此时将系统语音调整为中文:

此组件只支持中文,不管系统设置语言:
var result = await showDatePicker(
context: context,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,initialEntryMode: TimePickerEntryMode.input,helpText: '选择时间',confirmText: '确定');

24小时 制:
var result = showTimePicker(
context: context,builder: (BuildContext context,Widget child) {
return MediaQuery(
data: MediaQuery.of(context)
.copyWith(alwaysUse24HourFormat: true),);
},);

黑暗模式
var result = showTimePicker(
context: context,Widget child) {
return Theme(
data: ThemeData.dark(),);

国际化
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在顶级组件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',...
弹出时间组件:
RaisedButton(
child: Text('弹出时间选择器'),)
切换系统语言为中文:

不跟随系统语言,直接指定,比如当前系统语言为中文,指定为英文:
var result = showTimePicker(
context: context,Widget child) {
return Localizations(
locale: Locale('en'),delegates: [
GlobalMaterialLocalizations.delegate,);

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(),)

设置模式为日期:
CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,)

设置模式为日期和时间:
CupertinoDatePicker(
mode: CupertinoDatePickerMode.dateAndTime,)

-
time:只显示时间,效果:
4 | 14 | PM
-
date:只显示日期,效果:
July | 13 | 2012
-
dateAndTime:时间和日期都显示,效果:
Fri Jul 13 | 4 | 14 | PM
使用24小时制:
CupertinoDatePicker(
use24hFormat: true,)

国际化
在 pubspec.yaml 中引入:
dependencies:
flutter_localizations:
sdk: flutter
在顶级组件 MaterialApp 添加支持:
MaterialApp(
title: 'Flutter Demo',...
组件使用:
CupertinoDatePicker(
initialDateTime: DateTime.now(),)
组件语言跟随系统语言,当前系统语言为英文,效果:

不跟随系统语言,直接指定,比如当前系统语言为英文,指定为中文:
Localizations(
locale: Locale('zh'),delegates: [
GlobalMaterialLocalizations.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',...
组件使用:
CupertinoTimerPicker(onTimerDurationChanged: (time) {
print('$time');
})
组件语言跟随系统语言,当前系统语言为英文,效果:

不跟随系统语言,直接指定,比如当前系统语言为英文,指定为中文:
Localizations(
locale: Locale('zh'),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,)
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 = 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'),Expanded(
child: Container(),Row(
children: [
RaisedButton(
child: Text('重置'),onPressed: () {
_transformationController.value = Matrix4.identity();
},RaisedButton(
child: Text('左移'),onPressed: () {
var matrix = _transformationController.value.clone();
matrix.translate(-5.0);
_transformationController.value = matrix;
},RaisedButton(
child: Text('放大'),onPressed: () {
var matrix = _transformationController.value.clone();
matrix.scale(1.5,1.0);
_transformationController.value = matrix;
},);
}
}

交流
老孟Flutter博客地址(330个控件用法):http://laomengit.com
欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|