Flutter仿微信的下拉彈框

在移動開發中,下拉彈框是一種很常見的選擇交互方式,效果以下圖所示。
在這裏插入圖片描述
對於這種彈框,咱們可使用Dialog來實現,下面是自定義彈框的主要代碼。canvas

Color _bgColor = Colors.white;
double cellHeight = 34;
double cellWidth=120;

typedef ClickCallBack = void Function(int selectIndex, String selectText);

class PopMenus {
  static void showPop(
      {@required BuildContext context,
      @required List<String> listData,
      @required String selText,
      ClickCallBack clickCallback}) {
    Widget _buildMenuLineCell(dataArr) {
      return ListView.separated(
        itemCount: dataArr.length,
        physics: const NeverScrollableScrollPhysics(),
        itemBuilder: (BuildContext context, int index) {
          return GestureDetector(
              onTap: () {
                Navigator.pop(context);
                if (clickCallback != null) {
                  clickCallback(index, listData[index]);
                }
              },
              child: Container(
                height: cellHeight,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    selText==dataArr[index]?
                    Text(dataArr[index], style: TextStyle(fontSize: 16,color:
                    Colors.blue)):Text(dataArr[index], style: TextStyle(fontSize: 16))
                  ],
                ),
              ));
        },
        separatorBuilder: (context, index) {
          return Divider(
            height: 0.1,
            color: Color(0xFFE6E6E6),
          );
        },
      );
    }

    _buildMenusView(dataArr) {
      var cellH = dataArr.length * cellHeight;
      var navH = ScreenUtils.navigationBarHeight;
      navH = navH - ScreenUtils.topSafeHeight;
      var leftP=(ScreenUtils.screenWidth-cellWidth)/2;
      return Positioned(
        left: leftP,
        top: navH-10,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: <Widget>[
            Container(
              padding: EdgeInsets.only(right: 10),
              child: TriangleUpWidget(height: 10,width: 14),
            ),
            ClipRRect(
                borderRadius: BorderRadius.circular(2),
                child: Container(
                    color: _bgColor,
                    width: cellWidth,
                    height: cellH,
                    child: _buildMenuLineCell(dataArr)))
          ],
        ),
      );
    }

    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (context) {
          return BasePopMenus(child: _buildMenusView(listData));
        });
  }
}

class BasePopMenus extends Dialog {
  BasePopMenus({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Material(
      type: MaterialType.transparency,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          GestureDetector(onTap: () => Navigator.pop(context)),
          child
        ],
      ),
    );
  }
}

若是須要改變彈框的位置,能夠修改_buildMenusView()方法中的Positioned組件的邊距代碼。上面的代碼中用到了一個自定義三角形,代碼以下。ide

class TriangleUpPainter extends CustomPainter {

  Color color; //填充顏色
  Paint _paint; //畫筆
  Path _path; //繪製路徑
  double angle; //角度

  TriangleUpPainter() {
    _paint = Paint()
      ..strokeWidth = 1.0 //線寬
      ..color = Colors.white
      ..isAntiAlias = true;
    _path = Path();
  }

  @override
  void paint(Canvas canvas, Size size) {
    final baseX = size.width;
    final baseY = size.height;
    //起點
    _path.moveTo(baseX*0.5, 0);
    _path.lineTo(baseX, baseY);
    _path.lineTo(0, baseY);
    canvas.drawPath(_path, _paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

class TriangleUpWidget extends StatefulWidget {
  double height;
  double width;

  TriangleUpWidget({Key key, this.height = 14, this.width = 16}) : super(key:
  key);

  @override
  CoreTriangleState createState() => CoreTriangleState();
}

class CoreTriangleState extends State<TriangleUpWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
        height: widget.height,
        width: widget.width,
        child: CustomPaint(
          painter: TriangleUpPainter(),
        ));
  }
}

最後,在須要彈框的地方,調用咱們自定義的彈框組件便可,以下所示。ui

PopMenus.showPop(context: context, listData: segmentLists,
      selText: selectedTab, clickCallback: (int index, String value){
                  
 });
相關文章
相關標籤/搜索