上篇文章说了 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("我是一个可变的"),
          ),
        ),
      );
    },
  );
};

Kapture 2019-03-28 at 15.58.12.gif

这里就是弹出的 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("我是一个可变的"),
        ),
      ),
    );
  },
);

Kapture 2019-03-28 at 17.34.38.gif

分析一下属性的作用

context

这个不方便展开解释,可以自己查找 context 的相关文章

barrierLabel

分析一下这个东西的用处 20190329091122.png 20190329091144.png 这里有一个 override,说明虽然属性是私有的,但是父类中可以获取到这个属性

最终到达父类的 ModalRoute 20190329091316.png

看注释的说法,这个是用于语义化的

barrierDismissible

是否可以点击背景关闭

transitionDuration

这个是从开始到完全显示的时间

barrierColor

背景颜色

pageBuilder

这个参数是一个方法,入参是 context,animation,secondaryAnimation,返回一个 Widget

这个 Widget 就是显示在页面上的 dialog

transitionBuilder

路由显示和隐藏的过程,这里入参是 animation,secondaryAnimation 和 child, 其中 child 是 是 pageBuilder 构建的 widget

从其他位置进入

img

代码

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 位右偏移一屏

缩放效果

Kapture 2019-03-29 at 13.37.48.gif

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

Kapture 2019-03-29 at 13.43.45.gif

后记

组合利用 showGeneralDialog 的参数可以达成各种酷炫的效果,比如可以结合TransformMatrix4达到各种效果

完整代码查看github

以上