In the last video, a quick review

In my opinion, ValueNotifier and ValueListenableBuilder bind one variable to one Widget, which is easy to use and easy to understand. Using ValueListenableBuilder in many-to-one bindings can lead to nesting hell, so that’s where MultiProvider comes in.

Previous articles:

Flutter: From ValueListenableBuilder to Provider

MultiProvider

When it comes to MultiProvider, it is a component in the Provider library that binds a Widget to multiple states. When it comes to provider library, we will always be associated with global state management, who knows, in fact, provider is also very good at single page management, it can even be said that the understanding of provider in single page management, then global management is not a problem.

So let’s just pick up where we left off in the last video with the last example, and write the code. Requirements are as follows: Two input boxes. When the first input box enters the 11-digit mobile phone number and the second input box enters the 6-digit verification code, the button changes color and responds to the click event.

Before writing the component code, we define the following two models:

class IsRightPhoneNumber extends ChangeNotifier { bool _isOK = false; bool get isOK => _isOK; set isOK(bool newValue) { _isOK = newValue; notifyListeners(); } } class IsRightCode extends ChangeNotifier { bool _isOK = false; bool get isOK => _isOK; set isOK(bool newValue) { _isOK = newValue; notifyListeners(); }}Copy the code

And you might wonder, why are these two models, and why are these two models useful? In the previous section, we didn’t go into the source code for ValueNotifier, so let’s look at the source code for ValueNotifier:

class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
  /// Creates a [ChangeNotifier] that wraps this value.
  ValueNotifier(this._value);

  /// The current value stored in this notifier.
  ///
  /// When the value is replaced with something that is not equal to the old
  /// value as evaluated by the equality operator ==, this class notifies its
  /// listeners.
  @override
  T get value => _value;
  T _value;
  set value(T newValue) {
    if (_value == newValue)
      return;
    _value = newValue;
    notifyListeners();
  }

  @override
  String toString() => '${describeIdentity(this)}($value)';
}
Copy the code

If you look closely, the models we defined are identical to ValueNotifier, and the most important methods of The ChangeNotifier are notifyListeners(). It’s just a notification telling the interface that the value has changed and it’s time to refresh the interface.

We can say that our custom model is a simplified and specialized version of ValueNotifier. Simplified because we do not follow the ValueListenable protocol, specialized because we specify generics in ValueNotifier as the types we define. It is also possible to write custom models directly from ValueNotifier.

Here is the main code to enter the interface:

As in the previous section, I’ll attach the rest of the non-topic logic code at the end.

Final _isRightPhoneNumber = IsRightPhoneNumber(); final _isRightCode = IsRightCode(); Override Widget Build (BuildContext context) {/// We use the MultiProvider component to build the top layer of the page. Providers: [ChangeNotifierProvider(create: (context) => _isRightPhoneNumber, ), ChangeNotifierProvider( create: (context) => _isRightCode, ), ], child: GestureDetector(Child: Scaffold(appBar: appBar (title: Text("MultiProvider two inputs bind one button "),), body: Container(margin: Const EdgeInsets. FromLTRB (16, 40, 16, 0), child: ListView(children: [_textField(title: "enter 11 bits ", limit: 11, onChanged: (inputString) { _isRightPhoneNumber.isOK = inputString.length == 11; }), _textField( title: "Enter a 6-digit string ", limit: 6, onChanged: (inputString) { _isRightCode.isOK = inputString.length == 6; }), <IsRightPhoneNumber, IsRightCode, bool> IsRightPhoneNumber and IsRightCode, return bool, Selector2<IsRightPhoneNumber, IsRightCode, bool> Selector2<IsRightPhoneNumber, IsRightCode, bool> (context, value1, value2) => value1.isOK && value2.isOK, builder: (context, isAllRight, child) { return Container( margin: const EdgeInsets.fromLTRB(0, 30, 0, 0), child: RaisedButton( color: _buttonColor(isAllRight), shape: BeveledRectangleBorder( borderRadius: BorderRadius. Circular (0),), child: Container(child: Center(child: Text("Selector2+ custom model confirm modification ", style: TextStyle( fontSize: 16, color: isAllRight ? Colors.white : DSColor.colorA3A4A4, ), ), ), height: 48, ), onPressed: () {if (isAllRight) {}},),);},),),),),), onTap: () = > print (" keyboard fold method "),),); }Copy the code

Code interpretation:

One key point is that we built the top layer of the page using the MultiProvider component and registered to listen for _isRightPhoneNumber and _isRightCode;

The other key is the use of the Selector2 component. First of all, don’t be scared by the

generics. It actually defines two input parameters as IsRightPhoneNumber and IsRightCode types. Returns a bool, which is used in Selector2. Selector2’s Builder is very similar to ValueListenableBuilder’s builder, in that widgets are created using variables. And change the Widget as the variable changes, which is actually controlled by the selector, whose essential type in this case is a bool Function(IsRightPhoneNumber, IsRightCode).
,>

The Selector and the Consumer

Selector2 is a component that has two input parameters that are merged into a new output parameter. There are also components such as Selector3, Selector4, Selector5, and Selector6 that can be used.

In addition to the Selector family of components, there is also a Consumer component, which I understand to be a simplified version of the Selector component. Instead of taking the Selector and shouldRebuild arguments, its Builder method will directly define the generic arguments in order. Create and update widgets. Our button here could have been built using Consumer2 as well, with the following code:

Consumer2<IsRightPhoneNumber, IsRightCode>( builder: (context, IsRightPhoneNumber value1, IsRightCode value2, child) { final isAllRight = value1.isOK && value2.isOK; return Container( margin: const EdgeInsets.fromLTRB(0, 30, 0, 0), child: RaisedButton( color: _buttonColor(isAllRight), shape: BeveledRectangleBorder( borderRadius: BorderRadius.circular(0), ), child: Container(child: Center(child: Text("Consumer2+ custom model confirm modification ", style: TextStyle(fontSize: 16, color: isAllRight ? Colors.white : DSColor.colorA3A4A4, ), ), ), height: 48, ), onPressed: () { if (isAllRight) {} }, ), ); },),Copy the code

In general, whether it’s a Selector or a Consumer, it’s basically the same as ValueListenableBuilder in terms of how it’s used, and it’s even more elaborate, except that there’s a Selector method, ShouldRebuild is also used to determine whether the new value and the old value really need to be updated. Overall, the single-page multi-parameter control Widget is very developer friendly both in terms of coding and ease of use.

Non-business code pulled out

CV the following code into the class of each example.

Widget _textField({ String title, int limit, ValueChanged<String> onChanged, }) { return Column( children: [ TextField( inputFormatters: [LengthLimitingTextInputFormatter(limit)], decoration: InputDecoration( hintText: title, hintStyle: TextStyle( color: Color(0xFFA3A4A4), fontSize: 14, ), enabledBorder: BorderSide: borderSide (color: color (0xFF303131)),), focusedBorder: BorderSide: borderSide (color: color (0xFFC3B5AB)),),), keyboardType: TextInputType.number, onChanged: onChanged, ), _spacer23(), ], ); } Widget _spacer23() { return SizedBox( height: 23, ); } Color _buttonColor(bool value) { if (value) { return Color(0xFFC3B5AB); } else { return Color(0xFF303131); }}Copy the code

In the next section, let’s talk about my understanding of global management.

Reference Documents:

Flutter component | ValueListenableBuilder partial refresh small expert

You have to have a state management Provider

This article is participating in the “Nuggets 2021 Spring Recruitment Campaign”, click to see the details of the campaign