The basic Widget for Flutter

I will update a series of Flutter text tutorials in the coming days

Update progress: at least two articles per week;

Update location: first in the public account, the next day update in nuggets, Sifu, developer headlines and other places;

More communication: You can add me on wechat at 372623326 and follow me on Weibo at CoderWhy

I hope you can help forward, click to see, give me more creative power.

Preface 2: This chapter was originally intended to explain the rendering principle of Flutter, but too much explanation of the original content at the beginning of learning is not conducive to quick introduction and mastery, and make some effective content.

Therefore, I would like to change the way of thinking. First, I will explain the usage of some components so that we can get used to the development process and mode of Flutter. Then I will go back to consolidate the knowledge of Flutter.

In addition, I’m not going to list all the attributes when I talk about these widgets, because it doesn’t make sense or make sense to remember them;

I plan to have a topic about the layout of Flutter in the future. I will select some beautiful layouts to complete: the Page of Meituan, the page of Jingdong, the page of B station, etc. Some properties THAT I have not mentioned so far will be explained later.

1. The text Widget

On Android we use TextView, on iOS we use UILabel to display text;

In Flutter, we use the Text component to control how the Text is displayed.

1.1. Plain text display

In Flutter, we can divide the control display of text into two categories:

  • Parameters that control text layout, such as textAlign, textDirection, maxLines, overflow, and so on, are all arguments in constructors;
  • Parameters that control text styles, such as font name fontFamily, fontSize fontSize, text color color, text shadow, and so on, are encapsulated in the constructor’s style parameter.

Let’s look at the use of some of these attributes:

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      Don't listen to the sound of trees and leaves, why not chant and xu Xing. \n Bamboo stick straw in ear shoe is better than a horse, who is afraid? A rush of rain any life.",
      style: TextStyle(
        fontSize: 20, color: Colors.purple ), ); }}Copy the code

The display effect is as follows:

We can change the layout of a Text with a few properties:

  • TextAlign: Text alignment, such as textalign.center
  • MaxLines: Maximum number of display lines, such as 1
  • Overflow: The display of an overflow part, such as textoverflow.ellipsis
  • TextScaleFactor: Controls text scaling, such as 1.24

The code is as follows:

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      Don't listen to the sound of trees and leaves, why not chant and xu Xing. \n Bamboo stick straw in ear shoe is better than a horse, who is afraid? A rush of rain any life.",
      textAlign: TextAlign.center, // Everything is centered
      maxLines: 3.// Obviously "live". Been deleted
      overflow: TextOverflow.ellipsis, // The exceeding part shows...
/ / textScaleFactor: 1.25.
      style: TextStyle(
        fontSize: 20, color: Colors.purple ), ); }}Copy the code

1.2. Rich text display

We have applied the same style to all of the text shown above. What if we wanted to give them different styles?

  • For Example, I wanted the font to be bigger, black, and bold.
  • For example, SU Shi, I hope the font is red;

If you want to show this hybrid style, you can do it using sharding (SpannableString on Android, NSAttributedString on iOS).

The code is as follows:

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text.rich(
      TextSpan(
        children: [
          TextSpan(text: "The Storm", style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold, color: Colors.black)),
          TextSpan(text: "Su shi", style: TextStyle(fontSize: 18, color: Colors.redAccent)),
          TextSpan(text: "\n Don't listen to the sound of trees and leaves, why not chant and walk slowly. \n Bamboo stick straw in ear shoe is better than a horse, who is afraid? A rush of rain any life.")
        ],
      ),
      style: TextStyle(fontSize: 20, color: Colors.purple), textAlign: TextAlign.center, ); }}Copy the code

Button widgets

2.1. The basics of buttons

The Material Widget library provides a variety of button widgets such as FloatingActionButton, RaisedButton, FlatButton, OutlineButton, and more

Let’s go ahead and give them a demonstration:

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        FloatingActionButton(
          child: Text("FloatingActionButton"),
          onPressed: () {
            print("FloatingActionButton Click");
          },
        ),
        RaisedButton(
          child: Text("RaisedButton"),
          onPressed: () {
            print("RaisedButton Click");
          },
        ),
        FlatButton(
          child: Text("FlatButton"),
          onPressed: () {
            print("FlatButton Click");
          },
        ),
        OutlineButton(
          child: Text("OutlineButton"),
          onPressed: () {
            print("OutlineButton Click"); },)],); }}Copy the code

2.2. Custom styles

We use the default style for the previous buttons, and we can change the style of the buttons through some properties

