The past and present life of this article
I got this article out of my draft box, and it’s a little bit of history, but let me tell you a little bit about my history with Flutter.
The first contact with Flutter was at the beginning of 2019. At that time, the company’s product App was developed using the framework of Uni-app. At that time, the users of Uni-app were relatively small, the community was not perfect, and the nature of Uni-app itself was web, which led to some performance problems in the long list of apps. For those of you who didn’t do Android and IOS development, my Leader and I later did some technical research, and we turned our attention to the mobile cross-end framework dark horse Flutter. Later, we resolutely used The Flutter to re-develop the App. At that time, THE Leader and I were not used to the first contact with Flutter. However, we had no way out when we were ordered in a crisis. It took us nearly two weeks from writing the first line of DART code to completing the development of the entire App. Two days in front of the familiar with new code style and development mode, slowly to fit into the ball, often develop late into the night, with two weeks to quickly learn a new framework as well as the actual combat, this two weeks and I feel the most fulfilling the year time, practice is the only way to truth, is also the most effective way to (salute those who struggle of years).
Since the launch of the revitalized App, performance and user experience have been greatly improved.
What are the antecedents of this passage?
Since then, various aspects of the App have been optimized, and some new apps have been developed with Flutter, and the understanding of Flutter has been deepened. Until I moved to a new company, I didn’t use Flutter much, so I felt a little rusty. One day, I suddenly remembered it, and my face turned red. I felt like I was thinking of my ex-girlfriend, so I wrote a Music App on my whim. During some sudden want to record down the idea, there is this article, yes, this is a miscellany of thoughts, no system, think of where to say. Therefore, it has not been sent out before, and now I think that knowledge is used to share, if it solves the problem that is bothering some users, it may be the best destination for this article, at least to see the light of day.
The consequences?
This article may be described in some places will be relatively simple, the author will try to warm up and continue to update and optimize this miscellaneous book!!
What wrong place welcome big guy to testify, really haven’t written Flutter for a long time!
Start the text!
Some tips on kinetic effects
The animation value is 0-1
The majority of the effect (prevent the face), the process is from 0 to 1, this is a bit abstract, most Wudang disciples do not understand that tai Chi produces two yi, two yi produces four xiang, four xiang produces eight diagrams (how the eight diagrams evolve I do not know)… The true meaning of that Zhang Sanfeng and others can understand the essence of it, the achievement of the master, just around the corner. Digress…
For example:
- 0 goes to 600 is 0 minus 1, right? // 0*600-1*600
Little xia?
get?
Just touch it…
1. Initialize the function
class Demo extends StatelessWidget{
Demo(){
doSomething()
}
}
class Demo extends StatefulWidget{
@override
_DemoState createState = > _DemoState();
}
class _DemoState extends extends State<Demo>{
_DemoState(){
print('_DemoState first ');
doSomething();
}
@override
void initState(){
print('initState first ');
super.initState();
}
/ / the result
// _DemoState is output first
// initState first
}
Copy the code
2. Use Model as much as possible
- Using model parameters can detect errors in the program 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 the code
3.ClipOval component to make different layers of pictures in the same layer display effect, look at the section of code
// Use Stack to place the image in the hierarchy
Stack:[
Picture1(),
Picture2()
]
// This will only show Picture2.Stack: [Picture1 (), ClipOval (clipper: CircleRevealClipper (parameters), the child: Picture2 ()))class CircleRevealClipper extends CustomClipper<Rect>{
final double param;
CircleRevealClipper(this.param);
@override
Rect getClip(Size size) {
// Here draw the cut shape (route)
}
@override
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
// TODO: implement shouldReclip
return true; }}Picture1 and Picture2 are displayed at the same time.
Copy the code
4. Usually fixed values are accepted with all capital English variables
// Good at reading
final BUBBLE_WIDTH = 55.0;
Copy the code
5. Use Transform to make simple animations
varTranslation = value; Transform( transform: Matrix4.translationValues(translation,0.0.0.0), the child: Widget ()) with AnimationController completionAnimationController =newAnimationController( duration: duration, vsync: vsync, ) .. addListener(() {print(completionAnimationController.value);
/ / completionAnimationController. The value value of 0-1
}
Copy the code
6. How to use enumeration values
enum SlideDirection { leftToRight, rightToLeft, none }
SlideDirection direction = SlideDirection.leftToright;
Copy the code
7. The process from transparency to display can use the Opacity component, which is also a 0-1 process.
8. One of the ways to implement top-level gesture events
Stack:[
page(),
GestureDetector(
onHorizontalDragStart: onDragStart, // Touch the screen
onHorizontalDragUpdate: onDragUpdate, // Touch the screen and swipe
onHorizontalDragEnd: onDragEnd, // Leave the screen
);
]
Copy the code
9. About the basic use of classes
class Demo{
final double value;
Demo({
this.value
}){
// Initialize the function
print('execution');
}
fn1(){
/ / the method body
}
fn2(){
/ / the method body}}/ / use
Demo a = new Demo();
a.fn1();
a.fn2();
Copy the code
10. About using 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 the listener
slideUpdateStream.stream.listen((Demo d){
// doSomething...}}})/ / triggers
class Trigger extends StatelessWidget{
StreamController<Demo> demo;
Trigger(){
/ / triggers
demo.add(new Demo())
}
}
Copy the code
11. Other small uses of SizeBox
Spacing between elements (some of which are flexible) can be implemented using SizeBox to avoid nesting again.
- There is a spacing of 20.0 between the two elements
Row(
children:[
A(),
SizeBox(
width:20.0
),
B()
...
]
)
Copy the code
12. On the use of position.fill () in a Stack
Position.fill() will fill the Stack
Stack(
children:[
Text("Try to stop me, boy?"),
Position.fill(
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
child:Text('I'm young, but my dad can't see the sun.')))Copy the code
13.PageView A very handy list of scrolling views (a simple version of the playround)
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(() {
// Note that the controller. Page value here is what I call the process value, not the result value, such as from page 0 to page 1, or from 0.000to 0.99 to 1.0
// And when the slide does not go to the next page, the value will bounce back (0.1-0.3-0.45-0.2-0.0). This feature can be used to achieve a rebound animation effect.
setState(() {
currentPage = controller.page;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// For more information, please refer to Baidu
body:PageView.builder(
itemCount: images.length,
controller: controller,
reverse: true,
itemBuilder: (context, index) {
returnContain( ... ) }))}Copy the code
14. The use of FittedBox
The FittedBox will scale and position the child within its size range so that the child fits its size. The Fit property of the FittedBox is a bit like the background-size property used when writing CSS (it feels like children are being laid out as images).
Container(
color: Colors.amberAccent,
width: 300.0,
height: 300.0,
child: new FittedBox(
fit: BoxFit.contain,
alignment: Alignment.topLeft,
child: new Container(
color: Colors.red,
child: new Text("FittedBox"),),),),Copy the code
15. The use of AspectRatio
AspectRatio will first expand as much as the layout constraints allow. The height of the widget is determined by the width and ratio. The height and width values are roughly the same as the code below
if{height = width / _aspectRatio; width = constraints.maxWidth; }else if(height limit) {height = constraints. MaxHeight; width = height * _aspectRatio; }else{
height = constraints.maxHeight;
width = constraints.maxWidth;
}
Copy the code
Note: The aspectRatio attribute cannot be empty
AspectRatio is used for views that require a fixed ratio between the height and width.
16. The use of ConstrainedBox
It can be simply understood as a container with limits to height and width, such as setting maximum height, minimum height, maximum width, 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: Colors.red,
),
);
Copy the code
The final displayed child is 200 in height, 250 in width, and just so.
17.RepaintBoundary component can achieve screenshot effect
Use RepaintBoundary to wrap the part that you want to cut (controlled by key). RenderRepaintBoundary takes out the part that RepaintBoundary wraps and converts it into ui.image object by.toimage () method. The image is then converted toByteData using.tobytedata (). Finally, it is stored as File objects via File(‘ path ‘).writeasBytes (byteData). Look at the code:
GlobalKey rootWidgetKey = GlobalKey();
List<Uint8List> images = List(a); _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(Icons.camera),
tooltip: 'capture',
onPressed: () async {
await this._interceptPng();
},
),
body: Column(
children: <Widget>[
RepaintBoundary(
key: rootWidgetKey,
child: Container(
height:100.0,
width:30.0,
color:Colors.green
)
),
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 the code
18. Use of the CircleAvatar component
If you look at the meaning of the English words, you can see that you can use this component to achieve the effect of a round head. However, you need to set the backgroundImage or backgroundColor property to achieve the circular effect. The Child property can be thought of as setting the Widgets on top of the avatar. Look at the code:
CircleAvatar(
radius: 40.0,
backgroundColor: Colors.red,
child: Text("test"),Copy the code
Use of the IndexedStack component
The IndexedStack inherits from the Stack and is used to display the index child component. The other child components are not visible, but the state of all components is preserved. (You can also do this with the OffStage component, but they are expensive. All child components are instantiated during page load initialization.
IndexedStack(
index: currentIndex, // The index displayed
children: widgetList, // Subcomponent list
)
Copy the code
20. AutomaticKeepAliveClientMixin class
WantKeepAlive: wantKeepAlive: wantKeepAlive: wantKeepAlive: wantKeepAlive: true;
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> with AutomaticKeepAliveClientMixin {
// Overwrite properties can be generated directly by the plugin via error repair prompt, and the corresponding value can be changed
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
...
}
Copy the code
21.InheritedWidget
Updating…