20

【Flutter 实战】1.20版本更新及新增组件

 3 years ago
source link: https://segmentfault.com/a/1190000024419315
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

bVbMkpr

老孟导读 :Flutter 1.20 更新了 Slider、RangeSlider、日期选择器组件、时间选择器组件的样式,新增了交换组件:InteractiveViewer,下面详细介绍其用法。

滑块

Flutter 1.20 版本将 SliderRangeSlider 小部件更新为最新的 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 :滑块值改变时回调。

2f5f3bad0b5e4778bd262a72b67f121a~tplv-k3u1fbpfcp-zoom-1.image

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

202ded80d62a4eb6bb6b39a2bd636212~tplv-k3u1fbpfcp-zoom-1.image

明显的感觉就是滑块轨道变粗了,滑块变的更有立体感(加了阴影)了。

Slider默认滑动范围是 0-1,修改为 1-100:

Slider(
  value: _sliderValue,
  min: 1,
  max: 100,
  onChanged: (v){
    setState(() {
      _sliderValue = v;
    });
  },
)

ec2623b7b64d44d1a365c332f51b10d1~tplv-k3u1fbpfcp-zoom-1.image

设置滑块的滑动为 离散的 ,即滑动值为 0、25 、50、75 100:

Slider(
  value: _sliderValue,
  min: 0,
  max: 100,
  divisions: 4,
  onChanged: (v){
    setState(() {
      _sliderValue = v;
    });
  },
)

fe7a1bea7784483caa29587029a0e3eb~tplv-k3u1fbpfcp-zoom-1.image

设置标签,滑动过程中在其上方显示:

Slider(
  value: _sliderValue,
  label: '$_sliderValue',
  min: 0,
  max: 100,
  divisions: 4,
  onChanged: (v){
    setState(() {
      _sliderValue = v;
    });
  },
)

19e389ce842c47baa5329f668b3739cb~tplv-k3u1fbpfcp-zoom-1.image

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

b67b25dc51ed4c6cbfdb88642e79a9c7~tplv-k3u1fbpfcp-zoom-1.image

个人感觉以前的更好看。

下面是官方给的 Slider 结构图:

7a05e5da94754de7abbef42682a74470~tplv-k3u1fbpfcp-zoom-1.image

  • 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 = v;
    });
  },
)

3ab5186cc90e46309165ee05ab7054ef~tplv-k3u1fbpfcp-zoom-1.image

这个自定义比较笼统,下面来一个更细致的自定义:

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 = v;
      });
    },
  ),
)

3cf9234077344ca8b758479781fcce21~tplv-k3u1fbpfcp-zoom-1.image

这个基本可以完全自定义样式了。

如何在 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 = v;
      });
    },
  ),
)

91339995c55245a3a6b46e878ff5ba74~tplv-k3u1fbpfcp-zoom-1.image

RectangularSliderValueIndicatorShape表示矩形样式:

44f886c15f44488cb67233cdaa416477~tplv-k3u1fbpfcp-zoom-1.image

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;
    });
  },
),

673482bd33b842cf8eff1bb7b5d1c809~tplv-k3u1fbpfcp-zoom-1.image

滑块状态

696cd01aa79b4876a25de81acc03de9a~tplv-k3u1fbpfcp-zoom-1.image

ios风格的 Slider

ios风格的 Slider,使用 CupertinoSlider:

double _sliderValue = 0;
CupertinoSlider(
  value: _sliderValue,
  onChanged: (v) {
    setState(() {
      _sliderValue = v;
    });
  },
)

2ad0677f53f245aeafb640bc4b6702a3~tplv-k3u1fbpfcp-zoom-1.image

当然也可以根据平台显示不同风格的Slider,ios平台显示CupertinoSlider效果,其他平台显示Material风格,用法如下:

Slider.adaptive(
  value: _sliderValue,
  onChanged: (v) {
    setState(() {
      _sliderValue = v;
    });
  },
)

Material风格日期选择器

Flutter 1.20 版本更新了 日期 类组件的样式,加入了新的紧凑设计以及对日期范围的支持。

