Knowledge points of "Flutter" that you may not know will continue to be updated...

Knowledge points of "Flutter" that you may not know will continue to be updated...

The past and present of this article

I picked up this article from the draft box. It's a bit historical. Let's talk about some of the "relationships" between me and Flutter .

First contact

At the beginning of 2019, when the company s product App used
This framework was developed at that time
There are still relatively few users, the community is not complete enough, and the nature of the web itself, resulting in some performance problems in the long list of App , due to the insufficient technical team
Development classmates, after doing some technical research with Leader , I turned my attention to the dark horse of mobile cross-end framework at that time.
Above, we decided to use
Of App redevelopment. First contact
I m not used to it, but when I m in danger, I have no retreat. I start writing the first line.
It took the Leader and I for nearly 2 weeks from the start of the code to the completion of the entire App development . In the first two days, I was familiar with the new code style and development model. I slowly started to get through it all the way. I often developed into the night. I used two weeks to quickly learn a new framework and actual combat. These two weeks are also the most fulfilling of my year. In time, practice is the only way to test the truth, and it is also the most effective way (pay tribute to the years of struggle).

After the reborn App was launched , the performance and user experience have been greatly improved.

The antecedent of the origin of this article?

Later, the App has been optimized in all aspects one after another , and at the same time

Developed some new apps , right
The understanding is deepened day by day. Until later, I changed to a new company, basically I didn t use it
, So I felt a little bit of a wasteful day. One day I suddenly thought of it, my old face blushed, and I thought of my ex-girlfriend, so I wrote a Music App on a whim . During the period, there were some thoughts that I suddenly wanted to record, so I came up with this article. Yes, this is a miscellaneous book of thoughts, which is not systematic. Therefore, it has not been sent out before. Now I think that knowledge is used to share . In case it solves the problem that is plagued by a code friend, it may be the best of this article to give the code friend a little bit of harvest. Home, at least see the sun again.

What about the consequences?

Some parts of this article may be simpler, the author will try to review the past and continue to update and optimize this miscellaneous book! ! !

If there is any mistake, the big guys are welcome to testify, it's really been a long time since I wrote Flutter !

The text begins!

Some tips on animation

The animation value of animation is 0-1

Most of the effects (to prevent face beating), the process is from 0-1, this is a bit abstract, most Wudang disciples did not understand that Taiji produces two yis, two yis produce four elephants, and four elephants produce gossip. I don't know)... the true meaning of..., Zhang Sanfeng and others will be able to realize the essence and become a master, just around the corner. Far away...

To make an analogy:

  • If 0 moves horizontally to 600, is it 0-1?//0*600-1*600 Is there a problem?

Young man?


Click to end...

1. Initialization function

class Demo extends StatelessWidget { Demo(){ doSomething() } } class Demo extends StatefulWidget { @override _DemoState createState => _DemoState(); } class _DemoState extends extends State < Demo > { _DemoState(){ print ( '_DemoState output first' ); doSomething(); } @override void initState(){ print ( 'initState enter first' ); super .initState(); } //Result //_DemoState is output first //initState is input first } Copy code

2. Try to use Model to pass parameters

