[Flutter actual combat] 1.20 version update and new components

Lao Meng's guide : Flutter 1.20 updated the styles of Slider, RangeSlider, date picker component, time picker component, and added an exchange component: InteractiveViewer. The usage is described in detail below.

Slider

Flutter version 1.20 updates Slider and RangeSlider widgets to the latest Material guidelines. The new slider was designed with better accessibility in mind: the track is higher, the slider is shaded, and the value indicator has a new shape and improved text scaling support.

Slider

Basic usage:

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 : current value.
  • onChanged : Call back when the slider value changes.

Take a look at the styles of Flutter before version 1.20 (my collection):

The obvious feeling is that the slider track has become thicker, and the slider has become more three-dimensional (shaded).

Slider default sliding range is 0-1, modified to 1-100:

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

Provided to slide the slider discrete , i.e. a sliding value 0,25, 50,75 100:

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

Set a label, which will be displayed above it during sliding:

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

Take a look at the styles of Flutter before version 1.20 (still my collection):

I personally feel that it looks better before.

The following is the official Slider structure diagram:

  • 1 : Track (Track), there is a difference between 1 and 4, 1 refers to the entire track at the bottom, and the track shows the range that can be selected by the user. For left-to-right (LTR) languages, the minimum value appears at the far left end of the track, and the maximum value appears at the far right end. For right-to-left (RTL) languages, this direction is the opposite.
  • 2 : Slider (Thumb), position indicator, which can be moved along the track to display the selected value of its position.
  • 3 : Label (label), which displays a specific numeric value corresponding to the position of the slider.
  • 4 : Tick mark, which indicates the predetermined value that the user can move the slider to.

Custom slider active color and inactive color :

Slider(
  activeColor: Colors.red,
  inactiveColor: Colors.blue,
  value: _sliderValue,
  label: '$_sliderValue',
  min: 0,
  max: 100,
  divisions: 4,
  onChanged: (v){
    setState(() {
      _sliderValue = v;
    });
  },
)

This customization is more general, here is a more detailed customization:

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

This basically can completely customize the style.

How to use the previous label style in 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;
      });
    },
  ),
)

RectangularSliderValueIndicatorShape represents the rectangular style:

RangeSlider

RangeSlider and Slider almost the same, RangeSlider range slider, you want to choose some values, you can use 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;
    });
  },
),

Slider state

Slider in ios style

ios style Slider, use CupertinoSlider:

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

Of course, different styles of Slider can be displayed according to the platform. The ios platform displays the CupertinoSlider effect, and other platforms display the Material style. The usage is as follows:

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

Material style date picker

Flutter 1.20 updated version of the date style class components, adding the new compact design and support for the date range.

showDatePicker

Structure diagram

  1. title
  2. Selected date
  3. Switch to input mode
  4. Year selection menu
  5. Month paging
  6. current time
  7. Selected date

Input mode structure diagram:

  1. title
  2. Selected date
  3. Switching calendar mode
  4. Input box

Basic usage

Click the button to pop up the date component:

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

  • initialDate : Initialization time, usually set to the current time.
  • firstDate : Indicates the start time, and the time before this time cannot be selected.
  • lastDate : Indicates the end time, and the time after this time cannot be selected.

Set the mode of the date picker dialog:

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

Direct display input mode , the default is the calendar mode .

Set the initial display of the calendar date picker, including day and year :

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

Compared with the previous version:

Set the top title, cancel button, and confirm button copy:

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

Modify the input mode under Docket:

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

Set optional date range

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

Dates after today are all grayed out and cannot be selected.

Set a dark theme

Set the dark theme builder, which is used to wrap dialog widgets to add inherited widgets. For example Theme, set the dark theme as follows:

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

Get the selected date

The showDatePicker method is a Future method. After clicking the OK button of the date selection control, the selected date is returned.

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

print('$result');

result is the selected date.

CalendarDatePicker

The date component is displayed directly on the page instead of pop-up display:

CalendarDatePicker(
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  onDateChanged: (d) {
    print('$d');
  },
)

The parameters are the same as showDatePicker.

Range date

Use showDateRangePicker to select the range date :

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

The parameters are the same as showDatePicker.

Range date structure chart:

  1. title
  2. Selected date range
  3. Switch to input mode
  4. Month and year labels
  5. current time
  6. Starting time
  7. Selected time range
  8. End Time

globalization

Internationalization is a routine. Take showDatePicker as an example:

Introduced in pubspec.yaml :

dependencies:
  flutter_localizations:
    sdk: flutter

Add support in the top-level component MaterialApp :

MaterialApp(
  title: 'Flutter Demo',

  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    const Locale('zh'),
    const Locale('en'),
  ],
  ...

Pop-up date component:

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

Now adjust the system voice to Chinese :

This component only supports Chinese , regardless of the system setting language:

var result = await showDatePicker(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2010),
  lastDate: DateTime(2025),
  locale: Locale('zh')
);

Material style time selector

Flutter 1.20 updated version of the time style class components.

Basic use

Pop-up time component:

RaisedButton(
  child: Text('弹出时间选择器'),
  onPressed: () async {
    var result =
        showTimePicker(context: context, initialTime: TimeOfDay.now());
  },
)

Effects before version 1.20:

