flutter 使用PopupRoute构建popupWindow弹窗并 动态刷新弹窗UI

flutter 开发app中,弹窗应该是必定会用到的,这里推荐使用PopupRoute去实现,怎么实现不是本文的重点,重点是动态刷新弹窗中控件的UI样式,比如下图:在弹窗中,点击第一个列表某个item,将item状态设为选中状态样式,其它item还原为未选中样式,并且 重置刷新第二个列表数据(第二个列表会根据第一个列表item的选择而呈现不同数据)。做过弹窗动态刷新UI的应该都知道,如果直接在当前页面使用setState,并不会使弹窗上的UI动态更新,那么该如何做呢?

废话不多说,这里提供一种我的实现方式,如果有更好的方法欢迎留言探讨,共同进步。

首先简单看下popupRoute弹窗的代码:

 RenderBox renderBox = _globalKey1.currentContext.findRenderObject();
 Rect box = renderBox.localToGlobal(Offset.zero) & renderBox.size;
  Navigator.push(context,DropDownMenuRoute(
                      position: box,//弹窗位置信息
                      menuWidth:ScreenUtil.getScreenW(context) - model.getAh(10),//弹窗宽度
                      menuHeight: model.getAh(549),//弹窗高度
                      offset: model.getAh(5),//偏移量
                      itemView:PopSubjectWidget(courseModel: model)//这里的PopSubjectWidget就是弹窗布局
                ));

可以看到弹窗的UI布局是通过自定义方式将view传进去的,那么我们可以把弹窗布局PopSubjectWidget单独抽出来构建(如果你是直接写在当前页面的一个widget,setState方法是不会起作用的)继承StatefulWidget,这样在PopSubjectWidget使用setState方法更新列表数据就可以刷新列表UI了。

最后贴一下自定义弹窗DropDownMenuRoute 代码:

import 'package:flutter/material.dart';

///自定义下拉弹窗  实现思路:
///通过自定义路由继承自PopupRoute,并结合Navigator.push使弹出的下拉列表能够覆盖在当前页面显示
///使用CustomSingleChildLayout组件,自定义SingleChildLayoutDelegate并结合RelativeRect来控制下拉列表显示的位置和高度
/// 使用SizeTransition实现下拉列表的下拉动画效果
class DropDownMenuRoute extends PopupRoute {
  ///点击控件的相对位置信息
  final Rect position;
  ///下拉控件高度
  final double menuHeight;
  ///下拉控件宽度
  final double menuWidth;
  ///弹窗控件布局
  final Widget itemView;
  ///偏移量
  final double offset;
  ///构造方法
  DropDownMenuRoute({this.position,this.menuWidth, this.menuHeight,this.offset,this.itemView});

  @override
  // TODO: implement barrierColor
  Color get barrierColor => null;

  @override
  // TODO: implement barrierDismissible
  bool get barrierDismissible => true;

  @override
  // TODO: implement barrierLabel
  String get barrierLabel => null;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    return CustomSingleChildLayout(
      delegate: DropDownMenuRouteLayout(position: position,menuWidth: menuWidth, menuHeight: menuHeight,offset:offset),
      ///这里加入了下拉动画
      child: SizeTransition(
        sizeFactor: Tween<double>(
            begin: 0.0,
            end: 1.0
        ).animate(animation),
        ///这里写具体布局,通过外面传入
        child:itemView,
      ),
    );
  }

  @override
  // TODO: implement transitionDuration
  Duration get transitionDuration => Duration(milliseconds: 300);

}
///下拉选择布局控制器
class DropDownMenuRouteLayout extends SingleChildLayoutDelegate {
  final Rect position;
  final double menuHeight;
  final double menuWidth;
  final double offset;
  DropDownMenuRouteLayout({this.position,this.menuWidth, this.menuHeight,this.offset});

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    ///控制下拉控件的宽高

    return BoxConstraints.loose(Size(menuWidth, menuHeight));
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    ///控制下拉控件显示位置,这里始终居于点击控件的下方
    return Offset(offset, position.bottom+5);
  }

  @override
  bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
    // TODO: implement shouldRelayout
    return true;
  }

}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个简单的 Flutter 代码示例,实现一个自定义的弹窗: ```dart import 'package:flutter/material.dart'; class MyDialog extends StatelessWidget { final String title; final String message; final VoidCallback onConfirm; MyDialog({ @required this.title, @required this.message, @required this.onConfirm, }); @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Padding( padding: EdgeInsets.all(16), child: Text( title, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 20, ), ), ), Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text( message, textAlign: TextAlign.center, style: TextStyle(fontSize: 16), ), ), SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ FlatButton( child: Text('取消'), onPressed: () { Navigator.of(context).pop(); }, ), SizedBox(width: 16), RaisedButton( child: Text('确定'), onPressed: onConfirm, ), ], ), ], ), ); } } ``` 在这个示例中,我们定义了一个 `MyDialog` 类,它接收一个标题、一个消息和一个确认回调函数作为参数。在 `build` 方法中,我们使用 `Dialog` 来实现弹窗使用 `Column` 和 `Row` 来组织弹窗中的内容。弹窗中包含一个标题、消息、一个“取消”按钮和一个“确定”按钮。我们使用 `FlatButton` 和 `RaisedButton` 来分别实现这两个按钮。 要使用这个自定义弹窗,只需要在需要的地方创建一个 `MyDialog` 实例,并将它传递给 `showDialog` 方法即可: ```dart showDialog( context: context, builder: (BuildContext context) { return MyDialog( title: '标题', message: '这是一条消息。', onConfirm: () { // 确认回调函数 }, ); }, ); ``` 在这个示例中,我们将 `MyDialog` 实例作为 `builder` 函数的返回值,传递给 `showDialog` 方法。当用户点击弹窗中的“确定”按钮时,传递给 `MyDialog` 的确认回调函数将被调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值