I’ve been learning the Flutter for a while. Idle nothing, with the company has a cool App design to practice. Of course, the interface is not working, so it’s all dead data, and the implementation is pretty good. . Of course, I wrote my own review, and I borrowed many of the best Flutter projects on Github. Now open source out (with design), for everyone to exchange learning. Hope more Star, Fork support, there are problems can Issue. Attached link: github.com/simplezhli/…

This article mainly shares their own problems and experience in this project, I hope to help you!

1. A component overflows

The exception is as follows:

A RenderFlex overflowed by 22 pixels on the bottom.
Copy the code

The reason is that the content in the horizontal or vertical direction exceeds the size of the parent component. Generally speaking, our pages do not have this problem, because according to the design of the page, we can anticipate in advance whether or not to exceed. However, notice that the input method pops up. Take my following example:

You can see that the bottom is overflowing by 22 pixels, which is probably less of a problem above 18:9 phones because the screen is high enough. But the 16:9 phone could be exposed. There are two ways to solve this problem:

  1. Package a layer of SingleChildScrollView to make your page slidable.

  2. Set resizeToAvoidBottomInset to false in Scaffold. The default value is true to prevent parts from being obscured. If this method is used, occlusion will occur if there is input field at the bottom.

You can choose according to your actual needs.

2. The input box is blocked

The page is as follows:

There are input boxes at the bottom, and a “submit” button is fixed at the bottom. The first thought was that since it was Positioned at the bottom, we would use the Stack in combination with the tourists, but this resulted in occlusion as the input popped out.

In the image above, I selected the last input field, but this is obscured by the “submit” button that pops up below the input field by default.

In the end, my solution was to use a Column with Expanded. After repair:

3.SafeArea

Once the parts are fixed at the top or bottom (or, more precisely, at the sides of the screen). Well, we’d better use the SafeArea to wrap it up. Because both Android and IOS have a status bar, and even IOS has a bar called the HomeIndicator. So you can have adaptation problems if you’re not careful.

The BottomNavigationBar and AppBar that we often use in our Flutter actually handle this kind of problem internally. Take the AppBar source code as an example:

class _AppBarState extends State<AppBar> {

  @override
  Widget build(BuildContext context) {
    
    if (widget.primary) {
      appBar = SafeArea(  / / < -- - 1
        top: true,
        child: appBar,
      );
    }

    return Semantics(
      container: true,
      child: AnnotatedRegion<SystemUiOverlayStyle>(
        value: overlayStyle,
        child: Material( / / < -- - 2
          color: widget.backgroundColor
            ?? appBarTheme.color
            ?? themeData.primaryColor,
          child: Semantics(
            explicitChildNodes: true, child: appBar, ), ), ), ); }}Copy the code

So the use method is:

Material( // Need the color to fill the border area can be used
  color: Colors.white,
  child: SafeArea(
    child: Container(),
  ),
)		
Copy the code

Again on the above page, let’s compare the effect before and after processing:

4. To make good use of the Theme

One of the criticisms of The development of Flutter was that there was a lot of nesting, which we had to avoid. For example, some parts and attributes are encapsulated to avoid duplication of writing. But encapsulation is also about usage scenarios. If this style of part is only used in one or two places, the encapsulation is a bit of a storm in a teacup. And the size and completeness of the package increases the complexity of using it. This is where you can use a Theme.

For example, the circled section in the image below has three buttons of the same height, text, and rounded corners. It would be too much trouble to set these properties for each one.

It is convenient to use the Theme to change their styles uniformly.

			Theme( 
              data: Theme.of(context).copyWith(
                buttonTheme: ButtonThemeData(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  minWidth: 64.0,
                  height: 30.0,
                  materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  shape:RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(4.0),
                  )
                ),
                textTheme: TextTheme(
                  button: TextStyle(
                    fontSize: 14.0,
                  )
                )
              ),
              child: Row(
                children: <Widget>[
                  FlatButton(
                    color: Color(0xFFF6F6F6),
                    onPressed: (){},
                    child: Text("Contact customers"),),... FlatButton( color: Color(0xFFF6F6F6),
                    onPressed: (){},
                    child: Text("From the single"))])Copy the code

For example, the default width of a FlatButton is 88 and the height is 36. However, there are no properties that can be modified directly in a FlatButton. Many methods on the Internet use a layer of Containers to modify the properties. So using themes can save you time and effort, but the downside is that you have to go through the source code to find places to use them.

5. Pay attention to platform differences

Note how some components differ between Android and IOS.

  1. ScaffoldtheAppBar.AppBarIn the defaulttitleOn Android, it is displayed on the left, and on IOS, it is displayed in the middle. If you want the two platforms to be uniform, you need to set it atAppBarIntermediate active settingcenterTitleProperties. At the same timeAppBarThe return arrow icon is not the same, if the unity needs to be customizedleading.

  1. Page jump if usedMaterialPageRouteTo do a transition effect, notice that in Android a new page slides from the bottom of the screen to the top of the screen, and in IOS a new page slides from the right to the left of the screen.

