Adhering to the object, with the object; No object, look for an object; The ListWheelViewport component is finally running without the thought of creating an object. Previously due to cognitive limitations, has not been able to play ListWheelViewport, now, does grow up. This component has been included in FlutterUnit, now over 310+ components are included, congratulations, welcome star.
Take a look at the basics of ListWheelViewport:
Source location: flutter/lib/SRC/widgets/list_wheel_scroll_view dart parent class: RenderObjectWidget related components: ListWheelScrollView, CupertinoPicker, CupertinoDatePickerCopy the code
ListWheelViewport has the following scrolling viewport effect. If you’ve used a Cupertino style selector, you might think it’s similar. Yes, they all have ListWheelViewport participation at the bottom. After learning about ListWheelViewport, the others are all younger brothers.
A,ListWheelViewport
Three required attributes
The property name | type | The default value | introduce |
---|---|---|---|
itemExtent | double | required | Item size in spindle direction |
offset | ViewportOffset | required | The viewport offset |
childDelegate | ListWheelChildDelegate | required | The child proxy constructor |
Here is a simple demo to test the use of ListWheelViewport. The above three attributes must be given. ItemExtent is the simplest, representing the size of item along the main axis. If you scroll down the wheel, the main axis is the Y-axis, and itemExtent is the height of each item.
ChildDelegate attribute is ListWheelChildDelegate type, it is an abstract class, implementation class has the following three, including: ListWheelChildListDelegate accept List < widgets > to display. ListWheelChildBuilderDelegate by builder constructor to create the item. ListWheelChildLoopingListDelegate slide can be infinite List, and accept the List < widgets > to display.
The offset attribute needs to be passed into a ViewportOffset object, which is hard to build. However, based on previous experience, this object can be obtained from Scrollable. When the viewportBuilder property is assigned, the ViewportOffset object can be called back.
typedef ViewportBuilder = Widget Function(BuildContext context, ViewportOffset position);
class Scrollable extends StatefulWidget {
const Scrollable({
Key? key,
this.axisDirection = AxisDirection.down,
this.controller,
this.physics,
required this.viewportBuilder, //<---- viewportBuilder
this.incrementCalculator,
this.excludeFromSemantics = false.this.semanticChildCount,
this.dragStartBehavior = DragStartBehavior.start,
this.restorationId,
Copy the code
By putting these elements together, ListWheelViewport can be used. The code is as follows:
class ListWheelViewportDemo extends StatelessWidget {
final List<Color> data = [
Colors.blue[50], Colors.blue[100], Colors.blue[200],
Colors.blue[300], Colors.blue[400], Colors.blue[500],
Colors.blue[600], Colors.blue[700], Colors.blue[800],
Colors.blue[900], Colors.blue[800], Colors.blue[700],
Colors.blue[600], Colors.blue[500], Colors.blue[400],
Colors.blue[300], Colors.blue[200], Colors.blue[100]];@override
Widget build(BuildContext context) {
return Container(
height: 250,
width: 320,
child: Scrollable(
axisDirection: AxisDirection.down,
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
viewportBuilder: (ctx, position) => ListWheelViewport(
itemExtent: 50,
offset: position,
childDelegate: ListWheelChildLoopingListDelegate(
children: data.map((e) => _buildItem(e)).toList()),
)),
);
}
Widget _buildItem(Color color) => Container(
alignment: Alignment.center,
color: color,
child: Text(colorString(color),
style: TextStyle(color: Colors.white, shadows: [
Shadow(color: Colors.black, offset: Offset(. 5.. 5), blurRadius: 2))));String colorString(Color color) =>
"#${color.value.toRadixString(16).padLeft(8.'0').toUpperCase()}";
}
Copy the code
Look at what the itemExtent attribute does
itemExtent = 80 | itemExtent = 100 |
---|---|
We have diametrics, sectors, etc. in the hospital
The property name | type | The default value | introduce |
---|---|---|---|
perspective | double | 0.003 | Fluoroscopy parameters 0~0.01 |
squeeze | double | 1.0 | Squeeze the value |
diameterRatio | double | 2.0 | Diameter of the fraction |
1. The perspective of attributes
Perspective means perspective. The default value is 0.003 and ranges from 0 to 0.01.
---->[RenderListWheelViewport]----
static const double defaultPerspective = 0.003;
Copy the code
- This is a
Perspective: 0.01
The effect of
- This is a
Perspective: 0.001
The effect is visibleperspective
The higher the value, the stronger the perspective.
2. Squeeze the properties
Squeeze means squeeze, default is 1.0.
- This is a
Advertisement: 0.8
The effect of
- This is a
Advertisement: 1.5
The effect is visiblesqueeze
I can control itemLoose degree
3. DiameterRatio properties
Diameters, diameters, diameters, diameters, diameters, diameters, diameters, diameters
diameterRatio = 2 | diameterRatio = pi/2 |
---|---|
Other attributes
The property name | type | The default value | introduce |
---|---|---|---|
magnification | double | 1.0 | Zoom ratio |
useMagnifier | bool | false | Whether the zoom |
clipBehavior | Clip | Clip.hardEdge | Clipping behavior |
renderChildrenOutsideViewport | bool | false | Out of view whether render |
offAxisFraction | double | 0.0 | Axis center offset ratio |
overAndUnderCenterOpacity | double | 1 | Transparency outside the amplifier |
1. Magnification effect
This component has the following magnification effects, which are controlled by Magnification and useMagnifier.
@override
Widget build(BuildContext context) {
return Container(
height: 250,
width: 320,
child: Scrollable(
axisDirection: AxisDirection.down,
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
viewportBuilder: (ctx, position) => ListWheelViewport(
perspective: 0.008,
squeeze: 1,
diameterRatio: 2,
itemExtent: 50,
useMagnifier: true,
magnification: 2,
offset: position,
childDelegate: ListWheelChildLoopingListDelegate(
children: data.map((e) => _buildItem(e)).toList()),
)),
);
}
Copy the code
2. Out-of-bounds rendering and clipping
By default, the item is not in sight area will not apply colours to a drawing, can pass renderChildrenOutsideViewport: true to its display, pay attention to ClipBehavior at this time must be a Clip. None. The effect is as follows:
@override
Widget build(BuildContext context) {
return Container(
height: 250,
width: 320,
child: Scrollable(
axisDirection: AxisDirection.down,
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
viewportBuilder: (ctx, position) => ListWheelViewport(
perspective: 0.008,
squeeze: 1,
diameterRatio: 2,
renderChildrenOutsideViewport: true,
clipBehavior: Clip.none,
itemExtent: 50,
offset: position,
childDelegate: ListWheelChildLoopingListDelegate(
children: data.map((e) => _buildItem(e)).toList()),
)),
);
}
Copy the code
3. offAxisFraction
和 overAndUnderCenterOpacity
attribute
OffAxisFraction: 0.2 effect
OverAndUnderCenterOpacity: 0.4 effect
Four, based onListWheelViewport
Implemented components
1. ListWheelScrollView
component
The underlying implementation is based on _FixedExtentScrollable(subclass Scrollable) and ListWheelViewport, which has the ability to listen for sliding items in addition to the viewport. Below, the color of the small circle above is determined by selecting the color of the scroll wheel below. The related properties of ListWheelViewport are the same in ListWheelScrollView.
class CustomListWheelScrollView extends StatefulWidget {
@override
_CustomListWheelScrollViewState createState() =>
_CustomListWheelScrollViewState();
}
class _CustomListWheelScrollViewState extends State<CustomListWheelScrollView> {
var data = <Color>[
Colors.orange[50], Colors.orange[100], Colors.orange[200],
Colors.orange[300], Colors.orange[400], Colors.orange[500],
Colors.orange[600], Colors.orange[700], Colors.orange[800],
Colors.orange[900]]. Color _color = Colors.blue;@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildCircle(),
Container(
height: 150,
width: 300,
child: ListWheelScrollView.useDelegate(
childDelegate: ListWheelChildLoopingListDelegate(
children: data.map((e) => _buildItem(e)).toList()),
perspective: 0.006,
itemExtent: 50, onSelectedItemChanged: (index) { setState(() => _color = data[index]); },),),],); } Widget _buildCircle() => Container( margin: EdgeInsets.only(bottom:5),
width: 30,
height: 30,
decoration: BoxDecoration(color: _color, shape: BoxShape.circle),
);
Widget _buildItem(Color color) {
return Container(
key: ValueKey(color),
alignment: Alignment.center,
height: 50,
color: color,
child: Text(
colorString(color),
style: TextStyle(color: Colors.white, shadows: [
Shadow(color: Colors.black, offset: Offset(. 5.. 5), blurRadius: 2)))); }String colorString(Color color) =>
"#${color.value.toRadixString(16).padLeft(8.'0').toUpperCase()}";
}
Copy the code
2. CupertinoPicker
component
CupertinoPicker’s internal source code implementation relies on ListWheelScrollView. So ListWheelViewport was responsible for the final effect.
class CustomCupertinoPicker extends StatelessWidget {
final names = [
'Java'.'Kotlin'.'Dart'.'Swift'.'C++'.'Python'."JavaScript"."PHP"."Go"."Object-c"
];
@override
Widget build(BuildContext context) {
return Container(
height: 150,
width: 300,
child: CupertinoPicker(
backgroundColor: CupertinoColors.systemGrey.withAlpha(33),
diameterRatio: 1,
offAxisFraction: 0.2,
squeeze: 1.5,
itemExtent: 40,
onSelectedItemChanged: (position) {
print('Current entry${names[position]}'); }, children: names.map((e) => Center(child: Text(e))).toList()), ); }}Copy the code
3. CupertinoDatePicker
component
CupertinoDatePicker is internally based on the CupertinoPicker implementation.
class CustomCupertinoDatePicker extends StatefulWidget {
@override
_CustomCupertinoDatePickerState createState() =>
_CustomCupertinoDatePickerState();
}
class _CustomCupertinoDatePickerState extends State<CustomCupertinoDatePicker> {
DateTime _date = DateTime.now();
@override
Widget build(BuildContext context) {
return Container(
width: 350,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Current date:${_date.toIso8601String()}',
style: TextStyle(color: Colors.grey, fontSize: 16),
),
_buildInfoTitle('CupertinoDatePickerMode.dateAndTime'),
buildPicker(CupertinoDatePickerMode.dateAndTime),
],
),
);
}
Container buildPicker(CupertinoDatePickerMode mode) {
return Container(
margin: EdgeInsets.all(10),
height: 150,
child: CupertinoDatePicker(
mode: mode,
initialDateTime: DateTime.now(),
minimumYear: 2018,
maximumYear: 2030,
use24hFormat: false,
minuteInterval: 1,
backgroundColor: CupertinoColors.white,
onDateTimeChanged: (date) {
print(date); setState(() => _date = date); },),); } Widget _buildInfoTitle(info) {return Padding(
padding: const EdgeInsets.only(left: 20, top: 20, bottom: 5),
child: Text(
info,
style: TextStyle(
color: Colors.blue, fontSize: 16, fontWeight: FontWeight.bold), ), ); }}Copy the code
4. Summary
In this way, the wheel-related components, traced back to their origins, are related to ListWheelViewport. So knowing the meaning of the properties of ListWheelViewport makes it easier to understand the other derived components. This is the same, should change. Maybe one day you’ll come across some kind of custom wheel effect, and ListWheelViewport will help you do that.
[1] ListWheelScrollView is implemented based on Scrollable + ListWheelViewport. [2] CupertinoPicker is implemented based on ListWheelScrollView. [3] CupertinoDatePicker is implemented based on CupertinoPicker.Copy the code