美文网首页
Flutter入门学习记录【四】

Flutter入门学习记录【四】

作者: 有点健忘 | 来源:发表于2019-12-20 17:39 被阅读0次

    https://flutterchina.club/widgets/input/
    Flutter入门学习记录【四】

    表单

    1. Form
    final _formKey = GlobalKey<FormState>();
    //
              Form(
                key: _formKey,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    TextFormField(
                      decoration: const InputDecoration(
                        hintText: 'Enter your email',
                      ),
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'Please enter some text';
                        }
                        return null;
                      },
                    ),
                    TextFormField(
                      decoration: const InputDecoration(
                        hintText: 'Enter your email password',
    
                      ),
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'Please enter your password';
                        }
                        return null;
                      },
                    ),
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 16.0),
                      child: RaisedButton(
                        onPressed: () {
                          // Validate will return true if the form is valid, or false if
                          // the form is invalid.
                          if (_formKey.currentState.validate()) {
                            // Process data.
                          }
                          
                        },
                        child: Text('Submit'),
                      ),
                    ),
                  ],
                ),
              )
    

    点击按钮,autovalidate为false的情况,执行_formKey.currentState.validate()会对上边的TextFormField的内容进行验证,如果不符合验证条件就会显示错误的提示文字

    image.png

    参数解析

      const Form({
        Key key,
        @required this.child,
        this.autovalidate = false,
        this.onWillPop,
        this.onChanged,
      })
      /// If true, form fields will validate and update their error text
      /// immediately after every change. Otherwise, you must call
      /// [FormState.validate] to validate.
    //默认是false,你必须手动调用FormState的vallidate方法才会执行判断,如果为true,获取焦点就会自动做判断的
      final bool autovalidate;
      /// Called when one of the form fields changes.
      ///任一一个FormField发生改变的时候都会回调这里,好像没啥用
      /// In addition to this callback being invoked, all the form fields themselves
      /// will rebuild.
      final VoidCallback onChanged;
    
      /// Enables the form to veto attempts by the user to dismiss the [ModalRoute]
      /// that contains the form.
      ///简单点说,就是执行页面后退功能的时候也就是pop当前页面的时候,根据返回结果来决定是否 阻止后退,为false阻止,为true不阻止
      /// If the callback returns a Future that resolves to false, the form's route
      /// will not be popped.
      final WillPopCallback onWillPop;
    //比如
                onWillPop: (){
                  return Future.value(false);
                }
    

    TextFormField

    这个和普通的TextFiled参数差不多
    有些区别主要就是回调了,比如

        ValueChanged<String> onChanged,
        GestureTapCallback onTap,
        VoidCallback onEditingComplete,
        ValueChanged<String> onFieldSubmitted,
        FormFieldSetter<String> onSaved,
        FormFieldValidator<String> validator,
        List<TextInputFormatter> inputFormatters,
    

    RawKeyboardListener

    交互

    1. LongPressDraggable
      长按可以拖动
      const LongPressDraggable({
        Key key,
        @required Widget child,//默认显示的widget
        @required Widget feedback,//长按以后跟随手指移动的widget
        T data,//到时候传给一个DragTarget的控件,用来判断是否接收
        Axis axis,
        Widget childWhenDragging,//可有可无,长按触发以后用来替换默认的child的
        Offset feedbackOffset = Offset.zero,
        DragAnchor dragAnchor = DragAnchor.child,//锚点
        int maxSimultaneousDrags,
        VoidCallback onDragStarted,
        DraggableCanceledCallback onDraggableCanceled,//同下,也有对应的数据
        DragEndCallback onDragEnd,//这个回调里会有偏移量,速率数据
        VoidCallback onDragCompleted,
        this.hapticFeedbackOnStart = true,
        bool ignoringFeedbackSemantics = true,
      }) 
    
    1. 关联的DragTarget
      const DragTarget({
        Key key,
        @required this.builder,
        this.onWillAccept,// 回调里返回的参数就是上边那个LongPressDraggable里data,当那个拖动到这个控件范围的时候,返回true表示接收,会存到build的回调参数candidateData,返回false会存到build的回调参数rejectedData里
        this.onAccept,//松开手指,上边那个onWillAccept返回true的话会走这里,否则走下边那个
        this.onLeave,//另外手指从target范围移出去以后也会走这里
      })
    

    简单测试demo

     var _dragResult="drag to here please";
    
                           DragTarget(
                    builder: (BuildContext context, List<String> candidateData,
                        List<dynamic> rejectedData) {
                      print(
                          'builder==========${candidateData.length}==========${rejectedData.length}');
                      if (candidateData.length > 0) {
                        _dragResult="you'are accepted,please release your finger";
                      }else if(rejectedData.length>0){
                        _dragResult="you'are rejected,please release your finger";
                      }
                      return Container(
                        width: 240,
                        height: 100,
                        alignment: Alignment.center,
                        child: Text(_dragResult,style: _defaultStyle,),
                        decoration: BoxDecoration(
                            border: Border.all(color: Colors.deepPurpleAccent)),
                      );
                    },
                    onWillAccept: (willAccept) {
                      print('onWillAccept=========$willAccept');
                      return willAccept == "test";
                    },
                    onAccept: (accept) {
                      print('accept==========$accept');
                      _dragResult="accept:$accept";
                    },
                    onLeave: (leave) {
                      print('leave============$leave');
                      _dragResult="leave:$leave";
                    },
                  ),
    
    image.png

    LongPressDraggable触发以后DragTarget就会执行一次builder,完事手指移动到DragTarget范围的时候会走onWillAccept方法,返回true的话会继续走builder,当手指移出DragTarget范围的时候会执行onLeave,完事继续builder

    没搞懂rejectedData这个集合啥时候会有数据

    1. GestureDetector
      想给widget添加触摸事件可以用这个,我一般也就加个点击事件,用onTap即可
    
    
    1. Dismissible
      可以拖动的控件,最多拖动距离是控件自身的宽或者高
      const Dismissible({
        @required Key key,
        @required this.child,
        this.background,
        this.secondaryBackground,
        this.confirmDismiss,//根据返回的结果来决定是否dismiss
        this.onResize,//确定dismiss以后会回调这里N次
        this.onDismissed,//控件彻底消失以后回调
        this.direction = DismissDirection.horizontal,//可以滑动的方向
        this.resizeDuration = const Duration(milliseconds: 300),
        this.dismissThresholds = const <DismissDirection, double>{},//阀值默认0.4也就是拖动40%的距离
        this.movementDuration = const Duration(milliseconds: 200),
        this.crossAxisEndOffset = 0.0,//偏移量,高度或者宽度【根据主轴来定】的多少倍
        this.dragStartBehavior = DragStartBehavior.start,
      })
    
      /// A widget that is stacked behind the child. If secondaryBackground is also
      /// specified then this widget only appears when the child has been dragged
      /// down or to the right.
    //往右往上滑动的时候底层显示的widget,如果secondary没设置,往左往下也是这个
      final Widget background;
    
      /// A widget that is stacked behind the child and is exposed when the child
      /// has been dragged up or to the left. It may only be specified when background
      /// has also been specified.
    //往左往下滑动的时候显示的wiget,如果设置了这个,上边那个background必须设置
    //assert(secondaryBackground == null || background != null),
      final Widget secondaryBackground;
    
      /// Defines the end offset across the main axis after the card is dismissed.
      ///滑到最后横轴的偏移量,
      /// If non-zero value is given then widget moves in cross direction depending on whether
      /// it is positive or negative.
      final double crossAxisEndOffset;
    

    demo

                  Text("place holder start",style: _defaultStyle,),
                  Dismissible(
                    key: Key("dismiss"),
                    child: Text("Dismissible",style: TextStyle(color: Colors.deepPurple, fontSize: 25,
    backgroundColor: Colors.lightBlue)),
                    confirmDismiss: (dismissDirection) {
                      print('confirmDismiss===========${dismissDirection}');
                      return Future.value(true);
                    },
                    onDismissed: (dismissDirection) {
                      print('onDismissed===========${dismissDirection}');
                    },
                    crossAxisEndOffset: 2,
                    background: Text("background",style: _defaultStyle,),
                    secondaryBackground: Text("secondaryBackground",style: _defaultStyle,),
                  ),
                  Text("place holder end",style: _defaultStyle,),
    

    看图可以发现:
    background或者secondaryBackground的宽高由child来决定的,图上明显少了个字母d
    crossAxisEndOffset:我们这里是水平拖动,这个偏移是垂直方向的,child高度的2倍,如果是负的,是往上偏移


    初始样子.png
    拖动到最终的样子.png

    异步 Widgets

    1. FutureBuilder
      const FutureBuilder({
        Key key,
        this.future,//一个future到时候返回的数据类型也是T
        this.initialData,//初始化数据,泛型T
        @required this.builder,//构建widget
      })
    

    demo
    就是个textview,初始化显示loading,过5秒显示success

              FutureBuilder(
                builder: (context, snapshot) {
                  print('build=========${snapshot.connectionState}===${snapshot.data}');
    //当然可以根据连接状态返回不同的widget
                  return Text("${snapshot.data}");
                },
                initialData: "loading",
                future: Future.delayed(Duration(seconds: 5), () {//延迟5秒模拟异步操作
                  return "success";
                }),
              ),
    
    1. StreamBuilder
      看起来和上边那个差不多,参数都差不多
              StreamBuilder(builder: (context,  snapshot){
                print('build=========${snapshot.connectionState}===${snapshot.data}');
                if (snapshot.hasError)
                  return Text('Error: ${snapshot.error}');
                switch (snapshot.connectionState) {
                  case ConnectionState.none: return Text('Select lot');
                  case ConnectionState.waiting: return Text('Awaiting bids...');
                  case ConnectionState.active: return Text('\$${snapshot.data}');
                  case ConnectionState.done: return Text('\$${snapshot.data} (closed)');
                }
                return null; // unreachable
              },stream: _createStream(),),
    
      Stream<int> _createStream() {
        return Stream.periodic(Duration(seconds: 4),(computationCount){
          return computationCount;
        });
      }
    

    相关文章

      网友评论

          本文标题:Flutter入门学习记录【四】

          本文链接:https://www.haomeiwen.com/subject/odtvnctx.html