If we want the same effect for both platforms, we don’t use the original effect, we can customize one.

Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
  pageBuilder: (context, animation, secondaryAnimation){
    return new FadeTransition( // Use a fade in transition,opacity: animation, child: TestPage(), ); }));Copy the code

Or modify the Theme to unify the implementations of the two platforms. :

class MyApp extends StatelessWidget {

  static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
    TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
    TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
  };
  
  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      theme: ThemeData(
        pageTransitionsTheme: PageTransitionsTheme(
          builders: _defaultBuilders
        )
      ),
      ...
    );
  }
}
Copy the code
  1. The ScrollPhysics effect, everything that slides has a physics property. When sliding to the edge, the Android platform is ClampingScrollPhysics for the edge shadow effect, and IOS is BouncingScrollPhysics for the rebound effect. If you want uniformity, you can specify the physics property.

  2. The status bar is translucent by default on Android and transparent on IOS. For example, if Android wants to achieve the effect of IOS, you can set the status bar to transparent. But IOS can’t do what Android does… Can only be customized? Those who know how can share it.

void main(a){
  runApp(MyApp());
  // Transparent status bar
  if(Platform.isAndroid) { SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent); SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); }}Copy the code
  1. Keyboard input

When the keyboardType property of the TextField is set to TextinputType. phone or TextinputType. number, the number input keyboard displayed in the IOS system does not have the “Finish” button. As a result, the input method cannot be disabled. Android, of course, doesn’t have this problem.

A more effective solution is to hover a button above the keyboard popup, which can be clicked to close the keyboard. Of course, there are libraries that can solve this problem, and I used flutter_keyboard_actions to solve this problem. Because I found compatibility problems with some input methods on Android, I only dealt with it on IOS. You can take a look at the before and after comparison, the implementation code can refer to the flutter_Keyboard_Actions document and my project code:

Of course, there are more platform differences than that, for example, IOS comes with sideslip return and so on. Look at the code that calls the TargetPlatform enumeration class.

If you think this is a hassle, you can change the ThemeData platform to specify a platform.

class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      theme: ThemeData(
        platform: TargetPlatform.android
      ),
      ...
    );
  }
}
Copy the code

The second is to use textinputType. number in IOS to play keyboard without decimal point symbol. Type in the input amount data, need to keyboardType attribute is set to TextInputType. NumberWithOptions (decimal: true).

6.keyboardType

The keyboardType attribute indicates the keyboardType that is tapped, and does not represent the type of input data.

In Android development, setting Android :inputType in EditText not only specifies the keyboard type to be tapped, but also determines the type of input data, which is built-in format validation. The latter is not in The Flutter, so you may start with TextinputType. number, but switch to a Chinese keyboard in the input method and you can still enter Chinese characters. So we need to use inputFormatters to process the data.