  • Using model to pass parameters can find errors in the program about parameter passing errors when the program is compiled.
class DemoModel { final Color color; final String title; DemoModel( this .color, this .title); } class Demo extends StatelessWidget { final DemoModel model; Demo({ this .model}) } Copy code

3. The ClipOval cutting component makes different layers of pictures displayed on the same layer, look at the code

//Use Stack to put pictures into the hierarchy Stack:[ Picture1(), Picture2() ] //Only Picture2 can be seen in this way, let's modify the code... Stack:[ Picture1(), ClipOval( clipper: CircleRevealClipper (parameter), child:Picture2() ) ] class CircleRevealClipper extends CustomClipper < Rect > { final double param; CircleRevealClipper( this .param); @override Rect getClip(Size size) { //Draw the cutting shape (route) here } @override @override bool shouldReclip (CustomClipper<Rect> oldClipper) { //TODO: implement shouldReclip return true ; } } //So Picture1 and Picture2 can be displayed at the same time. Copy code

4. Usually fixed values are accepted in all English capital variables

//strong readability final BUBBLE_WIDTH = 55.0 ; copy the code

5. Use Transform to do simple animation

var translation = value; Transform( transform: Matrix4.translationValues(translation, 0.0 , 0.0 ), child: Widget() ) Cooperate with AnimationController completionAnimationController = new AnimationController( duration: duration, vsync: vsync, ) ..addListener(() { print (completionAnimationController.value); //completionAnimationController.value is 0-1 } Copy code

6. About the use of enumeration values

enum SlideDirection {leftToRight, rightToLeft, none} SlideDirection direction = SlideDirection.leftToright; Copy code

7. The process from transparent to display can use Opacity components, which is also a 0-1 process.

8. One of the ways to realize the top-level gesture event

Stack:[ page(), GestureDetector( onHorizontalDragStart: onDragStart, //touch the screen onHorizontalDragUpdate: onDragUpdate, //touch the screen and slide onHorizontalDragEnd: onDragEnd, //leave the screen ); ] Copy code

9. About the basic use of the class

class Demo { final double value; Demo({ this .value }){ //Initialization function print ( 'execute' ); } fn1(){ //method body } fn2(){ //Method body } } //use Demo a = new Demo(); a.fn1(); a.fn2(); Copy code

10. About the use of StreamController

class Demo { final double value; Demo( this .value); } class Example extends StatefulWidget { @override _ExampleState createState => _ExampleState(); } class _ExampleState extends State < Example > { StreamController<Demo> slideUpdateStream; _ExampleState(){ slideUpdateStream = new StreamController<Demo>(); //Set up monitoring d){ //doSomething... }) } } //Trigger class Trigger extends StatelessWidget { StreamController<Demo> demo; Trigger(){ //Trigger demo.add( new Demo()) } } Copy code

11. Other small usages about SizeBox

The spacing between elements (flexible in some cases) can be implemented using SizeBox to avoid nesting again.

  • 20.0 spacing between two elements
Row( children:[ A(), SizeBox( width: 20.0 ), B() ... ] ) Copy code

12. About the use of Position.fill() in Stack

Position.fill() will fill up the Stack

Stack( children:[ Text( "Boy, want to block me?" ), Position.fill( //It should be noted here that there must be a child for Position.fll to take effect and be a father! ! ! child:Text( 'I am young, but my father covers the sky and the sun' ) ) ] ) Copy code

13. PageView a very easy to use scroll view list (simple version of the carousel)

class Example extends StatefulWidget { @override _ExampleState createState() => _ExampleState(); } class _ExampleState extends State < Example > { var currentPage = 1.0 ; PageController controller = PageController(initialPage: 0 ); @override void initState() { //TODO: implement initState controller.addListener(() { //It is worth noting that the value of here is what I call a process value, not a result value. For example, from page 0 to page 1, it is from 0.000-0.99-1.0 //and when the slide does not slide to On the next page, the value will rebound (0.1-0.3-0.45-0.2-0.0) to use this feature to achieve a rebound animation effect. setState(() { currentPage =; }); }); super .initState(); } @override Widget build(BuildContext context) { return Scaffold( //For more usage, please Baidu by yourself body:PageView.builder( itemCount: images.length, controller: controller, reverse: true , itemBuilder: (context, index) { return Contain( ... ) } ) ) } } Copy code

14. Use of FittedBox

FittedBox will scale within its own size range and adjust the position of the child so that the child fits its size. The fit attribute of FittedBox is a bit like the background-size attribute when writing CSS (it feels that the child elements are laid out as pictures).

Container( color: Colors.amberAccent, width: 300.0 , height: 300.0 , child: new FittedBox( fit: BoxFit.contain, alignment: Alignment.topLeft, child: new Container( color:, child: new Text( "FittedBox" ), ), ), ), Copy code

15. Use of AspectRatio

AspectRatio will first expand as much as possible within the range allowed by the layout restrictions. The height of the widget is determined by the width and the ratio. The height and width values are roughly calculated by the following code

if (width is limited) { height = width/_aspectRatio; width = constraints.maxWidth; } else if (height is limited) { height = constraints.maxHeight; width = height * _aspectRatio; } else { height = constraints.maxHeight; width = constraints.maxWidth; } Copy code

Note: the aspectRatio attribute cannot be empty

Generally, AspectRatio is used for views that require a fixed ratio of height and width.

16. Use of ConstrainedBox

It can be simply understood as a container limited to height and width, such as setting the maximum height, minimum height, maximum width, and minimum width. Look at the code:

ConstrainedBox( constraints: const BoxConstraints( minWidth: 220.0 , minHeight: 100.0 , maxWidth: 250.0 , maxHeight: 150.0 , ), child: new Container( width: 300.0 , height: 200.0 , color:, ), ); Copy code

The final displayed child element is 200 high and 250 wide, just so.

17.RepaintBoundary component can achieve screenshot effect

With RepaintBoundary partially encased wish to capture (by the key control), RenderRepaintBoundary the RepaintBoundary portion taken out of the package, and then converted by methods .toImage () is ui.Image object and use .toByteData () the image into byteData. Finally, it is stored as a file object through File('path').writeAsBytes(byteData). Look at the code:

GlobalKey rootWidgetKey = GlobalKey(); List <Uint8List> images = List (); _interceptPng() async { try { RenderRepaintBoundary boundary = rootWidgetKey.currentContext.findRenderObject(); var image = await boundary.toImage(pixelRatio: 3.0 ); ByteData byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData.buffer.asUint8List(); images = [pngBytes]; setState((){}) //Or save the picture //File('path').writeAsBytes(pngBytes); } catch (e) { print (e); } } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text( 'RepaintBoundary Demo' ), ), floatingActionButton: FloatingActionButton( child: const Icon(, tooltip: 'Screenshot' , onPressed: () async { await this ._interceptPng(); }, ), body: Column( children: <Widget>[ RepaintBoundary( key: rootWidgetKey, child: Container( height: 100.0 , width: 30.0 , ) ), Expanded( child: ListView.builder( itemBuilder: (context, index) { return Image.memory( images[index], width: 100.0 , height: 200.0 , ); }, itemCount: images.length, scrollDirection: Axis.vertical, ), ) ], ), ), ) } Copy code

18. Use of CircleAvatar component

Looking at the meaning of English words, you can also see that this component can achieve the effect of a round head portrait. But you need to set the backgroundImage or backgroundColor property to achieve the circular effect. The child property can be understood as setting widgets on the upper layer of the avatar. Look at the code:

CircleAvatar( radius: 40.0 , backgroundColor:, child: Text( "test" ), ) Copy code

19. The use of IndexedStack components

IndexedStack inherits from Stack , the function is to display the index child component, other child components are invisible, but the state of all components will be maintained (the OffStage component can also be used to maintain the state, but their disadvantage is that the cost is relatively large , All child components will be instantiated when the page is loaded and initialized).

IndexedStack( index: currentIndex, //displayed index children: widgetList, //list of child components ) Copy code

20.AutomaticKeepAliveClientMixin class

The role of this class is to maintain the state of the page. We can let the page inherit this class and override wantKeepAlive to true. The code is as follows:

class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState(); } class _TestPageState extends State < TestPage > with AutomaticKeepAliveClientMixin { //Rewriting attributes can generally be directly generated through the error repair prompt plug-in, and the corresponding value can be modified @override bool get wantKeepAlive => true ; @override void initState() { super .initState(); } @override Widget build(BuildContext context) { ... } Copy code