flutter 封装评论回复弹出键盘输入框组件

       本来打算开启下一段作死旅行的,后来想了想还是先把flutter这段不堪回首的作死往事总结一下吧,好了,如之前的博文一样,不知不觉又开始废话连篇了。(ps:这么爱讲废话,不知道自己去日记)。
       这次flutter重构之旅包含部分社区的功能,社区又怎么能少了正常的用户交流呢,所以一个评论回复而且能发图不发种,xx万人捅的发布组件呼之欲出。思来想去,似乎并没有想出更好的交互,只能学学你们口中不共戴天,水火不容的产品,所有的产品都是互相借鉴,于是我也去稍微借鉴借鉴目前流行的交互方式,无非就是点击弹出键盘和输入框,其他就没什么了。能不能设计得酷炫点,是看不起我们开发实现不了吗?
       翻来翻去,手机上app都翻烂了,果然千篇一律,不亏为借鉴,可能借的人比较多哈。好了玩笑的话就不多说了,直接开始。

。。。。。。。。。思考再三,无从下手,此时的脸啪啪的疼。

搞错了,重来。

首先
先封装入口方法吧,用showDialog这个类往路由栈里插入一条记录,对于原生开发来说不比h5,原生开发所有的视图都是叠在一起的,只需要把背景搞透明就感觉像在一个页面一样,而h5往dom上插dom容易出事。总结:遇事不决跳页面。

void Function(BuildContext, Map<String, dynamic>, [dynamic]) comment =
    (BuildContext context, Map<String, dynamic> params, [dynamic callback]) {
  showDialog<Null>(
      context: context, //BuildContext对象
      builder: (BuildContext context) {
        return GestureDetector(
          onTap: () {
            router.back(context); //点击背景透明层,退出弹出框
          },
          child: CommentDialog(params: params, callback: callback),
        );
      });
};

然后
开始写输入框类,由于我这里需要用setData来更新视图,所以先提取CommentDialog继承与无状态StatelessWidget用作父组件,把有状态组件尽量封存在最小小部件CommentContent 里面。

class CommentDialog extends StatelessWidget {
  final dynamic callback;
  final Map<String, dynamic> params;

  CommentDialog({Key key, @required this.callback, this.params})
      : assert(callback != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      //创建透明层
      type: MaterialType.transparency, //透明类型
      child: GestureDetector(
          onTap: () {
            return false;
          },
          child: Stack(children: <Widget>[
            Positioned(
                left: 0,
                right: 0,
                bottom: MediaQuery.of(context).viewInsets.bottom > 0
                    ? MediaQuery.of(context).viewInsets.bottom
                    : 0,
                child: Container(
                    width: MediaQuery.of(context).size.width,
                    padding: EdgeInsets.only(
                        left: 16.0, right: 16.0, top: 10.0, bottom: 6.0),
                    decoration: BoxDecoration(color: Colors.white),
                    child: CommentContent(
                      params: params,
                      callback: callback,
                    )))
          ])),
    );
  }
}

class CommentContentState extends State<CommentContent> {
  String text;
  String currentValue = '';
  List<File> imgList = [];
  List<String> imgPaths = [];
  bool pending = false;

  @override
  void initState() {
    super.initState();
  }

  addImage() {
    pickImageFromCameraOrAlbum(context, 3 - imgList.length,
        (PickImageResponse r) {
      if (r.files != null) {
        imgList.addAll(r.files);
      }
      if (r.paths != null) {
        imgPaths.addAll(r.paths);
      }
      setState(() {});
    });
  }