Setting interaction mode , interactive mode comprises clock mode (the default), and the input mode .

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

Clock mode (TimePickerEntryMode.dial):

Input mode (TimePickerEntryMode.input):

Set the top title, cancel button, and confirm button copy:

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

24-hour clock:

var result = showTimePicker(
  context: context,
  initialTime: TimeOfDay.now(),
  builder: (BuildContext context, Widget child) {
    return MediaQuery(
      data: MediaQuery.of(context)
          .copyWith(alwaysUse24HourFormat: true),
      child: child,
    );
  },
);

Dark mode

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

globalization

Introduced in pubspec.yaml :

dependencies:
  flutter_localizations:
    sdk: flutter

Add support in the top-level component MaterialApp :

MaterialApp(
  title: 'Flutter Demo',

  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    const Locale('zh'),
    const Locale('en'),
  ],
  ...

Pop-up time component:

RaisedButton(
  child: Text('弹出时间选择器'),
  onPressed: () async {
    var result =
        showTimePicker(context: context, initialTime: TimeOfDay.now());
  },
)

Switch the system language to Chinese:

Do not follow the system language and specify it directly. For example, the current system language is Chinese and English is specified:

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 style date picker

Basic use

CupertinoDatePicker is an iOS style date picker.

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

}

Set max/min time:

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

The maximum time is tomorrow, and the minimum time is yesterday:

Set the mode to time :

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

Set the mode to date :

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

Set the mode to date and time :

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

  • time : only display time, effect:4 | 14 | PM
  • date : Only display the date, effect:July | 13 | 2012
  • dateAndTime : Both time and date are displayed, effect:Fri Jul 13 | 4 | 14 | PM

Use the 24-hour clock:

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

globalization

Introduced in pubspec.yaml :

dependencies:
  flutter_localizations:
    sdk: flutter

Add support in the top-level component MaterialApp :

MaterialApp(
  title: 'Flutter Demo',

  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    const Locale('zh'),
    const Locale('en'),
  ],
  ...

Component usage:

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

The component language follows the system language, the current system language is English, the effect:

Do not follow the system language and specify it directly. For example, the current system language is English, and it is specified as Chinese:

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

iOS style time picker

Basic use

CupertinoTimerPicker is an iOS style time picker.

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

Set the display mode:

  • CupertinoTimerPickerMode.hm : Display hours | minutes, English effect16 hours | 14 min
  • CupertinoTimerPickerMode.ms : display minutes | seconds, English effect14 min | 43 sec
  • CupertinoTimerPickerMode.hms : Display hours | minutes | seconds, English effect16 hours | 14 min | 43 sec
CupertinoTimerPicker(
    mode: CupertinoTimerPickerMode.hm,
    onTimerDurationChanged: (time) {
      print('$time');
    })

By default, CupertinoTimerPicker displays 0:0:0, and the setting displays the current time:

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

Set the minute/second interval:

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

globalization

Introduced in pubspec.yaml :

dependencies:
  flutter_localizations:
    sdk: flutter

Add support in the top-level component MaterialApp :

MaterialApp(
  title: 'Flutter Demo',

  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    const Locale('zh'),
    const Locale('en'),
  ],
  ...

Component usage:

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

The component language follows the system language, the current system language is English, the effect:

Do not follow the system language and specify it directly. For example, the current system language is English, and it is specified as Chinese:

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

InteractiveViewer

InteractiveViewer is a new component of Flutter 1.20. Users can pan, zoom, and drag and drop subcomponents by dragging.

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

The alignPanAxis parameter indicates whether to drag only in the horizontal and vertical directions, the default is false, set to true, and it cannot move along the diagonal (oblique) direction.

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

maxScale , minScale , scaleEnabled are zoom related parameters, which respectively indicate the maximum zoom factor, the minimum zoom factor, and whether it can be zoomed:

InteractiveViewer(
  maxScale: 2,
  minScale: 1,
  scaleEnabled: true,
  child: Image.asset('assets/images/go_board_09x09.png'),
)

The constrained parameter indicates whether the constraint in the component tree is applied to the sub-component. The default is true. If set to true, the sub-component is an unlimited constraint. This is very useful when the size of the sub-component is larger than the InteractiveViewer, for example, the sub-component is a rolling series Components.

In the following case, the child component is Table, and the table size is larger than the screen. It must be constrainedset to false in order to draw it to the full size. The excess screen size can be panned into the view.

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

Callback event:

  • onInteractionStart : Called when the user starts a pan or zoom gesture.
  • onInteractionUpdate : Called when the user updates the pan or zoom gesture on the component.
  • onInteractionEnd : Called when the user ends a pan or zoom gesture on the component.
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');
  },
)

Transform it through the Matrix4 matrix, such as shift left, zoom, etc., add a transformation controller:

final TransformationController _transformationController =
      TransformationController();

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

Zoom in and transform:

var matrix = _transformationController.value.clone();
matrix.scale(1.5, 1.0, 1.0);
_transformationController.value = matrix;

Complete code:

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

communicate with

Laomeng Flutter blog address (330 control usage): http://laomengit.com

Welcome to join the Flutter exchange group (WeChat: laomengit) and follow the public account [Lao Meng Flutter]:

Guess you like

Origin blog.csdn.net/mengks1987/article/details/108526412