RaisedButton(
  child: Text("Consent agreement", style: TextStyle(color: Colors.white)),
  color: Colors.orange, // Button color
  highlightColor: Colors.orange[700].// Press highlight color
  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), // Implement rounded corners
  onPressed: () {
    print("Consent agreement"); },)Copy the code

In fact, there is a more common attribute here: elevation, which controls the size of the shadow, elevation, elevation, elevation, elevation, elevation, elevation, elevation, elevation, elevation

Image widgets

Images can make our application more colorful. Flutter uses the Image component

The Image component has a number of constructors, and we’ll focus on two here:

  • Image.assets: loads images of local resources.
  • Image.network: Loads images from the network;

3.1. Load network images

Loading web images into Flutter is relatively easy. Passing in urls directly requires no configuration, so let’s first look at how to load web images into Flutter.

Let’s first look at the properties of the Image that can be set:

const Image({
  ...
  this.width, // Width of the image
  this.height, // Image height
  this.color, // The mixed color value of the image
  this.colorBlendMode, // Mix mode
  this.fit,// Zoom mode
  this.alignment = Alignment.center, // Alignment
  this.repeat = ImageRepeat.noRepeat, // Repeat mode. })Copy the code
  • width,height: Used to set the width and height of the image. If the width and height are not specified, the original size of the image will be displayed according to the current parent containerwidth,heightThe other property is scaled by default, but can be scaled by the followingfitProperty to specify adaptation rules.
  • fit: This property is used to specify the image’s adaptation mode when the image’s display space and image size are different. Adaptive mode is inBoxFit, which is an enumerated type with the following values:
    • fill: will stretch to fill the display space, the picture itself aspect ratio will change, the picture will be deformed.
    • cover: The image will be enlarged according to the aspect ratio of the image and then centered to fill the display space. The image will not be deformed, and the part beyond the display space will be clipped.
    • contain: This is the default image adaptation rule. The image will be scaled to fit the current display space without changing the aspect ratio of the image itself.
    • fitWidth: The width of the image will be scaled to the width of the display space, the height will be scaled to scale, and then the image will be centered. The image will not be distorted, and the parts outside the display space will be clipped.
    • fitHeight: The height of the image will be scaled to the height of the display space, the width will be scaled to scale, and then the image will be centered. The image will not be distorted, and the parts outside the display space will be clipped.
    • none: The image has no adaptive policy and will be displayed in the display space. If the image is larger than the display space, only the middle part of the image is displayed in the display space.
  • colorandcolorBlendMode: Color mixing can be performed on each pixel during picture drawing.colorSpecify the blend color, whilecolorBlendModeSpecify blending mode;
  • repeat: Specifies the image repetition rule when the image itself is smaller than the display space.

Let’s do a walkthrough on some of these properties:

  • Notice, I’m using a Container here, and you can think of it as a UIView or a View, which is a Container;
  • I’ll focus on the use of this component later;
class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        child: Image.network(
          "http://img0.dili360.com/ga/M01/48/3C/wKgBy1kj49qAMVd7ADKmuZ9jug8377.tub.jpg",
          alignment: Alignment.topCenter,
          repeat: ImageRepeat.repeatY,
          color: Colors.red,
          colorBlendMode: BlendMode.colorDodge,
        ),
        width: 300,
        height: 300, color: Colors.yellow, ), ); }}Copy the code

3.2. Load local images

Loading local images is a bit trickier, requiring images to be imported and configured

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300,
        height: 300,
        color: Colors.yellow,
        child: Image.asset("images/test.jpeg"),),); }}Copy the code

3.3. Realize rounded corner image

The rounded corner effect in Flutter is also implemented using widgets.

3.3.1. Implement rounded avatar

Method 1: CircleAvatar

CircleAvatar can be implemented as a rounded avatar and can also be added as a child Widget:

const CircleAvatar({
  Key key,
  this.child, / / child widgets
  this.backgroundColor, // Background color
  this.backgroundImage, // Background image
  this.foregroundColor, // Foreground color
  this.radius, / / radius
  this.minRadius, // Minimum radius
  this.maxRadius, // Maximum radius
}) 
Copy the code

Let’s implement a circular avatar:

  • Note 1: Here we use NetworkImage, because backgroundImage requires us to pass in an ImageProvider;

    • ImageProvider is an abstract class that contains virtually all Image objects we created earlierimageProperty, which is an ImageProvider
  • Note 2: I’ve also added a text inside, but I’ve wrapped a Container around the text;

    • The Container is used to control the position of text in the Container.
