美文网首页Flutter 实战Flutter
Flutter入门(35):Flutter 组件之 Bottom

Flutter入门(35):Flutter 组件之 Bottom

作者: Maojunhao | 来源:发表于2020-10-14 13:58 被阅读0次

    1. 基本介绍

    BottomSheet 是一种常见的上拉框,个人感觉 showModalBottomSheet 更为常用一点。

    2. 示例代码

    代码下载地址。如果对你有帮助的话记得给个关注,代码会根据我的 Flutter 专题不断更新。

    3. 属性介绍

    BottomSheet 属性 介绍
    animationController 动画控制器
    enableDrag 是否可以拖动,默认为 true
    onDragStart 开始拖拽回调,没有找到具体使用场景,后续更新
    onDragEnd 结束拖拽回调,没有找到具体使用场景,后续更新
    backgroundColor 背景色
    elevation 阴影高度
    shape 形状 BorderShape
    clipBehavior 剪切方式
    onClosing 关闭回调函数
    builder 构建函数

    4. BottomSheet 详解

    BottomSheet 作为组件直接使用的时候比较少,比如配合 Scaffold 的子属性使用,可以理解为展示在屏幕下方的一个组件。

    import 'package:flutter/material.dart';
    
    class FMBottomSheetVC extends StatefulWidget{
      @override
      FMBottomSheetState createState() => FMBottomSheetState();
    }
    
    class FMBottomSheetState extends State <FMBottomSheetVC>{
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return _scaffold(context);
      }
    
      Scaffold _scaffold(context){
        return Scaffold(
          appBar: AppBar(title: Text("BottomSheet"),),
          body: Center(
            // child: BottomSheetBtn(),
          ),
          bottomSheet: _bottomSheet(context),
          floatingActionButton: FloatingActionButton(
            child: Text("返回"),
            onPressed: (){
              Navigator.pop(context);
            },
          ),
        );
      }
    
      BottomSheet _bottomSheet(context){
        return BottomSheet(
          onClosing: (){
            print("closed");
          },
    
          builder: (context){
            return Container(
              height: 300,
              color: Colors.yellow,
              alignment: Alignment.centerLeft,
              child: Text("BottomSheet In Scaffold"),
            );
          },
        );
      }
    }
    
    BottomSheet.png

    5. showModalBottomSheet 详解

    showModalBottomSheet 是一个直接调起 BottomSheet 的 api,使用频率较高。

    import 'package:flutter/material.dart';
    
    class FMBottomSheetVC extends StatefulWidget{
      @override
      FMBottomSheetState createState() => FMBottomSheetState();
    }
    
    class FMBottomSheetState extends State <FMBottomSheetVC>{
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return _scaffold(context);
      }
    
      Scaffold _scaffold(context){
        return Scaffold(
          appBar: AppBar(title: Text("BottomSheet"),),
          body: Center(
            child: _raisedButton(context),
          ),
          // bottomSheet: _bottomSheet(context),
          // floatingActionButton: FloatingActionButton(
          //   child: Text("返回"),
          //   onPressed: (){
          //     Navigator.pop(context);
          //   },
          // ),
        );
      }
    
      BottomSheet _bottomSheet(context){
        return BottomSheet(
          onClosing: (){
            print("closed");
          },
    
          builder: (context){
            return Container(
              height: 300,
              color: Colors.yellow,
              alignment: Alignment.centerLeft,
              child: Text("BottomSheet In Scaffold"),
            );
          },
        );
      }
    
      RaisedButton _raisedButton(context){
        return RaisedButton(
          child: Text("showModalBottomSheet"),
          onPressed: (){
            showModalBottomSheet(
              context: context,
              builder: (context){
                return Container(
                  width: 414,
                  height: 300,
                  color: Colors.red,
                  alignment: Alignment.centerLeft,
                  child: Text("showModalBottomSheet", style: TextStyle(color: Colors.white),),
                );
              },
            );
          },
        );
      }
    }
    
    showModalBottomSheet.gif

    6. showBottomSheet 详解

    showBottomSheet 对新手可能不太友好,它的实际调用是 Scaffold.of(context).showBottomSheet,.of(context) 方法在当前同一层级是拿不到 Scaffold Widget 的,所以会报错,需要在封装一层 class 进行使用。

    6.1 常规报错

    ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
    The following assertion was thrown while handling a gesture:
    No Scaffold widget found.
    FMBottomSheetVC widgets require a Scaffold widget ancestor.
    The specific widget that could not find a Scaffold ancestor was:
      FMBottomSheetVC
    The ancestors of this widget were:
      ...
      Semantics
      Builder
      RepaintBoundary-[GlobalKey#26d4e]
      IgnorePointer
      AnimatedBuilder
      ...
    Typically, the Scaffold widget is introduced by the MaterialApp or WidgetsApp widget at the top of
    your application widget tree.
    
    When the exception was thrown, this was the stack:
    #0      debugCheckHasScaffold.<anonymous closure> (package:flutter/src/material/debug.dart:114:7)
    #1      debugCheckHasScaffold (package:flutter/src/material/debug.dart:125:4)
    #2      showBottomSheet (package:flutter/src/material/bottom_sheet.dart:725:10)
    #3      FMBottomSheetState._raisedButton.<anonymous closure> (package:FMStudyApp/Widgets/Material_components/bottomsheet.dart:53:9)
    #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
    #5      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1098:38)
    #6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
    #7      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
    #8      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
    #9      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:219:7)
    #10     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:477:9)
    #11     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:78:12)
    #12     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:124:9)
    #13     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
    #14     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:122:18)
    #15     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:108:7)
    #16     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:220:19)
    #17     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
    #18     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
    #19     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
    #20     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
    #24     _invoke1 (dart:ui/hooks.dart:267:10)
    #25     _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)
    (elided 3 frames from dart:async)
    
    Handler: "onTap"
    Recognizer:
      TapGestureRecognizer#1116e
    ════════════════════════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by gesture ═══════════════════════════════════════════════════════════════
    The following assertion was thrown while handling a gesture:
    No Scaffold widget found.
    
    FMBottomSheetVC widgets require a Scaffold widget ancestor.
    The specific widget that could not find a Scaffold ancestor was: FMBottomSheetVC
      dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#da548]]
      state: FMBottomSheetState#0bb6b
    The ancestors of this widget were: 
      : MaterialApp
        state: _MaterialAppState#e550a
      : MyApp
      ...
    
    Typically, the Scaffold widget is introduced by the MaterialApp or WidgetsApp widget at the top of your application widget tree.
    
    When the exception was thrown, this was the stack: 
    #0      debugCheckHasScaffold.<anonymous closure> (package:flutter/src/material/debug.dart:114:7)
    #1      debugCheckHasScaffold (package:flutter/src/material/debug.dart:125:4)
    #2      showBottomSheet (package:flutter/src/material/bottom_sheet.dart:725:10)
    #3      FMBottomSheetState._raisedButton.<anonymous closure> (package:FMStudyApp/Widgets/Material_components/bottomsheet.dart:53:9)
    #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
    ...
    Handler: "onTap"
    Recognizer: TapGestureRecognizer#1116e
      debugOwner: GestureDetector
      state: possible
      won arena
      finalPosition: Offset(214.5, 497.0)
      finalLocalPosition: Offset(106.5, 17.0)
      button: 1
      sent tap down
    ════════════════════════════════════════════════════════════════════════════════════════════════════
    
    

    No Scaffold widget found.
    Typically, the Scaffold widget is introduced by the MaterialApp or WidgetsApp widget at the top of
    your application widget tree.

    6.2 解决方案

    将 RaisedButton 单独用一个 class 封装一层即可。

    import 'package:flutter/material.dart';
    
    class FMBottomSheetVC extends StatefulWidget{
      @override
      FMBottomSheetState createState() => FMBottomSheetState();
    }
    
    class FMBottomSheetState extends State <FMBottomSheetVC>{
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        // return _materialApp(context);
        return _scaffold(context);
      }
    
      Scaffold _scaffold(context){
        return Scaffold(
          appBar: AppBar(title: Text("BottomSheet"),),
          body: Center(
            // child: _raisedButton(context),
            child: BottomSheetBtn(),
          ),
          // bottomSheet: _bottomSheet(context),
          // floatingActionButton: FloatingActionButton(
          //   child: Text("返回"),
          //   onPressed: (){
          //     Navigator.pop(context);
          //   },
          // ),
        );
      }
    
      BottomSheet _bottomSheet(context){
        return BottomSheet(
          onClosing: (){
            print("closed");
          },
    
          builder: (context){
            return Container(
              height: 300,
              color: Colors.yellow,
              alignment: Alignment.centerLeft,
              child: Text("BottomSheet In Scaffold"),
            );
          },
        );
      }
    
      RaisedButton _raisedButton(context){
        return RaisedButton(
          child: Text("showModalBottomSheet"),
          onPressed: (){
            showBottomSheet(
              context: context,
              builder: (context){
                return Container(
                  width: 414,
                  height: 300,
                  color: Colors.red,
                  alignment: Alignment.centerLeft,
                  child: Text("showModalBottomSheet", style: TextStyle(color: Colors.white),),
                );
              },
            );
          },
        );
      }
    }
    
    class BottomSheetBtn extends StatelessWidget{
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return RaisedButton(
          child: Text("showBottomSheet"),
          onPressed: (){
    
            showBottomSheet(
              context: context,
              builder: (context){
                return Container(
                  width: 414,
                  height: 300,
                  color: Colors.red,
                  alignment: Alignment.centerLeft,
                  child: Text("showBottomSheet", style: TextStyle(color: Colors.white),),
                );
              },
            );
          },
        );
      }
    }
    

    可以用以下方法收起上拉框

    Navigator.pop(context);

    showBottomSheet.gif

    7. 技术小结

    上拉框是一个很常用的控件,其实除了唤起,其他属性和该组件并没有太大关系,考验的还是各种组件搭配使用的基本功。

    相关文章

      网友评论

        本文标题:Flutter入门(35):Flutter 组件之 Bottom

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