showDatePicker

结构图

6088ae793e6641bc8d99e82f57dc09aa~tplv-k3u1fbpfcp-zoom-1.image

  1. 标题
  2. 选中的日期
  3. 切换到 输入模式
  4. 选择菜单
  5. 月份分页
  6. 当前时间
  7. 选中日期

输入模式结构图:

4ef7b0da63964700a252c440cda3ff2a~tplv-k3u1fbpfcp-zoom-1.image

  1. 标题
  2. 选中日期
  3. 切换 日历模式
  4. 输入框

基础用法

点击按钮弹出日期组件:

RaisedButton(
          child: Text('弹出日期组件'),
          onPressed: () async {
            await showDatePicker(
              context: context,
              initialDate: DateTime.now(),
              firstDate: DateTime(2010),
              lastDate: DateTime(2025),
            );

af2826a53b094d7bacdced3bec75769d~tplv-k3u1fbpfcp-zoom-1.image

  • initialDate :初始化时间,通常情况下设置为当前时间。
  • firstDate :表示开始时间,不能选择此时间前面的时间。
  • lastDate :表示结束时间,不能选择此时间之后的时间。

设置日期选择器对话框的模式:

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  initialEntryMode: DatePickerEntryMode.input,
);

34291704b20d49acb40452490cb5e331~tplv-k3u1fbpfcp-zoom-1.image

直接显示 输入模式 ,默认是 日历模式

设置日历日期选择器的初始显示,包含 dayyear

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  initialDatePickerMode: DatePickerMode.year,
);

82b04af824714f22a5b33de762462f45~tplv-k3u1fbpfcp-zoom-1.image

和以前的版本对比:

d678c5cd511e45db89255f730e049520~tplv-k3u1fbpfcp-zoom-1.image

设置顶部标题、取消按钮、确定按钮 文案:

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  helpText: '选则日期',
  cancelText: '取消',
  confirmText: '确定',
);

0151351ddba0463998fa6e862caa428a~tplv-k3u1fbpfcp-zoom-1.image

修改 输入模式 下文案:

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  errorFormatText: '错误的日期格式',
  errorInvalidText: '日期格式非法',
  fieldHintText: '月/日/年',
  fieldLabelText: '填写日期',
);

b9a2e2eafd55479bbfc53a9c90efe454~tplv-k3u1fbpfcp-zoom-1.image

e8be7f26f2894fa7a0a1cd7091b561c4~tplv-k3u1fbpfcp-zoom-1.image

设置可选日期范围

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  selectableDayPredicate: (date) {
    return date.difference(DateTime.now()).inMilliseconds < 0;
  },
);

64bf98c7c6154ad398b778a12146af16~tplv-k3u1fbpfcp-zoom-1.image

今天以后的日期全部为灰色,不可选状态。

设置深色主题

设置深色主题使 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,
    );
  }
);

6c342dd476ff45b28c7ffe297a8a60b3~tplv-k3u1fbpfcp-zoom-1.image

获取选中的日期

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');
  },
)

c8a4f0bd19c44a9192bbba80267c4253~tplv-k3u1fbpfcp-zoom-1.image

其参数和 showDatePicker 一样。

范围日期

选择范围日期使用 showDateRangePicker

RaisedButton(
  child: Text('范围日期'),
  onPressed: () async {
    var date = showDateRangePicker(context: context, firstDate: DateTime(2010), lastDate: DateTime(2025));
  },
),

0dd2901d917d412f95f8299368bc7656~tplv-k3u1fbpfcp-zoom-1.image

其参数和 showDatePicker 一样。

范围日期结构图:

40d5e27b9e334ed090914bdbd30000ae~tplv-k3u1fbpfcp-zoom-1.image

  1. 标题
  2. 选定的日期范围
  3. 切换到 输入模式
  4. 月和年标签
  5. 当前时间
  6. 开始时间
  7. 选中时间范围
  8. 结束时间

国际化

国际化都是一个套路,下面以 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),
);

