上篇文章说了 showDialog 方法的使用
但是这个方法有很多东西是固定的
比如背景颜色,转换的时长和样式等等,很多东西你很难去自定义
本篇我使用另一个方法showGeneralDialog
来做一些自定义
准备工作
同上一章一样,定义一个通用方法
Widget buildButton(
String text,
Function onPressed, {
Color color = Colors.white,
}) {
return FlatButton(
color: color,
child: Text(text),
onPressed: onPressed,
);
}
简单使用
这里有几个参数,虽然方法签名上只有 2 个@required
注解的参数
但事实上,在我当前的版本环境下,如下代码中所有的参数都是必填项,不填会报错
我的运行环境是这样的
flutter --version
Flutter 1.3.14 • channel dev • https://github.com/flutter/flutter.git
Framework • revision 8e7e435706 (6 days ago) • 2019-03-21 15:31:46 -0700
Engine • revision d4d4883216
Tools • Dart 2.2.1 (build 2.2.1-dev.2.0 None)
代码在这里
showGeneralDialog(
context: context,
barrierLabel: "你好",
barrierDismissible: true,
transitionDuration: Duration(milliseconds: 300),
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return Center(
child: Material(
child: Container(
color: Colors.black.withOpacity(animation.value),
child: Text("我是一个可变的"),
),
),
);
},
);
};
这里就是弹出的 dialog 了
这里有一个背景色的选项
showGeneralDialog(
context: context,
barrierLabel: "你好",
barrierDismissible: true,
transitionDuration: Duration(milliseconds: 1000), //这个是时间
barrierColor: Colors.black.withOpacity(0.5), // 添加这个属性是颜色
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return Center(
child: Material(
child: Container(
color: Colors.black.withOpacity(animation.value),
child: Text("我是一个可变的"),
),
),
);
},
);
分析一下属性的作用
context
这个不方便展开解释,可以自己查找 context 的相关文章
barrierLabel
分析一下这个东西的用处
这里有一个 override,说明虽然属性是私有的,但是父类中可以获取到这个属性
最终到达父类的 ModalRoute
看注释的说法,这个是用于语义化的
barrierDismissible
是否可以点击背景关闭
transitionDuration
这个是从开始到完全显示的时间
barrierColor
背景颜色
pageBuilder
这个参数是一个方法,入参是 context,animation,secondaryAnimation,返回一个 Widget
这个 Widget 就是显示在页面上的 dialog
transitionBuilder
路由显示和隐藏的过程,这里入参是 animation,secondaryAnimation 和 child, 其中 child 是 是 pageBuilder 构建的 widget
从其他位置进入
代码
buildButton("从左进入", () => showDialogWithOffset(handle: fromLeft)),
buildButton("从右进入", () => showDialogWithOffset(handle: fromRight)),
buildButton("从上进入", () => showDialogWithOffset(handle: fromTop)),
buildButton("从下进入", () => showDialogWithOffset(handle: fromBottom)),
buildButton("从左上进入", () => showDialogWithOffset(handle: fromTopLeft)),
typedef Offset OffsetHandle(Animation animation);
showDialogWithOffset({OffsetHandle handle = fromLeft}) {
showGeneralDialog(
context: context,
barrierColor: Colors.black.withOpacity(0.5),
barrierLabel: "",
barrierDismissible: true,
transitionDuration: const Duration(milliseconds: 1000),
pageBuilder: (
BuildContext context,
Animation animation,
Animation secondaryAnimation,
) {
return Center(
child: Material(
child: Container(
child: Text("我是dialog"),
),
),
);
},
transitionBuilder: (ctx, animation, _, child) {
return FractionalTranslation(
translation: handle(animation),
child: child,
);
},
);
}
Offset fromLeft(Animation animation) {
return Offset(animation.value - 1, 0);
}
Offset fromRight(Animation animation) {
return Offset(1 - animation.value, 0);
}
Offset fromTop(Animation animation) {
return Offset(0, animation.value - 1);
}
Offset fromBottom(Animation animation) {
return Offset(0, 1 - animation.value);
}
Offset fromTopLeft(Animation anim) {
return fromLeft(anim) + fromTop(anim);
}
这里使用了一个 Widget 叫 FractionalTranslation
接收一个 Offset 作为参数,来移动 child 的 widget
里面的单位是相对,而不是绝对
也就是 Offset 的 x=0 时在原地,-1 为左偏移一屏,1 位右偏移一屏
缩放效果
showGeneralDialog(
context: context,
barrierLabel: "",
barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: const Duration(milliseconds: 500),
barrierDismissible: true,
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return Center(
child: Image.asset("assets/demo.png"),
);
},
transitionBuilder: (_, anim, __, child) {
return ScaleTransition(
scale: anim,
child: child,
);
},
);
利用了 Scaletransition 类,里面需要一个Animation<double>
我这里直接把入参的 anim 传过去就可以了
还支持 alignment 参数,也就是从哪里缩放过来
简单修改一下能达到如下效果
showGeneralDialog(
context: context,
barrierLabel: "",
barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: const Duration(milliseconds: 500),
barrierDismissible: true,
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return Center(
child: Image.asset("assets/demo.png"),
);
},
transitionBuilder: (_, anim, __, child) {
return ScaleTransition(
alignment: Alignment.bottomCenter, // 添加这个
scale: anim,
child: child,
);
},
);
后记
组合利用 showGeneralDialog 的参数可以达成各种酷炫的效果,比如可以结合Transform
和Matrix4
达到各种效果
完整代码查看github
以上