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;
}
}