class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: CircleAvatar(
        radius: 100,
        backgroundImage: NetworkImage("https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg"),
        child: Container(
          alignment: Alignment(0.. 5),
          width: 200,
          height: 200,
          child: Text("Sergeant Lewell.")))); }}Copy the code

Method 2: ClipOval

ClipOval can also implement rounded avatars, and is usually used with only avatars

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ClipOval(
        child: Image.network(
          "https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg",
          width: 200,
          height: 200,),),); }}Copy the code

Implementation method 3: Container+BoxDecoration

This is the way we did it when we talked about containers

3.3.2. Realize rounded corner pictures

Method 1: ClipRRect

ClipRRect is used to achieve rounded corners. You can set the size of rounded corners.

The implementation code is as follows, very simple:

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ClipRRect(
        borderRadius: BorderRadius.circular(10),
        child: Image.network(
          "https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg",
          width: 200,
          height: 200,),),); }}Copy the code

Method 2: Container+BoxDecoration

We’ll do that later when we talk about containers

Form widgets

One of the ways we interact with the user is with input fields, such as register, log in, and search. We collect input from the user and submit it to the server.

4.1. Use of TextField

4.1.1. Introduction of TextField

TextField is used to receive text input from the user. It provides a number of attributes. Let’s look at the source code:

  • But we don’t need to go through all of them. Most of the time, we just need to check whether a feature is included or not
const TextField({
  Key key,
  this.controller,
  this.focusNode,
  this.decoration = const InputDecoration(),
  TextInputType keyboardType,
  this.textInputAction,
  this.textCapitalization = TextCapitalization.none,
  this.style,
  this.strutStyle,
  this.textAlign = TextAlign.start,
  this.textAlignVertical,
  this.textDirection,
  this.readOnly = false,
  ToolbarOptions toolbarOptions,
  this.showCursor,
  this.autofocus = false.this.obscureText = false.this.autocorrect = true.this.maxLines = 1.this.minLines,
  this.expands = false.this.maxLength,
  this.maxLengthEnforced = true.this.onChanged,
  this.onEditingComplete,
  this.onSubmitted,
  this.inputFormatters,
  this.enabled,
  this.cursorWidth = 2.0.this.cursorRadius,
  this.cursorColor,
  this.keyboardAppearance,
  this.scrollPadding = const EdgeInsets.all(20.0),
  this.dragStartBehavior = DragStartBehavior.start,
  this.enableInteractiveSelection = true.this.onTap,
  this.buildCounter,
  this.scrollController,
  this.scrollPhysics,
}) 

Copy the code

Let’s look at some of the more common attributes:

  • Some properties are simple:keyboardTypeKeyboard type,styleSet the style,textAlignText alignment,maxLengthMaximum number of display lines, etc.;
  • decoration: Used to set the style associated with the input box
    • Icon: Sets the icon displayed on the left
    • LabelText: Displays a prompt text above the input box
    • HintText: placeholder text to display the prompt
    • Border: The border of the input box. By default, there is a border at the bottom, which can be removed by InputBorder. None
    • Filled: Whether to fill the input box. The default value is false
    • FillColor: indicates the filling color of the input box
  • controller:
  • onChanged: Listens for changes in the input box, passing in a callback function
  • onSubmitted: a function that is called back when down is clicked on the lower right corner of the keyboard

4.1.2. Style and listener of TextField

Let’s demonstrate the decoration property of the TextField and its listener:

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(20), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ TextFieldDemo() ], ), ); }}class TextFieldDemo extends StatefulWidget {
  @override
  _TextFieldDemoState createState() => _TextFieldDemoState();
}

class _TextFieldDemoState extends State<TextFieldDemo> {
  @override
  Widget build(BuildContext context) {
    return TextField(
      decoration: InputDecoration(
        icon: Icon(Icons.people),
        labelText: "username",
        hintText: "Please enter user name",
        border: InputBorder.none,
        filled: true,
        fillColor: Colors.lightGreen
      ),
      onChanged: (value) {
        print("onChanged:$value");
      },
      onSubmitted: (value) {
        print("onSubmitted:$value"); }); }}Copy the code

4.1.3. TextField的controller

We can add a Controller to the TextField, which we can use to set the initial value of the text or to listen for changes to the text.

In fact, Flutter creates a TextEditingController by default if we do not provide a Controller for TextField. This conclusion can be obtained by reading the source code:

  @override
  void initState() {
    super.initState();
    / /... Other code
    if (widget.controller == null)
      _controller = TextEditingController();
  }