Such as TextInputType. The phone can use WhitelistingTextInputFormatter white list check, only allow you to enter 0 ~ 9:

	TextField(
      keyboardType: TextInputType.phone,
      inputFormatters: [WhitelistingTextInputFormatter(RegExp("[0-9].")))Copy the code

Enter the password can use BlacklistingTextInputFormatter blacklist check, remove Chinese characters:

	TextField(
      keyboardType: TextInputType.text,
      inputFormatters: [BlacklistingTextInputFormatter(RegExp("[\u4e00-\u9fa5]")))Copy the code

You can customize TextInputFormatter to restrict decimal format input:

	TextField(
      keyboardType: TextInputType.numberWithOptions(decimal: true),
      inputFormatters: [UsNumberTextInputFormatter()]
    )

Source: / / https://www.cnblogs.com/yangyxd/p/9639588.html
class UsNumberTextInputFormatter extends TextInputFormatter {
  static const defaultDouble = 0.001;
  static double strToFloat(String str, [double defaultValue = defaultDouble]) {
    try {
      return double.parse(str);
    } catch (e) {
      returndefaultValue; }}@override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    String value = newValue.text;
    int selectionIndex = newValue.selection.end;
    if (value == ".") {
      value = "0.";
      selectionIndex++;
    } else if(value ! =""&& value ! = defaultDouble.toString() && strToFloat(value, defaultDouble) == defaultDouble) { value = oldValue.text; selectionIndex = oldValue.selection.end; }return new TextEditingValue(
      text: value,
      selection: newTextSelection.collapsed(offset: selectionIndex), ); }}Copy the code

7.InkWell

An InkWell is called a splash effect or an InkWell effect. This is used when adding click events to non-clickable widgets (long press, double click, etc.), and you can also change the color and shape of the widgets.

InkWell(
  borderRadius: BorderRadius.circular(8.0), / / the rounded
  splashColor: Colors.transparent, // Splash ink (ripple color)
  highlightColor: Colors.transparent, // Click on the background color (high light color)
  onTap: () {},// Click the event
  child: Container(),
);
Copy the code

Sometimes, though, you’ll find that it’s not always the case that a coating of InkWell will result in a splash. The main reason for this is that the splash effect is in a background effect, not overlaying the foreground effect. So when a child in InkWell has a background image or background color set, the splash effect is blocked. If you need this splash effect, there are two ways to do it.

  1. Pack a layerMaterial, and set the background color toMaterialIn the color.
Material(
  color: Colors.white,
  child: InkWell(),
)
Copy the code
  1. useStackThe layout,InkWellPlaced on the upper level. This is useful for adding click effects to images such as banners.
		Stack(
            children: <Widget>[
              Positioned.fill(
                child: Image(),
              ),
              Positioned.fill(
                child: Material(
                  color: Colors.transparent,
                  child: InkWell(
                    splashColor: Color(0X40FFFFFF),
                    highlightColor: Colors.transparent,
                    onTap: () {},
                  ),
                ),
              )
            ],
          )
Copy the code

8. Keep the page in state

For example, clicking the navigation bar to switch back and forth between pages will lose the original page state by default, which means the page will be reinitialized each time. This solution is PageView combined with BottomNavigationBar, child pages at the same time the State of inheritance AutomaticKeepAliveClientMixin rewrite wantKeepAlive to true. The code looks something like this:

class _TestState extends State<Test> with AutomaticKeepAliveClientMixin{

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }

  @override
  bool get wantKeepAlive => true;
}

Copy the code

The details of the Flutter can be found in this article: Three ways to maintain the original page status after switching pages

9. Version dependency

First of all, it is recommended that all widgets with Flutter do not use the ^ symbol when filling in the version number.

The ^ symbol means that you can use the latest version of the plugin (at least the current version). What’s the problem with that? Maybe one day your code was running, and today it’s compiling wrong. Because these plug-ins include the use of Android, IOS dependency environment configuration, common is the new version of the use of AndroidX dependency, but some plug-ins do not use AndroidX, resulting in the conflict between the two.

When I was looking at the code for Flutter – Go, the installation failed because the WebView plugin was suddenly upgraded. You can see it here. So it is not recommended to use the ^ symbol when the code is stable.

There are several solutions to this problem:

  1. Use a non-AndroidX version of the plugin. The advantage is that it works quickly. The downside is that subsequent updates to the plug-in will not work.)

  2. Manually modify plugin conflicts. Since the code of the Flutter plugin is modifiable directly, you can manually modify these conflicts and unify the plugin version (the advantage is that you can use the latest version). The disadvantage is that this method is firstly troublesome and secondly not conducive to team development and use.)

I prefer to use the second, as long as you keep a record of the changes, once and for all.

10. The Flutter of the Android package

The package process is fine. Configure the signature file and run the flutter build apk command. However, it was found that the androidmanifest.xml file in the plug-in was not merged after packaging. For example, I use the image_picker plugin, which has the androidManifest.xml file as follows:

You can see the permissions and declarations for the Android 7.0FileProvider. Information like this is not packaged in (but the reference to the FLutter_image_picker_File_Paths file in XML is), so it doesn’t work when I actually use it, but it works fine in my normal debugging.

In the middle, I found that the App name after packaging was the same as before, which was suspected to be a cache problem, so I manually deleted the build and. Gradle folders in the project root directory, and repackaged it. So it’s a good idea to check the Androidmanifest.xml file after packaging to avoid such caching problems.

11. Other

  1. Container is powerful and can be used to set width and height, padding, margin, background color, background image, rounded corners, shadows, etc.

  2. Some widgets come with the padding property, so you don’t have to have multiple layers of padding. (Such as ListView, GridView, Container, ScrollView, Button)

  3. Use const whenever possible to define constants. Things like padding, color, style:

class Colours {
  static const Color text_dark = Color(0xFF333333);
}

Padding(
  padding: const EdgeInsets.all(8.0),
  child: Text(
  	"Test",
  	style: TextStyle(
      fontSize: 26.0,
      color: Colours.text_dark
    )
  )
)
Copy the code
  1. In the Dart2newKeywords are optional, so don’t choose them, haha!!

Next article: Tips on the Development of Flutter (II)

In fact, THERE are many small problems I encountered in this process, some of which have not found a good way to solve. But this is just the beginning and hopefully Flutter is getting better.

Space is limited, so share the above 11 Tips and like them if they helped you! Github: github.com/simplezhli/…