此时将系统语音调整为 中文

2101a742179545a289a744104035cec7~tplv-k3u1fbpfcp-zoom-1.image

此组件只支持 中文 ,不管系统设置语言:

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

59ca64a7d5c34121a7e7a2235a0b8653~tplv-k3u1fbpfcp-zoom-1.image

1.20 版以前的效果:

df58f8fbb5fc4ceab39572ce54f5e350~tplv-k3u1fbpfcp-zoom-1.image

设置 交互模式 ,交互模式包含 时钟模式 (默认)和 输入模式

var result = showTimePicker(
    context: context,
    initialTime: TimeOfDay.now(),
    initialEntryMode: TimePickerEntryMode.input);

时钟模式(TimePickerEntryMode.dial):

07a7a11e6ce04ad1a4b2a472f4d72c6b~tplv-k3u1fbpfcp-zoom-1.image

输入模式(TimePickerEntryMode.input):

b8151b5089b44d4bbb8b8a9123827218~tplv-k3u1fbpfcp-zoom-1.image

设置顶部标题、取消按钮、确定按钮 文案:

var result = showTimePicker(
    context: context,
    initialTime: TimeOfDay.now(),
    initialEntryMode: TimePickerEntryMode.input,
    helpText: '选择时间',
    cancelText: '取消',
    confirmText: '确定');

ffe5f8fd66ee4872ac30e55ada0dd384~tplv-k3u1fbpfcp-zoom-1.image

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,
    );
  },
);

6dbbb308fb1544b795c94b123a1e3d32~tplv-k3u1fbpfcp-zoom-1.image

黑暗模式

var result = showTimePicker(
  context: context,
  initialTime: TimeOfDay.now(),
  builder: (BuildContext context, Widget child) {
    return Theme(
      data: ThemeData.dark(),
      child: child,
    );
  },
);

e61e16dffd3543ee9c562280ce37c535~tplv-k3u1fbpfcp-zoom-1.image

国际化

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

切换系统语言为中文:

1cd31ba5b6f543adb5d3c3a12be19c10~tplv-k3u1fbpfcp-zoom-1.image

不跟随系统语言,直接指定,比如当前系统语言为中文,指定为英文:

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,
    );
  },
);

c5504342963f4cdbbba2321befe0e5cc~tplv-k3u1fbpfcp-zoom-1.image

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');
            },
          ),
        ),
      ),
    );
  }

}

1cab65cb96af441f99261842dbcc188c~tplv-k3u1fbpfcp-zoom-1.image

设置最大/小时间:

CupertinoDatePicker(
  initialDateTime: DateTime.now(),
  minimumDate: DateTime.now().add(Duration(days: -1)),
  maximumDate: DateTime.now().add(Duration(days: 1)),
  onDateTimeChanged: (date) {
    print('$date');
  },
)

最大时间为明天,最小时间为昨天:

538b1d7aa8de420e958efd6cb330b1ea~tplv-k3u1fbpfcp-zoom-1.image

设置模式为 时间

CupertinoDatePicker(
  mode: CupertinoDatePickerMode.time,
  initialDateTime: DateTime.now(),
  onDateTimeChanged: (date) {
    print('$date');
  },
)

e9587db9b4e24190a1858f33c7d11468~tplv-k3u1fbpfcp-zoom-1.image

设置模式为 日期

CupertinoDatePicker(
  mode: CupertinoDatePickerMode.date,
  initialDateTime: DateTime.now(),
  onDateTimeChanged: (date) {
    print('$date');
  },
)

346ce5d897214e3bb95ad0c870a97d2e~tplv-k3u1fbpfcp-zoom-1.image

设置模式为 日期和时间

CupertinoDatePicker(
  mode: CupertinoDatePickerMode.dateAndTime,
  initialDateTime: DateTime.now(),
  onDateTimeChanged: (date) {
    print('$date');
  },
)

e2991c26185d46e28ccb0471bd4a8e34~tplv-k3u1fbpfcp-zoom-1.image

  • 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');
  },
)