  comment() async {
    if (pending == true) return;
    pending = true;
    final Map<String, dynamic> params = widget.params;
    params['content'] = currentValue;
    // 先上传七牛云
    if (imgPaths != null && imgPaths.length != 0) {
      final rr = await uploadQiNiu(imgPaths);
      if (rr == null || rr.length == 0) return;
      params['resource'] = json.encode(rr);
    }
    toast(context, '资源提交中,请勿重复点击或退出');
    // 再评论
    final r = await api.commentOrReply(params);
    pending = false;
    if (r.code == 1) {
      toast(context, '评论成功');
      if (widget.callback != null) {
        widget.callback();
      }
    }
    // 回复
    router.back(context);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        imgList.length == 0
            ? Padding(padding: EdgeInsets.only(right: 0.0))
            : Container(
                padding: EdgeInsets.only(bottom: 8.0),
                child: Row(
                  children: imgList
                      .map(
                        (e) => Container(
                          height: 80.0,
                          width: 80.0,
                          margin: EdgeInsets.only(right: 8.0),
                          decoration: BoxDecoration(
                            borderRadius:
                                BorderRadius.all(Radius.circular(8.0)),
                            image: DecorationImage(
                              fit: BoxFit.cover,
                              image: FileImage(
                                e,
                              ),
                            ),
                            color: Color(0xFFF0F0F0),
                          ),
                          child: GestureDetector(
                            behavior: HitTestBehavior.opaque,
                            child: Align(
                                alignment: Alignment.topRight,
                                child: Opacity(
                                  opacity: 0.3,
                                  child: Container(
                                    height: 13.0,
                                    width: 13.0,
                                    margin: EdgeInsets.all(4.0),
                                    padding: EdgeInsets.all(1.0),
                                    decoration: BoxDecoration(
                                        shape: BoxShape.circle,
                                        color: Color(0xff000000)),
                                    child: Image.asset(
                                      'lib/images/cancle-image.png',
                                      height: 10.0,
                                      width: 10.0,
                                    ),
                                  ),
                                )),
                            onTap: () {
                              imgList.remove(e);
                              setState(() {});
                            },
                          ),
                        ),
                      )
                      .toList(),
                ),
              ),
        ConstrainedBox(
          constraints: BoxConstraints(
            minHeight: 40.0,
          ),
          child: Container(
            padding: EdgeInsets.only(left: 6.0, right: 6.0, bottom: 4.0),
            decoration: BoxDecoration(color: Color(0xfff0f0f0)),
            child: TextFormField(
              decoration: InputDecoration(
                hintText: "说点什么",
                border: InputBorder.none,
              ),
              style: TextStyle(fontSize: 14.0, color: Color(0xff606266)),
              autofocus: true,
              cursorColor: Color(0xff00c295),
              scrollPadding: EdgeInsets.only(top: 0.0, bottom: 6.0),
              minLines: 2,
              maxLines: 3,
              onChanged: (v) {
                currentValue = v;
                setState(() {});
              },
            ),
          ),
        ),
        Padding(padding: EdgeInsets.only(bottom: 4.0)),
        Row(
          children: <Widget>[
            Container(
                height: 30.0,
                width: 32.0,
                child: FlatButton.icon(
                    onPressed: addImage,
                    padding: EdgeInsets.all(0.0),
                    focusColor: Colors.white,
                    hoverColor: Colors.white,
                    highlightColor: Colors.white,
                    splashColor: Colors.white,
                    icon: Icon(
                      Icons.image,
                      color: Colors.grey,
                    ),
                    label: Text(''))),
            Expanded(child: Text('')),
            Container(
                height: 30.0,
                width: 40.0,
                child: FlatButton(
                  padding: EdgeInsets.all(0.0),
                  focusColor: Colors.white,
                  hoverColor: Colors.white,
                  highlightColor: Colors.white,
                  splashColor: Colors.white,
                  child: Text(
                    '发布',
                    style: TextStyle(
                        color: Color(currentValue.length == 0
                            ? 0xffbcbcbc
                            : 0xff00c295)),
                  ),
                  onPressed: () {
                    if (currentValue == '') return;
                    comment();
                  },
                ))
          ],
        )
      ],
    );
  }
}

class CommentContent extends StatefulWidget {
  final dynamic callback;
  final Map<String, dynamic> params;

  CommentContent({Key key, @required this.callback, this.params})
      : assert(callback != null),
        super(key: key);

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

界面大概就是下面这个样子吧。

在这里插入图片描述
图片给我整的大大的,都好好欣赏下我大幂幂。
客人来了,服务肯定要做全套,舒舒服服的。

拍照+相册选择多张图,请看这一篇
上传七牛云方法,请看这一篇
仓库地址:传送门

好了,废话也说完了,东西也实现了,广告也打完了,是时候说再见了。
难忘今宵,难忘~今宵。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值