1. Theme color setting
class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo',//Available for Android theme: ThemeData( primarySwatch: Colors.yellow,//Theme color setting, dark: time and battery color are white; light: time and battery color are black highlightColor: Color.fromRGBO(1, 0, 0, 0.0),//Remove the default selection effect of tabBar splashColor: Color.fromRGBO(1, 0, 0, 0.0),//Remove the default selection effect of tabBar ), home: RootPage(), ); } }
2. Remove iPhone x bangs from listview
MediaQuery.removePadding -> removeTop: true
Container( color: Color.fromRGBO(220, 220, 220, 1.0), child: MediaQuery.removePadding( removeTop: true, context: context, child: ListView( children: <Widget>[ Container( color: Colors.white, height: 200, ), SizedBox(height: 10,), DiscoverCell(imageName: 'images/Wechat payment 1.png',title: 'payment',), ], ), ), ),
3.Image setting fillet
Row( children: <Widget>[ Container( width: 70, height: 70, // child: Image(image: AssetImage('images/Steven.png ',), / / it is invalid to set fillet here decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10.0), image: DecorationImage(image:AssetImage('images/Steven.png'), fit: BoxFit.cover)//Set the fill mode for pictures ), ),//head portrait Container(),//Right section ], )
Set up a circular picture
CircleAvatar( backgroundImage: new AssetImage('images/1.jpeg'), radius: 100.0, )
4. Width and height acquisition of equipment
width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height,
5. Setting of text center direction
//Container properties alignment: Alignment.centerLeft,
6. Loading of network pictures and local pictures
Container( width: 34, height: 34, margin: EdgeInsets.all(10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(6.0), image: DecorationImage( image: imageUrl != null ? NetworkImage(imageUrl) //Network picture : AssetImage(imageAssets),//Local picture )), )
7. Chain programming - adding data
@override //Data and object creation void initState() { super.initState(); //Chain programming, call addAllData twice and return the array to_ listDatas _listDatas..addAll(datas)..addAll(datas); //Data sorting _listDatas.sort((Friends a, Friends b){ return a.indexLetter.compareTo(b.indexLetter); }); //print('_listDatas:$_listDatas'); }
8. Division and rounding
~/
onVerticalDragUpdate: (DragUpdateDetails details){ print(details.globalPosition.dy);//Values relative to the entire screen RenderBox box = context.findRenderObject(); //Calculate the coordinate conversion of the current position and calculate the y value double y = box.globalToLocal(details.globalPosition).dy; //The y value divided by the height of each item is the current index //Height of each item var itemH = ScreenHeight(context)/2/INDEX_WORDS.length; int index = y ~/ itemH;//Divide and round print(box.globalToLocal(details.globalPosition)); },
9. Array out of bounds processing
//Using clamp //Value range 0~INDEX_WORDS.length-1 add safety judgment int index = (y ~/ itemHeight).clamp(0, INDEX_WORDS.length - 1);
10. Define callback functions and calls
//Define callback function final void Function(String str) indexBarCallBack; //Construction method const IndexBar({Key key, this.indexBarCallBack}) : super(key: key); //Call the callBack //Monitor location: calculate the current location onVerticalDragUpdate: (DragUpdateDetails details){ widget.indexBarCallBack(getIndex(context, details.globalPosition)); }, //External use IndexBar( indexBarCallBack: (String str){ print("I got it: $str"); }, ),
11.PopupMenuButton
Container( margin: EdgeInsets.only(right: 10), child: PopupMenuButton( offset: Offset(0, 60.0), child: Image(image: AssetImage('images/Circle plus.png'),width: 25,), itemBuilder: _buildPopupMenuItem, ), ) //How to create an Item! PopupMenuItem<String> _buildItem(String imgAss, String title) { return PopupMenuItem( child: Row( children: <Widget>[ Image( image: AssetImage(imgAss), width: 20, ), Container( width: 20, ), Text( title, style: TextStyle(color: Colors.white), ), ], ), ); } //Callback method List<PopupMenuItem<String>> _buildPopupMenuItem(BuildContext context) { return <PopupMenuItem<String>>[ _buildItem('images/Initiate group chat.png', 'Initiate group chat'), _buildItem('images/Add a friend.png', 'Add a friend'), _buildItem('images/Sweep 1.png', 'scan'), _buildItem('images/Collection and payment.png', 'Collection and payment'), ]; }
Set pop background color
//MaterialApp -> theme -> cardColor MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo',//Available for Android theme: ThemeData( primarySwatch: Colors.yellow,//Theme color setting, dark: time and battery color are white; light: time and battery color are black highlightColor: Color.fromRGBO(1, 0, 0, 0.0),//Remove the default selection effect of tabBar splashColor: Color.fromRGBO(1, 0, 0, 0.0),//Remove the default selection effect of tabBar cardColor: Color.fromRGBO(1, 1, 1, 0.65),//Set pop background color ), home: RootPage(), )
design sketch:
PopupMenuButton
12. Slide ListView to make keyboard disappear
FocusScope.of(context).requestFocus(FocusNode());
//Listen to the ListView's slide event and make the keyboard disappear Expanded( flex: 1, //Occupy the remaining space child: MediaQuery.removePadding( context: context, removeTop: true, child: NotificationListener( onNotification: (ScrollNotification note){ FocusScope.of(context).requestFocus(FocusNode()); },//Slide to make the keyboard disappear child: ListView.builder( itemCount: _models.length, itemBuilder: _itemForRow, ), ), ), )
13. Contact set partial fillet and shadow effect
@override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(top: 10, bottom: 10), decoration: BoxDecoration( color: Colors.white, // Set the shadow to add a contact outside the clipping, otherwise it will be invalid boxShadow: [ BoxShadow( color: Color(0xff333333).withOpacity(0.05), offset: Offset(0, 1.0), blurRadius: 5), ], ), child: new ClipRRect( // Set local fillet borderRadius: BorderRadius.only( bottomLeft: Radius.circular(5), bottomRight: Radius.circular(5), ), child: Container( height: ScreenUtil().setHeight(147), child: Container( margin: EdgeInsets.only(left: 40, right: 40), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: navigatorList.map((item) { return _navigatorItem(context, item); }).toList(), ), ), ), ), ); }
14. Remove the bottom shadow from the app bar of scaffold
return Scaffold( appBar: AppBar( backgroundColor: Colors.white, centerTitle: true, title: Text( "find", style: TextStyle( color: Color(0xff333333), fontSize: ScreenUtil().setSp(34)), ), bottomOpacity: 0, elevation: 0, // Remove bottom shadow ), );
other
@override Widget build(BuildContext context) { return Scaffold( //Head elements such as: left return button middle title right menu appBar: AppBar( title: Text('Scaffold Example of scaffold components'), ), //The content part of the view is usually the main display area of the application page body: Center( child: Text('Scaffold'), ), //Bottom navigation bar bottomNavigationBar: BottomAppBar( child: Container(height: 50.0,), ), //Add FAB button floatingActionButton: FloatingActionButton( onPressed: () {}, tooltip: 'increase', child: Icon(Icons.add), ), //FAB button center display floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, );
15.Image image setting width adaptation
Container( margin: EdgeInsets.only(left: 15, right: 15), height: ScreenUtil().setHeight(243), decoration: BoxDecoration( image: DecorationImage( image: NetworkImage( 'http://fdfs.xmcdn.com/group63/M0A/99/95/wKgMaFz_RD-BDyFjAAIO0iRtj0U176.jpg'), fit: BoxFit.fitWidth, alignment: Alignment.topCenter, )), ),
16.FlutterListView nested GridView rolling conflict
Both ListView and GirdView are scrolling widgets. If two widgets are nested, there will be scrolling conflicts. The solution is as follows
body: new ListView( shrinkWrap: true, padding: EdgeInsets.all(0), children: <Widget>[ new GridView.count( padding: EdgeInsets.all(0), physics: new NeverScrollableScrollPhysics(),//increase shrinkWrap: true,//increase crossAxisCount: 3, children:<Widget>[] ], ),
① Processing listview nesting error
shrinkWrap: true,
② Handle sliding parent in GridView Listview cannot slide
physics: new NeverScrollableScrollPhysics();
17. Tailor TabBar and modify indiator width
1. Key code
import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class FriendsList extends StatefulWidget { @override _FriendsListState createState() => _FriendsListState(); } class _FriendsListState extends State<FriendsList> with SingleTickerProviderStateMixin { TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(initialIndex: 0, length: 2, vsync: this); } @override void dispose() { super.dispose(); _tabController.dispose(); } @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: Container( height: ScreenUtil().setHeight(73), alignment: Alignment.topLeft, child: TabBar( tabs: [ Tab(text: 'Friends'), Tab(text: 'Beckoning'), ], controller: _tabController, indicatorWeight: 2, indicatorPadding: EdgeInsets.only(left: 10, right: 10), labelPadding: EdgeInsets.symmetric(horizontal: 10), isScrollable: true, indicatorColor: Color(0xffFF7E98), labelColor: Color(0xffFF7E98), labelStyle: TextStyle( fontSize: ScreenUtil().setSp(36), color: Color(0xffFF7E98), fontWeight: FontWeight.w500, ), unselectedLabelColor: Color(0xffAAAAAA), unselectedLabelStyle: TextStyle( fontSize: ScreenUtil().setSp(32), color: Color(0xffAAAAAA)), indicatorSize: TabBarIndicatorSize.label, )), backgroundColor: Colors.white, elevation: 0, ), body: TabBarView( children: [ Container( child: Center( child: Text("Friends page"), ), ), Container( child: Center( child: Text("Heartbeat page"), ), ), ], controller: _tabController, ), ), ); } }
2. Renderings
Renderings.gif
18 the fluro plug-in implements the appBar without the return key
Application.router.navigateTo(context, "/index",replace: true);
19. Word overflow processing
①Expanded + TextOverflow.ellipsis Set ellipsis
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("LayoutPage")), body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon( Icons.star, size: 16.0, color: Colors.grey, ), Padding(padding: new EdgeInsets.only(left: 5.0)), Expanded( child: Text( "100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000", style: new TextStyle(color: Colors.grey, fontSize: 14.0), // Set ellipsis overflow: TextOverflow.ellipsis, // Set the maximum number of rows maxLines: 1, ), ) ], ), ), ); }
② Expanded + TextOverflow.ellipsis No effect
adopt
- Limit Container width
- Row layout nested Expanded to add constraints
TextOverflow.ellipsis No effect
20. Key do of data analysis error reporting
do is the key, cannot be set as the property of Model, and should be replaced with another name
class UserChatList { int doType; UserChatList({this.doType}); UserChatList.fromJson(Map<String, dynamic> json) { doType = json['do']; }
21. Build chat message UI
design sketch
Chat message U
thinking
- ① Positison settings
right: ScreenUtil().setWidth(20), bottom: -ScreenUtil().setHeight(50),
- ② Stack set overflow display
overflow: Overflow.visible
critical code
///Chat Widget Widget ChatWidget(String chatType, String msg) { // 1 sender if (chatType == 'send') { return Container( decoration: BoxDecoration( color: Colors.white, // Set shadow boxShadow: [ BoxShadow( color: Color(0xffFF7E98), offset: Offset(0, 1), blurRadius: 8, ) ], borderRadius: BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15), bottomRight: Radius.circular(15)), ), height: ScreenUtil().setHeight(80), margin: EdgeInsets.only( top: ScreenUtil().setHeight(40), ), padding: EdgeInsets.only( left: ScreenUtil().setWidth(40), right: ScreenUtil().setWidth(40), top: ScreenUtil().setHeight(10), bottom: ScreenUtil().setHeight(10)), child: Text( msg != null && msg.length > 0 ? msg : '', style: TextStyle( fontSize: ScreenUtil().setSp(30), color: Color(0xff333333)), maxLines: 1, overflow: TextOverflow.ellipsis, ), ); } else if (chatType == 'minisend') { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Stack( overflow: Overflow.visible, children: <Widget>[ // news Container( decoration: BoxDecoration( color: Colors.white, // Set shadow boxShadow: [ BoxShadow( color: Color(0xffFF7E98), offset: Offset(1, 1), blurRadius: 8, ) ], borderRadius: BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15), bottomRight: Radius.circular(15)), ), height: ScreenUtil().setHeight(80), margin: EdgeInsets.only( top: ScreenUtil().setHeight(40), ), padding: EdgeInsets.only( left: ScreenUtil().setWidth(40), right: ScreenUtil().setWidth(40), top: ScreenUtil().setHeight(10), bottom: ScreenUtil().setHeight(10)), child: Text( '😊I really want to know you😊', style: TextStyle( fontSize: ScreenUtil().setSp(30), color: Color(0xff333333)), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Positioned( right: ScreenUtil().setWidth(20), bottom: -ScreenUtil().setHeight(50), child: // Applet path Container( margin: EdgeInsets.only(top: ScreenUtil().setHeight(16)), child: Row( children: <Widget>[ Text( 'Go to the applet to check', style: TextStyle( fontSize: ScreenUtil().setSp(22), color: Color(0xffFF7E98)), ), Icon( MyIcons.sex_boy, size: ScreenUtil().setSp(16), color: Color(0xffFF7E98), ) ], ), ), ), ], ), ], ); } else if (chatType == 'mine') { return Row( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Container( decoration: BoxDecoration( color: Colors.white, // Set shadow boxShadow: [ BoxShadow( color: Color(0xffFF7E98), offset: Offset(0, 1), blurRadius: 8, ) ], // Set gradient gradient: LinearGradient( colors: [Color(0xFFFF7E98), Color(0xFFFD7BAB)], begin: Alignment(-1, -1), end: Alignment(1.0, 0.56), ), // Set fillet borderRadius: BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15), bottomLeft: Radius.circular(15)), ), height: ScreenUtil().setHeight(80), margin: EdgeInsets.only( top: ScreenUtil().setHeight(40), ), padding: EdgeInsets.only( left: ScreenUtil().setWidth(40), right: ScreenUtil().setWidth(40), top: ScreenUtil().setHeight(10), bottom: ScreenUtil().setHeight(10)), child: Text( msg != null && msg.length > 0 ? msg : '', style: TextStyle( fontSize: ScreenUtil().setSp(30), color: Colors.white), maxLines: 1, overflow: TextOverflow.ellipsis, ), ) ], ); } else { return Container( margin: EdgeInsets.only(bottom:ScreenUtil().setHeight(40) ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Stack( overflow: Overflow.visible, children: <Widget>[ Container( decoration: BoxDecoration( color: Colors.white, // Set shadow boxShadow: [ BoxShadow( color: Color(0xffFF7E98), offset: Offset(0, 1), blurRadius: 8, ) ], // Set gradient gradient: LinearGradient( colors: [Color(0xFFFF7E98), Color(0xFFFD7BAB)], begin: Alignment(-1, -1), end: Alignment(1.0, 0.56), ), // Set fillet borderRadius: BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15), bottomLeft: Radius.circular(15)), ), height: ScreenUtil().setHeight(80), margin: EdgeInsets.only( top: ScreenUtil().setHeight(40), ), padding: EdgeInsets.only( left: ScreenUtil().setWidth(40), right: ScreenUtil().setWidth(40), top: ScreenUtil().setHeight(10), bottom: ScreenUtil().setHeight(10)), child: Text( msg != null && msg.length > 0 ? msg : '', style: TextStyle( fontSize: ScreenUtil().setSp(30), color: Colors.white), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), // Applet path Positioned( left: ScreenUtil().setWidth(20), bottom: -ScreenUtil().setHeight(50), child: Container( margin: EdgeInsets.only(top: ScreenUtil().setHeight(16),), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Text( 'Go to the applet to check', style: TextStyle( fontSize: ScreenUtil().setSp(22), color: Color(0xffFF7E98)), ), Icon( MyIcons.sex_boy, size: ScreenUtil().setSp(16), color: Color(0xffFF7E98), ) ], ), ), ), ], ) ], ), ); } }
22. Flutter copy to clipboard
Copy operation through Clipboard
1. Declare the key and specify the key in Scaffold
///Shear Key final clicpBoardKey = new GlobalKey<ScaffoldState>(); return Scaffold( key: clicpBoardKey, );
2. Implement the copy operation and pop up the SnackBar
Clipboard.setData(ClipboardData(text: 'Life is like meeting each other for the first time')); clicpBoardKey.currentState.showSnackBar(SnackBar(content: Text('Copied to clipboard')));
other
Scaffold.of(context).showSnackBar(SnackBar( //Content of prompt message content: Text("display SnackBar"), ));
23.Url escape decode
decodeURIComponent('%2Fpage%2Forigin%2Forigin%3Fuid%3D')
24. Get the size of widget control
- Through Context
- Via GlobalKey
- Via layoutchangednotification (override)
// width width: MediaQuery.of(context).size.width, // height height: MediaQuery.of(context).size.height * 0.05, // Note: context is the context of the parent component
import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; class NewSizeChangedLayoutNotification extends LayoutChangedNotification{ Size size; NewSizeChangedLayoutNotification(this.size); } class NewSizeChangedLayoutNotifier extends SingleChildRenderObjectWidget { const NewSizeChangedLayoutNotifier({ Key key, Widget child, }) : super(key: key, child: child); @override _NewRenderSizeChangedWithCallback createRenderObject(BuildContext context) { return _NewRenderSizeChangedWithCallback( onLayoutChangedCallback: (Size size) { NewSizeChangedLayoutNotification(size).dispatch(context); } ); } } typedef VoidCallbackWithParam = Function(Size size); class _NewRenderSizeChangedWithCallback extends RenderProxyBox { _NewRenderSizeChangedWithCallback({ RenderBox child, @required this.onLayoutChangedCallback, }) : assert(onLayoutChangedCallback != null), super(child); final VoidCallbackWithParam onLayoutChangedCallback; Size _oldSize; @override void performLayout() { super.performLayout(); //Notify after the first layout if (size != _oldSize) onLayoutChangedCallback(size); _oldSize = size; } }
25.decoration
1) Border
// Set 4 borders at the same time: 1px thick black solid line border BoxDecoration( border: Border.all(color: Colors.black, width: 1, style: BorderStyle.solid) ) // Set single border: top border is 1px thick black solid line border, right border is 1px thick red solid line border BoxDecoration( border: Border( top: BorderSide(color: Colors.black, width: 1, style: BorderStyle.solid), right: BorderSide(color: Colors.red, width: 1, style: BorderStyle.solid), ), )
2) Fillet
// Set the fillet of 4 corners to 5 at the same time BoxDecoration( borderRadius: BorderRadius.circular(5), ) // Set single fillet: the fillet in the upper left corner is 5, and the fillet in the upper right corner is 10 BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(5), topRight: Radius.circular(10), ), )
3) Shadow
BoxDecoration( boxShadow: [ BoxShadow( offset: Offset(0, 0), blurRadius: 6, spreadRadius: 10, color: Color.fromARGB(20, 0, 0, 0), ), ], )
4) Gradient
// Linear gradient from left to right, red to blue BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [Colors.red, Colors.blue], ), ) // From center to all around, red to blue radial gradient BoxDecoration( gradient: RadialGradient( center: Alignment.center, colors: [Colors.red, Colors.blue], ), ) // Set angle final gradient = Utils.parseAngleToAlignment(90); BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFFFFA3AD), Color(0xFFFC5E72) ], begin: Alignment(gradient['beginX'], gradient['beginY']), end: Alignment(gradient['endX'], gradient['endY']) ), borderRadius: BorderRadius.circular(2) )
26. Introduction to the use of materialapp
Field type home Widget routes map < string, widgetbuilder > Theme theme data debugShowMaterialGrid bool navigatorKey globalkey < navigatorstate > Ongeneraterote RouteFactory onUnknownRoute RouteFactory navigatorObservers list < navigatorobserver > initialRoute String Builder transition builder title String On generatetitle GenerateAppTitle Color color Locale (place) localizationsDelegates (localizationsDelegates) Iterable < localizationsdelegate < dynamic > > LocaleResolutionCallback localeresolutioncallback supportedLocales (supportable < locale > Show performance overlay bool checkerboardRasterCacheImages bool Checkerboard off screen layers bool showSemanticsDebugger bool debugShowCheckedModeBanner bool
27. Use FutureBuilder to request future again every time setState is called
Solution: extract future as a variable
Future<int> future; @override void initState() { super.initState(); future=getInt(); } FutureBuilder<int>( future: future, builder: (context, snapshot) { return ...; } ), Future<int> getInt(){ return Future.value(1); }
28. When the content of the input box is empty, long press does not display the paste toolbar
Remove the autoFocus attribute from the input box as true
29. Return button callback in the upper left corner of the flutter
1.1 async await implementation
///Await when you jump to a lower level page Navigator.pushNamed onTap: () async { await Navigator.pushNamed(context, '/account'); //Perform refresh data operation refrshData(); },
2. Nesting encapsulation will lead to the failure of await
class NavigatorUtil{ ///General jump static push(BuildContext context,Widget widget ) { Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300), pageBuilder: (context, animation, secondaryAnimation){ return new FadeTransition( //Use fade in transitions, opacity: animation, child:widget, ); }) ); } } //Use causes await to fail onTap: () async { // other await NavigatorUtil.push(context, widget); //Perform refresh operation },
Solution
Package layer nesting async await
class NavigatorUtil{ ///General jump static push(BuildContext context,Widget widget ) async { await Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300), pageBuilder: (context, animation, secondaryAnimation){ return new FadeTransition( //Use fade in transitions, opacity: animation, child:widget, ); }) ); } }
30.GestureDetector gesture conflict
Resolve gesture conflict - IgnorePointer
IgnorePointer( child: GestureDetector( child: Container( height: ScreenUtil().setHeight(300), width: Screen.width, decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(ScreenUtil().setWidth(20)), topRight: Radius.circular(ScreenUtil().setWidth(20)), ), gradient: LinearGradient( colors: [ Color(0xFFFFFFFF), Colors.white.withOpacity(.2), Colors.white.withOpacity(0), Colors.white.withOpacity(0), Colors.white.withOpacity(0) ], begin: Alignment( topGradient['beginX'], topGradient['beginY']), end: Alignment(topGradient['endX'], topGradient['endY']), ), ), ), onTap: () { backToTop(); }, ), ),
31.TextField sets border color (black line changes color)
///Input box Container( child: Theme( data: ThemeData( primaryColor: Colors.white, hintColor: Colors.white), child: TextField( style: TextStyle( fontSize: ScreenUtil().setSp(36), color: Colors.white, ), controller: inputController, onChanged: handlePhoneInput, autofocus: true, decoration: new InputDecoration( border: const UnderlineInputBorder( borderSide: BorderSide(style: BorderStyle.solid,color: Colors.white,), ), contentPadding: EdgeInsets.only( left: ScreenUtil().setWidth(100), right: ScreenUtil().setWidth(20), top: ScreenUtil().setWidth(20), bottom: ScreenUtil().setWidth(20), ), hintText: 'Enter phone number', hintStyle: TextStyle( color: Color.fromRGBO(255, 255, 255, .7), fontSize: ScreenUtil().setSp(36), ), ), ), ), ),
32.decoration shadow setting borderless
Set the stop node and colors combination through Opacity and LinearGradient
// Top shadow Opacity( opacity: 0.23, child: Container( height: ScreenUtil().setHeight(129), decoration: BoxDecoration( gradient: LinearGradient( stops: [ 0, .8 ], colors: [ Color(0xff565656), Color(0xFF030303).withOpacity(0), ], begin: Alignment(gradient['beginX'], gradient['beginY']), end: Alignment(gradient['endX'], gradient['endY'])), borderRadius: BorderRadius.only( topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0), ), ), child: Container( margin: EdgeInsets.only( left: ScreenUtil().setWidth(10), right: ScreenUtil().setWidth(17), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( margin: EdgeInsets.only( top: ScreenUtil().setHeight(17)), child: Row( children: <Widget>[ Icon( MyIcons.heart, size: ScreenUtil().setSp(40), color: Colors.white, ), Container( margin: EdgeInsets.only( left: ScreenUtil().setWidth(5), top: ScreenUtil().setWidth(5), ), child: Text( this.widget.item != null && this.widget.item.praises != null ? this.widget.item.praises.toString() : '', style: TextStyle( fontSize: ScreenUtil().setSp(20), color: Colors.white, ), textAlign: TextAlign.center, ), ) ], ), ), ], ), ), ), )
33.Dart List.asMap () get subscript
this.list.asMap().keys.map((i) { // i is the subscript return _itemUI(context, i); }).toList()
34.indexWhere get array index
int currentIndex = this.renderList.indexWhere((item) => item.id == feed.id);
35. Use of build runner plug-in
build runner plug-in build property shortcut
flutter packages run build_runner build --delete-conflicting-outputs
36. Click area of container is too small
Container in GestureDetector does not set color. Click area will be determined according to content size
37.xcrun instruments open simulator
xcrun instruments -w "iPhone 8 Plus (13.1)"
39. GestureDetector handles gesture operation behavior
-
HitTestBehavior.opaque Handle events by yourself
-
HitTestBehavior.deferToChild Child handles events
-
HitTestBehavior.translucent You and your child can receive events
40.Widget cannot be centered, aligned
Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( width: ScreenUtil().setHeight(114), height: ScreenUtil().setHeight(114), margin: EdgeInsets.only( left: ScreenUtil().setWidth(10), ), child: Center(child: FailedDot(),), ) : Container() ], ),
41. The click area of the shuttle container is too small
When using GestureDetector to wrap the Container, it is found that when clicking in the area where the content of the Container is empty, the onTap click event cannot be captured.
Solution: Add Attribute: behavior: HitTestBehavior.opaque , you can:
GestureDetector( behavior: HitTestBehavior.opaque, child: Container( width: ScreenUtil().setHeight(114), height: ScreenUtil().setHeight(114),child:Text('Point me')), onTap: () { this.handlePlayVoice(); }, )
42. Monitor page return event (return button click + sideslip to return)
Sideslip does not trigger the onBack callback, so use the onWillPop of WillPopScope to implement
@override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { // Setting up the scratchpad this.setCraft(); return true; }, child: Container() }
43precautions for using pageview
Problem Description: the first time you specify to load the second page, you need to switch twice to display normal
Cause analysis:
When PageView is not initialized, the default index = 0. When you forcibly modify it, the two indexes will be inconsistent
terms of settlement:
_controller = PageController(initialPage: currentIndex); ///Switch _controller.animateToPage( currentIndex, duration: Duration( milliseconds: (pageSwitchAnimatedTime + 100), ), curve: Curves.ease, );
44 ClipOval component details
- Round clipping (the out part is hidden, which is equivalent to Stack's overFlow being clip)
Center( child: ClipOval( child: Image.asset( "images/app.png", width: 100.0, height: 100.0, fit: BoxFit.cover, ), ), )
How to judge whether the device is an iPad
// 1. Import device information plug-in # Device information device_info: ^0.4.0 // 2. Use Future<bool> isIpad() async{ DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); IosDeviceInfo info = await deviceInfo.iosInfo; if (info.name.toLowerCase().contains("ipad")) { return true; } return false; }
46 memory leak caused by setstate -- setState() called after dispose()
Error reason
- Timer not destroyed (dispose destroy cancel)
resolvent
Interim programme
- The asynchronous message is not returned, so the mouted property is called before the setState method can be judged.
if (mounted) { setState(() { //refreshData }); }
Final solution
@override void dispose() { _countdownTimer?.cancel(); super.dispose(); }
47. Setup fillet image for flutter
Realized by cliprrect + borderaradius
Container( child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( this.matchedUser.user.avatar, fit: BoxFit.cover, ), ), width: AdaptationUtils.px(140), height: AdaptationUtils.px(140), )
48.clamp syntax
As the name implies, clamping, the result will not exceed this range, similar to the closed interval []
For example:
int origen = 10; int result = origen.clamp(2, 11); print(result);//MARK: the result is 10 ////////////////////////////////// int origen = 10; int result = origen.clamp(2, 9); print(result);//MARK: the result is 9
49. Expanded click area (Container)
design sketch
Expand click area.gif
Code encapsulation
///Expand the click area (Container) /// /// created by hujintao /// created at 2020-03-19 // import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class EnlargeWrapper extends StatefulWidget { Widget child; EdgeInsetsGeometry enlarge; EnlargeWrapper({ this.child, this.enlarge, }); @override _EnlargeWrapperState createState() => _EnlargeWrapperState(); } class _EnlargeWrapperState extends State<EnlargeWrapper> { @override Widget build(BuildContext context) { return Container( child: this.widget.child, padding: this.widget.enlarge ?? EdgeInsets.fromLTRB( ScreenUtil().setWidth(40), ScreenUtil().setWidth(40), ScreenUtil().setWidth(40), ScreenUtil().setWidth(40), ), // color: Colors.yellow , / / test color: Colors.transparent, ); } }
use
Center( child: GestureDetector( child: EnlargeWrapper( child: Container( width: 100, height: 100, color: Colors.red, child: Center( child: Text('Point me s Scatter'), ), ), enlarge: EdgeInsets.all(50), ), onTap: () { Toast.show('Click'); }, ), )
50. Read file by name
//Read file by name import 'dart:io'; readFile(name) async { //Create a file object var file = File(name); try { //Judge whether it exists bool exists = await file.exists(); if (exists) { //If present print(await file.length()); //File size (bytes) --- 137 print(await file.lastModified()); //Last modified on December 21, 2018 13:49:35.000 print(file.parent.path); //Get the path of the parent folder -- C:\Users\Administrator\Desktop\dart return await file.readAsString(); //Read file and return } else { await file.create(recursive: true); //Create file if it does not exist return "No files found,Created for you!Dart robot:2333"; } } catch (e) { //exception handling print(e); } }
use
var result = await readFile("\Users\XXX\Desktop\dart\test.txt"); print(result);
Add all SD card file names
// Add all SD card file names localPath() { try { var perm = SimplePermissions.requestPermission(Permission.ReadExternalStorage); var sdPath = getExternalStorageDirectory(); sdPath.then((file) { perm.then((v) { file.list().forEach((i) { _files.add(i.path); }); setState(() {}); }); }); } catch (err) { print(err); } }
51 flitter wechat sharing and payment callback
Through fluwx wechat SDK plug-in
Download plug-ins
# Wechat sdk fluwx: ^1.2.1+1
1. Wechat share callback
import 'package:fluwx/fluwx.dart' as fluwx; ///Wechat sharing and monitoring StreamSubscription wxShareListener; @override void initState() { super.initState(); this.track(); initWxShareListener(); } ///Initialize wechat sharing monitoring void initWxShareListener() { wxShareListener = fluwx.responseFromShare.listen(this.onWxShareResponse); } ///Wechat share response void onWxShareResponse(fluwx.WeChatShareResponse response) { print( 'pay success: ${response.errStr}, ${response.type}, ${response.errCode}, ${response.androidOpenId}'); if (response.errCode == 0) { Toast.show('Share back~~~~'); } } // Destroy monitor @override void dispose() { wxShareListener.cancel(); super.dispose(); }
2. Wechat payment callback
import 'package:fluwx/fluwx.dart' as fluwx; ///Wechat payment monitoring StreamSubscription fluwxPaymentListener; @override void initState() { super.initState(); this.track(); initWxPayListener(); } ///Initialize wechat payment monitoring void initWxPayListener() { fluwxPaymentListener = fluwx.responseFromPayment.listen(this.onWxPayResponse); } ///Wechat payment response void onWxPayResponse(fluwx.WeChatPaymentResponse response) { print( 'pay success: ${response.errStr}, ${response.type}, ${response.errCode}, ${response.androidOpenId}'); // After wechat response, windows cannot be closed if (this.canClose) { this.canClose = false; setState(() {}); } if (response.errCode == 0) { this.checkOrderStatus(); } else { if (response.errCode == -1) { this.onError(PayErrorEnum.WxPayError); } else if (response.errCode == -2) { this.onError(PayErrorEnum.WxPayCanceled); } else { this.onError(PayErrorEnum.WxPayUnKnowError); } } } // Destroy monitor @override void dispose() { fluwxPaymentListener.cancel(); super.dispose(); }
52. Database operation abstract class (interface encapsulation)
//Database operation abstract class abstract class DateBaseOperate { void insert(); //Define how to insert void delete(); //Define how to delete void update(); //Define how to update void query(); //Define a query method } //Database operation implementation class class DateBaseOperateImpl extends DateBaseOperate { //The method of inserting is realized void insert(){ print('The method of inserting is realized'); } //The method of deletion is realized void delete(){ print('The method of deletion is realized'); } //Implementation of the update method void update(){ print('Implementation of the update method'); } //A query method is implemented void query(){ print('A query method is implemented'); } } main() { var db = new DateBaseOperateImpl(); db.insert(); db.delete(); db.update(); db.query(); }
53. Succession
//Zoology class Animal { //Animals can eat void eat(){ print('Animals can eat'); } //Animals can run void run(){ print('Animals can run'); } } //human beings class Human extends Animal { //People will say void say(){ print('People will say'); } //Human beings can learn void study(){ print('Human beings can learn'); } } main() { print('Instantiate an animal class'); var animal = new Animal(); animal.eat(); animal.run(); print('Instantiate a human'); var human = new Human(); human.eat(); human.run(); human.say(); human.study(); }
54. Process control statement
void test(){ //if else example // String today = 'Monday'; // if (today == 'Monday') { // print('today is Monday '); // } else if (today == 'Tuesday') { // print('today is Tuesday '); // } else { // print('today is a good day '); // } //for loop example var message = new StringBuffer("Hello Dart"); for (var i = 0; i < 5; i++) { message.write('!'); } print(message); //forEach example // var arr = [0, 1, 2, 3, 4, 5, 6]; // for (var v in arr) { // print(v); // } //while loop example // var _temp = 0; // while(_temp < 5){ // // print("this is a loop:" + (_ temp).toString()); // _temp ++; // } //Do while loop example // var _temp = 0; // // do{ // print("this is a loop:" + (_ temp).toString()); // _temp ++; // } // while(_temp < 5); //break continue example var arr = [0, 1, 2, 3, 4, 5, 6]; for (var v in arr) { if(v == 2 ){ //break; continue; } print(v); } //switch case example String today = 'Monday'; switch (today) { case 'Monday': print('Monday'); break; case 'Tuesday': print('Tuesday'); break; } //Exception handling example try { // ··· } on Exception catch (e) { print('Exception details:\n $e'); } catch (e, s) { print('Exception details:\n $e'); print('Stack trace:\n $s'); } finally { print('Do some thing:\n'); } }
54. Getters and Setters methods
class Rectangle { num left; num top; num width; num height; Rectangle(this.left, this.top, this.width, this.height); //Get right value num get right => left + width; //Setting the right value also changes left set right(num value) => left = value - width; //Get the bottom value num get bottom => top + height; //Setting the bottom value also changes the top set bottom(num value) => top = value - height; }
55. Text set underline, dotted line and strikethrough
TextStyle( //Font color color: const Color(0xffff0000), //Text decorator (strikeout) decoration: TextDecoration.lineThrough, //Text finisher color (strikethrough color) decorationColor: const Color(0xff000000), //font size fontSize: 18.0, //Whether the font style is italicized fontStyle: FontStyle.italic, //Font weight fontWeight: FontWeight.bold, //Text spacing letterSpacing: 2.0, ) // Underline color: const Color(0xffff9900), decoration: TextDecoration.underline, // Dotted line decoration: TextDecoration.underline, decorationStyle: TextDecorationStyle.dashed, // Italics fontStyle: FontStyle.italic, fontWeight: FontWeight.bold,
56.PopupMenuButton component example
//Master menu item enum ConferenceItem { AddMember, LockConference, ModifyLayout, TurnoffAll } FlatButton( onPressed: () {}, child: PopupMenuButton<ConferenceItem>( onSelected: (ConferenceItem result) {}, itemBuilder: (BuildContext context) =>//Menu item builder <PopupMenuEntry<ConferenceItem>>[ const PopupMenuItem<ConferenceItem>(//menu item value: ConferenceItem.AddMember, child: Text('Add member'), ), const PopupMenuItem<ConferenceItem>( value: ConferenceItem.LockConference, child: Text('Lock meeting'), ), const PopupMenuItem<ConferenceItem>( value: ConferenceItem.ModifyLayout, child: Text('Modify layout'), ), const PopupMenuItem<ConferenceItem>( value: ConferenceItem.TurnoffAll, child: Text('Hang up all'), ), ], ), )
57.TextField component details
TextField( //Bind controller controller: controller, //Maximum length. Setting this item will make TextField have a statistical string of input quantity in the lower right corner maxLength: 30, //Maximum rows maxLines: 1, //AutoCorrect or not autocorrect: true, //Auto focus or not autofocus: true, //Is it a password obscureText: false, //text alignment textAlign: TextAlign.center, //Style of input text style: TextStyle(fontSize: 26.0, color: Colors.green), //Callback when text content changes onChanged: (text) { print('Callback when text content changes $text'); }, //Callback on content submission onSubmitted: (text) { print('Callback on content submission $text'); }, enabled: true, //Disable or not decoration: InputDecoration(//Add decoration effect fillColor: Colors.grey.shade200,//Add a gray fill color filled: true, helperText: 'user name', prefixIcon: Icon(Icons.person),//Left Icon suffixText: 'user name'),//Right text prompt )
58. Example of sliding deletion
design sketch
Slide delete.gif
code
import 'package:flutter/material.dart'; void main() { runApp(new MaterialApp( title: 'Slide delete example', home: new MyApp(), )); } class MyApp extends StatelessWidget { //Build 30 list data List<String> items = new List<String>.generate(30, (i) => "List item ${i + 1}"); @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Slide delete example'), ), //Build list body: new ListView.builder( itemCount: items.length,//Specify list length itemBuilder: (context, index) {//Build list //Extract deleted items final item = items[index]; //Returns a list item that can be deleted return new Dismissible( key: new Key(item), //Deleted callback onDismissed: (direction) { //Remove specified index entry items.removeAt(index); //The bottom pop-up message indicates that the current item has been deleted Scaffold.of(context).showSnackBar( new SnackBar(content: new Text("$item Deleted"))); }, child: new ListTile(title: new Text('$item'),) ); }, ), ); } }
59 adding and using custom fonts
-
1. place font resources
Place font resources
-
2. In pubspec.yaml Configuration path
fonts: - family: myfont fonts: - asset: fonts/myfont.ttf
- 3. Use
Center( child: new Text( 'Hello flutter', style: new TextStyle(fontFamily: 'myfont',fontSize: 36.0), ), )
- design sketch
design sketch
60. Page Jump return data
//Stack operation and wait for page return operation final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), ); //Read and display return value Scaffold.of(context).showSnackBar(SnackBar(content: Text("$result"))); //Go back to the previous page with the parameters on the stack Navigator.pop(context, 'hi flutter');
61.fluro enterprise level routing
- Import dependency
fluro: ^1.5.0
- Component encapsulation
// 1. Define Application class import 'package:fluro/fluro.dart'; //Define Application class class Application{ //Creating a Router object with static variables static Router router; } // 2. Define route set and handler /// 2.1 handler import 'package:fluro/fluro.dart'; import '../pages/second_page.dart'; import 'package:flutter/material.dart'; //Create a Handler to receive route parameters and return a second page object Handler secondPageHandler = Handler( handlerFunc: (BuildContext context,Map<String,List<String>> params){ //Reading the goodId parameter first is the first data String goodId = params['goodId'].first; return SecondPage(goodId); } ); ///2.2 route set import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'router_handler.dart'; //Routing set class Routes{ //Root path static String root = '/'; //Second page path static String secondPage = '/secondPage'; //Configure routing objects static void configureRoutes(Router router){ //No callback method found for route router.notFoundHandler = Handler( handlerFunc: (BuildContext context,Map<String,List<String>> params){ print('error::: router Can't find'); } ); //Define the Handler for the second page route router.define(secondPage, handler: secondPageHandler); } }
- First page
import 'package:flutter/material.dart'; import '../routers/application.dart'; import 'package:fluro/fluro.dart'; //First page class FirstPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Fluro Route navigation example"), ), body: Center( child: RaisedButton( //Click to process onPressed: () { _navigateToSecondPage(context); }, child: Text('Open the second page'), ), ), ); } //Route to second page _navigateToSecondPage(BuildContext context) async { //Parameters of routing band String goodId = '001'; //Navigate to the second page through the routing router in the Application class to specify the page switching animation type Application.router.navigateTo(context, "/secondPage?goodId=$goodId",transition: TransitionType.fadeIn).then((result) {//Return value //When the second page returns, the parameter with it is the result value if (result != null) { print(result); } }); } }
- Second page
import 'package:flutter/material.dart'; //Second page class SecondPage extends StatelessWidget { //Pass parameter values final String goodId; SecondPage(this.goodId); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second page"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ //Show pass through parameter values Text( '$goodId', style: TextStyle( fontSize: 28.0, color: Colors.red, ), ), Padding( padding: const EdgeInsets.all(8.0), child: RaisedButton( onPressed: () { //Return to the first page with the parameters on the stack Navigator.pop(context, 'Second page return parameters($goodId)'); }, child: Text('Click back'), ), ), ], ), ), ); } }
- Configure routing
import 'package:flutter/material.dart'; import './routers/routes.dart'; import 'package:fluro/fluro.dart'; import './routers/application.dart'; import './pages/first_page.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //Create routing object final router = Router(); //Configure routing objects for route set Routes Routes.configureRoutes(router); //Specify the routing object for Application Application.router = router; return Container( child: MaterialApp( title: "Fluro Route navigation example", debugShowCheckedModeBanner: false, //Generate the route callback function, which will be used to generate the interface when the named route is navigated onGenerateRoute: Application.router.generator, //Home page designated as first page home: FirstPage(), ), ); } }
62. Database operation ('Sqlite ')
Model
//Customer data model class class Client { //id int id; //full name String name; //Age int age; //Gender bool sex; Client({this.id, this.name, this.age, this.sex,}); //Convert JSON data to data model factory Client.fromMap(Map<String, dynamic> json) => Client( id: json["id"], name: json["name"], age: json["age"], sex: json["sex"] == 1, ); //Convert data model to JSON Map<String, dynamic> toMap() => { "id": id, "name": name, "age": age, "sex": sex, }; }
Component encapsulation
import 'dart:async'; import 'dart:io'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'client.dart'; import 'package:sqflite/sqflite.dart'; //Database operation encapsulation class class DBProvider { DBProvider._(); static final DBProvider db = DBProvider._(); Database _database; //Get Database object Future<Database> get database async { //Using singleton mode to create Database objects if (_database != null) { return _database; } _database = await initDB(); return _database; } //Initialize database initDB() async { //Get document catalog object Directory documentsDirectory = await getApplicationDocumentsDirectory(); //Get the default database location (on Android, it is usually data / data / < package_ Name > / databases, on iOS, it is the Documents directory) String path = join(documentsDirectory.path, "client.db"); //Open database incoming path version No. open completion callback function return await openDatabase(path, version: 1, onOpen: (db) {}, onCreate: (Database db, int version) async { //Create Client table after database creation await db.execute("CREATE TABLE Client (" "id INTEGER PRIMARY KEY," "name TEXT," "age INTEGER," "sex BIT" ")"); }); } //New Client insertClient(Client newClient) async { final db = await database; //Get the largest id in the table and add 1 as the new id var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM Client"); int id = table.first["id"]; //Insert a piece of data into the table var raw = await db.rawInsert( "INSERT Into Client (id,name,age,sex)" " VALUES (?,?,?,?)", [id, newClient.name, newClient.age, newClient.sex]); return raw; } //Modify gender updateSex(Client client) async { final db = await database; Client newClient = Client( id: client.id, name: client.name, age: client.age, sex: !client.sex); //Update the gender of the current Client var res = await db.update("Client", newClient.toMap(), where: "id = ?", whereArgs: [client.id]); return res; } //Update Client updateClient(Client newClient) async { final db = await database; var res = await db.update("Client", newClient.toMap(), where: "id = ?", whereArgs: [newClient.id]); return res; } //Get Client according to id getClient(int id) async { final db = await database; //Query table records according to id var res = await db.query("Client", where: "id = ?", whereArgs: [id]); //Convert the data returned by the query to a Client object and return return res.isNotEmpty ? Client.fromMap(res.first) : null; } //Get all clients Future<List<Client>> getAllClients() async { final db = await database; var res = await db.query("Client"); List<Client> list = res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : []; return list; } //Delete Client according to id deleteClient(int id) async { final db = await database; return db.delete("Client", where: "id = ?", whereArgs: [id]); } //Delete all clients deleteAll() async { final db = await database; db.rawDelete("Delete * from Client"); } }
Component use
// Get all data DBProvider.db.getAllClients(), //Delete Client object according to id DBProvider.db.deleteClient(item.id); //Update gender DBProvider.db.updateSex(item); //Randomly take one piece of test data as Client object Client rnd = clients[math.Random().nextInt(clients.length)]; //Add a new Client object await DBProvider.db.insertClient(rnd);
By Steven Hu_ Sir
Link: https://www.jianshu.com/p/286c8beacb11
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.