7d9ab2e6904b4e5f8a618e0b7f57aa28~tplv-k3u1fbpfcp-zoom-1.image

国际化

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');
  },
)

组件语言跟随系统语言,当前系统语言为英文,效果:

e225b897044f4011ab62bb707d5765e3~tplv-k3u1fbpfcp-zoom-1.image

不跟随系统语言,直接指定,比如当前系统语言为英文,指定为中文:

Localizations(
  locale: Locale('zh'),
  delegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  child: CupertinoDatePicker(
    initialDateTime: DateTime.now(),
    onDateTimeChanged: (date) {
      print('$date');
    },
  ),
)

d7796274d8a24947a25d2ea5f5882401~tplv-k3u1fbpfcp-zoom-1.image

iOS风格时间选择器

基础使用

CupertinoTimerPicker是 iOS风格的时间选择器。

CupertinoTimerPicker(onTimerDurationChanged: (time) {
  print('$time');
})

023a842f31d74beba405c9228e2b36e9~tplv-k3u1fbpfcp-zoom-1.image

设置显示模式:

  • 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');
    })

4f249afd4dc3409b879561528ddee4ff~tplv-k3u1fbpfcp-zoom-1.image

默认情况下,CupertinoTimerPicker显示0:0:0,设置显示当前时间:

CupertinoTimerPicker(
    initialTimerDuration: Duration(
        hours: DateTime.now().hour,
        minutes: DateTime.now().minute,
        seconds: DateTime.now().second),
    onTimerDurationChanged: (time) {
      print('$time');
    })

9d65db5210e44a6ebaff24e2c9cfaa67~tplv-k3u1fbpfcp-zoom-1.image

设置 分/秒 的间隔:

CupertinoTimerPicker(
    minuteInterval: 5,
    secondInterval: 5,
    onTimerDurationChanged: (time) {
      print('$time');
    })

70aa7412f2b04b4f819d49c0478ce1f3~tplv-k3u1fbpfcp-zoom-1.image

国际化

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');
})

组件语言跟随系统语言,当前系统语言为英文,效果:

e8d883bb37c943708ff97e5fb1ca52ed~tplv-k3u1fbpfcp-zoom-1.image

不跟随系统语言,直接指定,比如当前系统语言为英文,指定为中文:

Localizations(
  locale: Locale('zh'),
  delegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  child: CupertinoTimerPicker(onTimerDurationChanged: (time) {
    print('$time');
  }),
)

2a5cb0c592f94dac8644d10dee388d17~tplv-k3u1fbpfcp-zoom-1.image

InteractiveViewer

InteractiveViewer是 Flutter 1.20 新增的组件,用户可以通过拖动以平移、缩放和拖放子组件。

InteractiveViewer(
  child: Image.asset('assets/images/go_board_09x09.png'),
)

bfdac0a5bbab422ab07653036a57e536~tplv-k3u1fbpfcp-zoom-1.image

alignPanAxis参数表示是否只在水平和垂直方向上拖拽,默认为false,设置为true,无法沿着对角线(斜着)方向移动。

InteractiveViewer(
  alignPanAxis: true,
  child: Image.asset('assets/images/go_board_09x09.png'),
)

a8715b3000844ee59df8ff9359d9301b~tplv-k3u1fbpfcp-zoom-1.image

maxScale、 minScalescaleEnabled 是缩放相关参数,分别表示最大缩放倍数、最小缩放倍数、是否可以缩放:

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,
                        ),
                    ],
                  ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

230052b354f34f1d9acab75aaa9bed7a~tplv-k3u1fbpfcp-zoom-1.image

回调事件:

  • 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'),
                transformationController: _transformationController,
              ),
            ),
          ),
          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, 1.0);
                  _transformationController.value = matrix;
                },
              ),
            ],
          ),
        ],
      ),
    );
  }
}

2c1523680b8c4fe79b6f4999c51b2a97~tplv-k3u1fbpfcp-zoom-1.image

交流

老孟Flutter博客地址(330个控件用法): http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

bVbGStH bVbGStI

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK