This article, the 17th in a series of articles, once again introduces practical techniques for the development of Flutter to help you continue to overtake cars on curves. The whole article is a personal summary of the practical things that Flutter can do every day, with a focus on filling holes in the road so that you don’t have to go on the wrong side of the road.
Article summary address:
A complete series of articles on Flutter
A series of articles on the world outside Flutter
1, Package get git failed
The Flutter project usually references a third library directly from a pub plugin, but sometimes we choose to use git references for security and privacy. For example:
photo_view:
git:
url: https://github.com/CarSmallGuo/photo_view.git
ref: master
Copy the code
At this time, if the flutter packages get fails, the following problems may occur when the flutter Packages GET is executed again:
Git fails because of flutter packages get:
The next time the package is pulled, the git directory in.pub_cache will detect an existing directory, but it may be empty, etc., causing an exception when the flutter packages get occurs.
So you need to clear it out.pub_cache
Within thegit
Exception directory, and then it is best to clear the project underpubspec.lock
, and then execute againflutter packages get
。
Git folder in C: Users\ XXXXX \AppData\ Pub\Cache folder
The MAC directory is ~/. Pub-cache.
2, TextEditingController
As shown in the code above, the red line indicates that if the controller is empty, a TextEditingController is assigned. Writing this way causes the problem shown below:
After successful input when the keyboard is popped up, the input disappears when the keyboard is folded up! This is because keyboard pop-ups and takedowns trigger page builds, and each TextEditingController assignment causes the TextEditingValue of the TextField to reset when the Controller is null.
As shown in the figure above, the TextEditingController needs to be built globally before assigning, since the value is not copied during update when the Controller of the TextField is not empty. If the controller is empty, null is used instead of reconstructing the TextEditingController every time you build.
3, Scrollable
As shown in the figure above, as analyzed in article 7, Scrollable usually exists in the slider list, and Scrollable happens to be an InheritedWidget, This makes it convenient to call Scrollable related methods in children.
We can control the children of the ListView/GridView more decoupled by scrollable.of (context) as shown in the following code.
ScrollableState state = scrollable. of(context) // get renderObject of viewport in _scrollable state.context.findRenderObject(); / / / to monitor position update state. The position. AddListener (() {}); / / / notify position update state. The position. NotifyListeners (); /// Scroll to the specified position state.position.jumpto (1000); ...Copy the code
4. Gaussian blur
With Flutter, BackdropFilter and ImageFilter support gaussian blur, as shown in the code below, can quickly achieve the gaussian blur effect shown above.
class BlurDemoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: new Container(
child: Stack(
children: <Widget>[
Positioned(
top: 0,
bottom: 0,
left: 0,
right: 0,
child: new Image.asset(
"static/gsy_cat.png",
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
)),
new Center(
child: new Container(
width: 200,
height: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(15.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Icon(Icons.ac_unit),
new Text("Wow!!)],)))))],)); }}Copy the code
5. Scroll to the specified position
Because Flutter currently does not provide a direct way to scroll to a given Item, a compromise can be achieved quickly with the code shown below if each Item is of different sizes:
Dart scroll_to_index_DEMO_page2.dart Add a GlobalKey to each item and find the RenderBox for each item. Then use localToGlobal to get the offset of the item in the ViewPort ancestor and scroll:
Of course, there is another way to do this, scroll_to_index_DEMO_page.dart
6, findRenderObject
There is a difference between container widgets and render widgets in Flutter.
Text
,Sliver
、ListTile
And so on all belong to render Widget, its interior is mainlyRenderObjectElement
。StatelessWidget
/StatefulWidget
Etc are container widgets that are used internally byComponentElement
,ComponentElement
It doesn’t existRenderObject
.
BuildContext is Element, so context.findRenderObject() is Element’s findRenderObject().
Then, as shown in the figure above, the implementation of findRenderObject is to obtain the renderObject. In Element, the obtaining logic of renderObject is very clear. When meeting ComponentElement, Element. VisitChildren (visit); , recurse until RenderObjectElement is found.
So as shown in the following code print (” ${globalKey. CurrentContext. FindRenderObject ()} “); The SizedBox RenderObject is output.
7. Line spacing
There is no direct method for setting the spacing between Text lines in Flutter. The Text effect should look like this:
So how do we deal with line spacing? As shown in the figure below, by setting StrutStyle leading, Transform is used to calculate the orientation and position offset. Since leading is balanced up and down, the required line spacing can be obtained after calculation. (Although there is no guarantee of 100% pixel accuracy, do you know of any other methods?)
As an additional point, it can be used by the parent node
DefaultTextStyle
To achieve local style sharing oh.
8 Builder.
There is a Builder Widget in Flutter. This Widget is a simple encapsulation of the StatelessWidget. Why should it exist?
As shown in the following figure, some Flutter developers may experience the following error when using scaffold.of (context).showsnackbar (snackbar). This is because the context passed in is the wrong node. Because the context passed in here did not find the Scaffold where the page was.
The Scaffold Builder method returns the given context. When you look up the Scaffold, you can find the Scaffold of the parent node. That’s part of what ComponentElement does.
9, fast implementation of animation switching effect
To achieve the animation effects shown above, an AnimatedSwitcher encapsulation is provided in Flutter for easy implementation.
As shown in the figure below, you can achieve the effect of animation switch by nesting AnimatedSwitcher, specifying the Animation Effect transitionBuilder, and then changing the key value of the animation to be executed when the data changes.
10, multi-language display exception
At the official github.com/flutter/flu… It can be found in the issue that Flutter is displayed in Korean/Japanese and Chinese at the same time, which will cause abnormal text rendering in iOS, as shown in the picture below. The abnormal situation is on the left.
There are two solutions to the problem:
-
Added font TTF to specify globally changing font display.
-
Modify the theme under all
TextTheme
的fontFamilyFallback
:
getThemeData() {
var themeData = ThemeData(
primarySwatch: primarySwatch
);
var result = themeData.copyWith(
textTheme: confirmTextTheme(themeData.textTheme),
accentTextTheme: confirmTextTheme(themeData.accentTextTheme),
primaryTextTheme: confirmTextTheme(themeData.primaryTextTheme),
);
returnresult; ConfirmTextTheme (TextTheme TextTheme) {getCopyTextStyle(TextStyle TextStyle) {return textStyle.copyWith(fontFamilyFallback: ["PingFang SC"."Heiti SC"]);
}
return textTheme.copyWith(
display4: getCopyTextStyle(textTheme.display4),
display3: getCopyTextStyle(textTheme.display3),
display2: getCopyTextStyle(textTheme.display2),
display1: getCopyTextStyle(textTheme.display1),
headline: getCopyTextStyle(textTheme.headline),
title: getCopyTextStyle(textTheme.title),
subhead: getCopyTextStyle(textTheme.subhead),
body2: getCopyTextStyle(textTheme.body2),
body1: getCopyTextStyle(textTheme.body1),
caption: getCopyTextStyle(textTheme.caption),
button: getCopyTextStyle(textTheme.button),
subtitle: getCopyTextStyle(textTheme.subtitle),
overline: getCopyTextStyle(textTheme.overline),
);
}
Copy the code
Ps: by WidgetsBinding. The instance. The window. The locale; You can get the current language of the mobile platform itself, not the context, not the Locale that you’ve set.
11. Long pressing the input box leads to abnormal situations
If the project has multi-language and theme switching scenarios, exceptions may occur due to long pressing of the input box. At present, two methods are recommended to solve the problem:
- 1, can give you custom
ThemeData
Force a fixed platform to be specified, but this method will cause the platform copy-paste pop-up box without platform features:
Platform: targetplatform. androidCopy the code
- 2, add a custom
LocalizationsDelegate
To achieve custom support in multi-language environments:
class FallbackCupertinoLocalisationsDelegate
extends LocalizationsDelegate<CupertinoLocalizations> {
const FallbackCupertinoLocalisationsDelegate();
@override
bool isSupported(Locale locale) => true;
@override
Future<CupertinoLocalizations> load(Locale locale) => loadCupertinoLocalizations(locale);
@override
bool shouldReload(FallbackCupertinoLocalisationsDelegate old) => false;
}
class CustomZhCupertinoLocalizations extends DefaultCupertinoLocalizations {
const CustomZhCupertinoLocalizations();
@override
String datePickerMinuteSemanticsLabel(int minute) {
if (minute == 1) return 'a minute';
return minute.toString() + 'minutes';
}
@override
String get anteMeridiemAbbreviation => 'morning';
@override
String get postMeridiemAbbreviation => 'afternoon';
@override
String get alertDialogLabel => 'warning';
@override
String timerPickerHourLabel(int hour) => 'hour';
@override
String timerPickerMinuteLabel(int minute) => 'points';
@override
String timerPickerSecond(int second) => '秒';
@override
String get cutButtonLabel => 'cut';
@override
String get copyButtonLabel => 'copy';
@override
String get pasteButtonLabel => 'paste';
@override
String get selectAllButtonLabel => 'all';
}
class CustomTCCupertinoLocalizations extends DefaultCupertinoLocalizations {
const CustomTCCupertinoLocalizations();
@override
String datePickerMinuteSemanticsLabel(int minute) {
if (minute == 1) return 'a minute';
return minute.toString() + 'minutes';
}
@override
String get anteMeridiemAbbreviation => 'morning';
@override
String get postMeridiemAbbreviation => 'afternoon';
@override
String get alertDialogLabel => 'warning';
@override
String timerPickerHourLabel(int hour) => 'hour';
@override
String timerPickerMinuteLabel(int minute) => 'points';
@override
String timerPickerSecond(int second) => '秒';
@override
String get cutButtonLabel => 'cut';
@override
String get copyButtonLabel => 'copy';
@override
String get pasteButtonLabel => 'paste';
@override
String get selectAllButtonLabel => 'all';
}
Future<CupertinoLocalizations> loadCupertinoLocalizations(Locale locale) {
CupertinoLocalizations localizations;
if (locale.languageCode == "zh") {
switch (locale.countryCode) {
case 'HK':
case 'TW':
localizations = CustomTCCupertinoLocalizations();
break; default: localizations = CustomZhCupertinoLocalizations(); }}else {
localizations = DefaultCupertinoLocalizations();
}
return SynchronousFuture<CupertinoLocalizations>(localizations);
}
Copy the code
Thus, canto xVII is finally over! (/ / / del / / /)
Resources to recommend
- Making: github.com/CarGuo
- Open Source Flutter complete project:Github.com/CarGuo/GSYG…
- Open Source Flutter Multi-case learning project:Github.com/CarGuo/GSYF…
- Open Source Fluttre Combat Ebook Project:Github.com/CarGuo/GSYF…
- Open Source React Native project: github.com/CarGuo/GSYG…