Copy the code

We can also create a Controller ourselves to control something:

class _TextFieldDemoState extends State<TextFieldDemo> {
  final textEditingController = TextEditingController();

  @override
  void initState() {
    super.initState();

    // 1. Set the default value
    textEditingController.text = "Hello World";

    // 2. Listen for the text box
    textEditingController.addListener(() {
      print("textEditingController:${textEditingController.text}");
    });
  }
	
  / /... Omit the build method
}

Copy the code

4.2. Use of the Form

When we develop registration and login pages, there are usually multiple forms that need to fetch content or perform some validation at the same time. It would be troublesome to validate each TextField separately.

We know from front-end development that we can put multiple input tags into a form. Flutter also takes advantage of this idea: we can group input fields using forms to perform operations uniformly.

4.2.1. Basic use of Form

The Form Form is also a Widget where we can put our input field.

But the input field in the Form Form must be of type FormField

  • TextField is derived from StatefulWidget and is not a FormField type;
  • We can use TextFormField, which is similar to TextField and inherits from FormField;

We use the Form package to implement a registered page:

class FormDemo extends StatefulWidget {
  @override
  _FormDemoState createState() => _FormDemoState();
}

class _FormDemoState extends State<FormDemo> {
  @override
  Widget build(BuildContext context) {
    return Form(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
              icon: Icon(Icons.people),
              labelText: "User name or mobile phone number"
            ),
          ),
          TextFormField(
            obscureText: true,
            decoration: InputDecoration(
              icon: Icon(Icons.lock),
              labelText: "Password"
            ),
          ),
          SizedBox(height: 16,),
          Container(
            width: double.infinity,
            height: 44,
            child: RaisedButton(
              color: Colors.lightGreen,
              child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white),),
              onPressed: () {
                print("Click the register button."); },),) [,),); }}Copy the code

4.2.2. Save and obtain form data

When we have a form, we need to click on the register, we can get and save the data in the form at the same time. How can we do that?

  • 1. Listen for the register button click in the onPressed callback that we already listen for. (Of course, if there is too much nesting, we can extract it into a separate method later)
  • 2. When the button is clicked, obtain it at the same timeThe user nameandpasswordForm information.

How do I get form information for both username and password?

  • If we callForm's State objectThe save method calls the onSave callback to the TextFormField put in the Form:
TextFormField(
  decoration: InputDecoration(
    icon: Icon(Icons.people),
    labelText: "User name or mobile phone number"
  ),
  onSaved: (value) {
    print("User name:$value"); },),Copy the code
  • But is there any way we can get it when we click the buttonThe Form objectTo call its save method?

How can a Flutter get a State object that gets a StatefulWidget by reference?

Answer: By binding a GlobalKey.

Case code walkthroughs:

class FormDemo extends StatefulWidget {
  @override
  _FormDemoState createState() => _FormDemoState();
}

class _FormDemoState extends State<FormDemo> {
  final registerFormKey = GlobalKey<FormState>();
  String username, password;

  void registerForm() {
    registerFormKey.currentState.save();

    print("username:$username password:$password");
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: registerFormKey,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
              icon: Icon(Icons.people),
              labelText: "User name or mobile phone number"
            ),
            onSaved: (value) {
              this.username = value;
            },
          ),
          TextFormField(
            obscureText: true,
            decoration: InputDecoration(
              icon: Icon(Icons.lock),
              labelText: "Password"
            ),
            onSaved: (value) {
              this.password = value;
            },
          ),
          SizedBox(height: 16,),
          Container(
            width: double.infinity,
            height: 44,
            child: RaisedButton(
              color: Colors.lightGreen,
              child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white),), onPressed: registerForm, ), ) ], ), ); }}Copy the code

4.2.3. Verify the filled form data

In the form, we can add validators to inform the user if certain rules are not met

For example, we need an account and password. There are rules like this: The account and password cannot be empty.

Follow these steps to complete the verification process:

  • 1. Add a validator callback to TextFormField;
  • Calling the validate method on the Form’s State object calls back the function passed in by the Validator.

You can also add an attribute to TextFormField: Autovalidate

  • There is no need to call the validate method, which automatically verifies compliance;

Note: All content will be published on our official website. Later, Flutter will also update other technical articles, including TypeScript, React, Node, Uniapp, MPvue, data structures and algorithms, etc. We will also update some of our own learning experiences