Controller in Flutter Range Selector (SfRangeSelector)
18 Nov 201824 minutes to read
You can use RangeController for setting and getting current selected values of Flutter Range Selector.
The start represents the currently selected start value of the Flutter Range Selector. The left thumb of the Range Selector is drawn corresponding to this value.
The end represents the currently selected end value of the Flutter Range Selector. The right thumb of the Range Selector is drawn corresponding to this value.
You can get previous values using previousStart and previousEnd properties.
The start, end, previousStart, previousEnd properties can be either double or DateTime based on whether it is date type SfRangeSelector or numeric SfRangeSelector.
IMPORTANT
You do not need to set the
initialValuesproperty when using thecontrollerproperty in the Flutter Range Selector.
NOTE
You must import the
Coreto use the range controller in the Flutter Range Selector.
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_core/core.dart';
import 'package:syncfusion_flutter_sliders/sliders.dart';
class ControllerSample extends StatefulWidget {
@override
_ControllerSampleState createState() => _ControllerSampleState();
}
class _ControllerSampleState extends State<ControllerSample> {
final double _min = 2.0;
final double _max = 10.0;
SfRangeValues _values = SfRangeValues(4.0, 6.0);
late RangeController _rangeController;
@override
void initState() {
super.initState();
_rangeController = RangeController(start: _values.start, end: _values.end);
}
@override
void dispose() {
_rangeController.dispose();
super.dispose();
}
final List<Data> chartData = <Data>[
Data(x: 2.0, y: 2.2),
Data(x: 3.0, y: 3.4),
Data(x: 4.0, y: 2.8),
Data(x: 5.0, y: 1.6),
Data(x: 6.0, y: 2.3),
Data(x: 7.0, y: 2.5),
Data(x: 8.0, y: 2.9),
Data(x: 9.0, y: 3.8),
Data(x: 10.0, y: 3.7),
];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SfRangeSelector(
min: _min,
max: _max,
interval: 1,
showTicks: true,
showLabels: true,
controller: _rangeController,
child: Container(
height: 130,
child: SfCartesianChart(
margin: const EdgeInsets.all(0),
primaryXAxis: NumericAxis(
minimum: _min,
maximum: _max,
isVisible: false,
),
primaryYAxis: NumericAxis(isVisible: false),
plotAreaBorderWidth: 0,
series: <SplineAreaSeries<Data, double>>[
SplineAreaSeries<Data, double>(
color: Color.fromARGB(255, 126, 184, 253),
dataSource: chartData,
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y)
],
),
),
),
),
),
);
}
}
class Data {
Data({required this.x, required this.y});
final double x;
final double y;
}
Selection with SfChart
The Flutter Range Selector provides built-in support for selecting the chart segments based on the selected range in the Range Selector. To achieve this segment selection, you must set the SelectionBehavior.selectionController property in the SfCartesianChart.series property. The selectionController links the chart selection to the controller of the Range Controller.
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_core/core.dart';
import 'package:syncfusion_flutter_sliders/sliders.dart';
class SelectionWithSfChartSample extends StatefulWidget {
@override
_SelectionWithSfChartSampleState createState() =>
_SelectionWithSfChartSampleState();
}
class _SelectionWithSfChartSampleState
extends State<SelectionWithSfChartSample> {
SfRangeValues _values =
SfRangeValues(DateTime(2010, 03, 01), DateTime(2010, 06, 01));
late RangeController _rangeController;
final List<Data> chartData = <Data>[
Data(x: DateTime(2010, 01, 01), y: 2.2),
Data(x: DateTime(2010, 02, 01), y: 3.4),
Data(x: DateTime(2010, 03, 01), y: 2.8),
Data(x: DateTime(2010, 04, 01), y: 1.6),
Data(x: DateTime(2010, 05, 01), y: 2.3),
Data(x: DateTime(2010, 06, 01), y: 2.5),
Data(x: DateTime(2010, 07, 01), y: 2.9),
Data(x: DateTime(2010, 08, 01), y: 3.8),
Data(x: DateTime(2010, 09, 01), y: 3.7),
];
@override
void initState() {
super.initState();
_rangeController =
RangeController(start: _values.start, end: _values.end);
}
@override
void dispose() {
_rangeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SfRangeSelector(
min: DateTime(2010, 01, 01),
max: DateTime(2010, 09, 01),
interval: 2,
dateIntervalType: DateIntervalType.months,
dateFormat: DateFormat.yM(),
showTicks: true,
showLabels: true,
controller: _rangeController,
onChanged: (SfRangeValues values) {
setState(() {});
},
child: SizedBox(
height: 130,
child: SfCartesianChart(
margin: EdgeInsets.zero,
primaryXAxis: DateTimeAxis(
minimum: DateTime(2010, 01, 01),
maximum: DateTime(2010, 09, 01),
isVisible: false,
),
primaryYAxis: const NumericAxis(isVisible: false),
plotAreaBorderWidth: 0,
plotAreaBackgroundColor: Colors.transparent,
series: <ColumnSeries<Data, DateTime>>[
ColumnSeries<Data, DateTime>(
dataSource: chartData,
selectionBehavior: SelectionBehavior(
selectionController: _rangeController,
),
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y,
pointColorMapper: (Data sales, int index) {
final DateTime start =
_rangeController.start as DateTime;
final DateTime end = _rangeController.end as DateTime;
if (sales.x.isAfter(start) && sales.x.isBefore(end)) {
return const Color.fromRGBO(0, 178, 206, 1);
}
return Colors.transparent;
},
color: const Color.fromRGBO(255, 255, 255, 0),
dashArray: const <double>[5, 4],
borderColor: const Color.fromRGBO(194, 194, 194, 1),
animationDuration: 0,
borderWidth: 1,
),
],
),
),
),
),
),
);
}
}
class Data {
Data({required this.x, required this.y});
final DateTime x;
final double y;
}
Zooming with SfChart
The Flutter Range Selector provides built-in support for updating the visible range of the chart based on the selected range in the Range Selector. To update the visible range, you must set the primaryXAxis.rangeController property in the SfCartesianChart.
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_core/core.dart';
import 'package:syncfusion_flutter_sliders/sliders.dart';
class ZoomingWithSfChartSample extends StatefulWidget {
@override
_ZoomingWithSfChartSampleState createState() =>
_ZoomingWithSfChartSampleState();
}
class _ZoomingWithSfChartSampleState extends State<ZoomingWithSfChartSample> {
final double _min = 2.0;
final double _max = 19.0;
SfRangeValues _values = SfRangeValues(8.0, 16.0);
late RangeController _rangeController;
late SfCartesianChart splineChart;
final List<Data> chartData = <Data>[
Data(x: 2.0, y: 2.2),
Data(x: 3.0, y: 3.4),
Data(x: 4.0, y: 2.8),
Data(x: 5.0, y: 1.6),
Data(x: 6.0, y: 2.3),
Data(x: 7.0, y: 2.5),
Data(x: 8.0, y: 2.9),
Data(x: 9.0, y: 3.8),
Data(x: 10.0, y: 3.7),
Data(x: 11.0, y: 2.2),
Data(x: 12.0, y: 3.4),
Data(x: 13.0, y: 2.8),
Data(x: 14.0, y: 1.6),
Data(x: 15.0, y: 2.3),
Data(x: 16.0, y: 2.5),
Data(x: 17.0, y: 2.9),
Data(x: 18.0, y: 3.8),
Data(x: 19.0, y: 3.7),
];
@override
void initState() {
super.initState();
_rangeController =
RangeController(start: _values.start, end: _values.end);
}
@override
void dispose() {
_rangeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
splineChart = SfCartesianChart(
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 20),
primaryXAxis: NumericAxis(
minimum: _min,
maximum: _max,
isVisible: true,
rangeController: _rangeController),
primaryYAxis: NumericAxis(isVisible: true),
plotAreaBorderWidth: 0,
series: <SplineSeries<Data, double>>[
SplineSeries<Data, double>(
color: Color.fromARGB(255, 126, 184, 253),
dataSource: chartData,
animationDuration: 0,
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y)
],
);
return MaterialApp(
home: Scaffold(
body: Center(
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 80),
child: Column(
children: <Widget>[
Container(
child: splineChart,
),
SfRangeSelector(
min: _min,
max: _max,
interval: 2,
showTicks: true,
showLabels: true,
controller: _rangeController,
child: Container(
height: 130,
child: SfCartesianChart(
margin: const EdgeInsets.all(0),
primaryXAxis: NumericAxis(
minimum: _min,
maximum: _max,
isVisible: false),
primaryYAxis: NumericAxis(isVisible: false),
plotAreaBorderWidth: 0,
series: <SplineSeries<Data, double>>[
SplineSeries<Data, double>(
color: Color.fromARGB(255, 126, 184, 253),
dataSource: chartData,
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y)
],
),
),
),
],
),
),
),
),
);
}
}
class Data {
Data({required this.x, required this.y});
final double x;
final double y;
}
Deferred update
You can control when the dependent components are updated while thumbs are being dragged continuously. It can be achieved by setting the SfRangeSelector.enableDeferredUpdate property and the delay in the update can be achieved by setting the SfRangeSelector.deferredUpdateDelay property. The default value of the deferredUpdateDelay property is 500 milliseconds.
It updates the controller start and end values and invoke the onChanged callback when the thumb is dragged and held for the duration specified in the deferredUpdateDelay. However, range values are immediately updated in touch up action.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_core/core.dart';
import 'package:syncfusion_flutter_sliders/sliders.dart';
class DeferredUpdateSample extends StatefulWidget {
@override
_DeferredUpdateSampleState createState() => _DeferredUpdateSampleState();
}
class _DeferredUpdateSampleState extends State<DeferredUpdateSample> {
final DateTime min = DateTime(2000, 01, 01, 0), max = DateTime(2000, 12, 15);
late RangeController rangeController;
late SfCartesianChart splineAreaChart;
late SfCartesianChart splineChart;
late List<Data> data;
@override
void initState() {
super.initState();
rangeController = RangeController(
start: DateTime(2000, 04, 15),
end: DateTime(2000, 07, 15),
);
data = <Data>[
Data(x: DateTime(2000, 01, 01, 0), y: 100),
Data(x: DateTime(2000, 01, 15), y: 10),
Data(x: DateTime(2000, 02, 01), y: 40),
Data(x: DateTime(2000, 02, 15), y: 34),
Data(x: DateTime(2000, 03, 01), y: 80),
Data(x: DateTime(2000, 03, 15), y: 49),
Data(x: DateTime(2000, 04, 01), y: 56),
Data(x: DateTime(2000, 04, 15), y: 26),
Data(x: DateTime(2000, 05, 01), y: 8),
Data(x: DateTime(2000, 05, 15), y: 80),
Data(x: DateTime(2000, 06, 01), y: 42),
Data(x: DateTime(2000, 06, 15), y: 12),
Data(x: DateTime(2000, 07, 01), y: 28),
Data(x: DateTime(2000, 07, 15), y: 68),
Data(x: DateTime(2000, 08, 01), y: 94),
Data(x: DateTime(2000, 08, 15), y: 24),
Data(x: DateTime(2000, 09, 01), y: 72),
Data(x: DateTime(2000, 09, 15), y: 32),
Data(x: DateTime(2000, 10, 01), y: 48),
Data(x: DateTime(2000, 10, 15), y: 4),
Data(x: DateTime(2000, 11, 01), y: 64),
Data(x: DateTime(2000, 11, 15), y: 10),
Data(x: DateTime(2000, 12, 01), y: 85),
Data(x: DateTime(2000, 12, 15), y: 96),
];
splineAreaChart = SfCartesianChart(
margin: const EdgeInsets.all(0),
primaryXAxis: DateTimeAxis(isVisible: false, maximum: max),
primaryYAxis: NumericAxis(isVisible: false),
plotAreaBorderWidth: 0,
series: <SplineAreaSeries<Data, DateTime>>[
SplineAreaSeries<Data, DateTime>(
dataSource: data,
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y,
)
],
);
}
@override
void dispose() {
rangeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
splineChart = SfCartesianChart(
plotAreaBorderWidth: 0,
primaryXAxis: DateTimeAxis(
isVisible: false,
minimum: min,
maximum: max,
rangeController: rangeController),
primaryYAxis: NumericAxis(
labelPosition: ChartDataLabelPosition.inside,
labelAlignment: LabelAlignment.end,
majorTickLines: MajorTickLines(size: 0),
axisLine: AxisLine(color: Colors.transparent),
),
series: <SplineSeries<Data, DateTime>>[
SplineSeries<Data, DateTime>(
dataSource: data,
animationDuration: 0,
xValueMapper: (Data sales, int index) => sales.x,
yValueMapper: (Data sales, int index) => sales.y,
)
],
);
final Widget page = Container(
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
child: Center(
child: Column(
children: <Widget>[
Expanded(
child: Container(
padding: const EdgeInsets.fromLTRB(5, 20, 15, 25),
child: splineChart),
),
Container(
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
child: Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(14, 0, 15, 15),
child: SfRangeSelector(
min: min,
max: max,
interval: 1,
enableDeferredUpdate: true,
deferredUpdateDelay: 500,
labelPlacement: LabelPlacement.betweenTicks,
dateIntervalType: DateIntervalType.months,
controller: rangeController,
showTicks: true,
showLabels: true,
dragMode: SliderDragMode.both,
labelFormatterCallback:
(dynamic actualLabel, String formattedText) {
final String label = DateFormat.MMM().format(actualLabel);
return label;
},
onChanged: (SfRangeValues values) {},
child: Container(
child: splineAreaChart,
height: 75,
padding: const EdgeInsets.all(0),
margin: const EdgeInsets.all(0),
),
),
),
),
),
],
),
),
);
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(height: 400, child: page),
),
),
);
}
}
class Data {
Data({required this.x, required this.y});
final DateTime x;
final double y;
}