Flutter--Button浅谈

2023-11-16

作为一个常用到不能再常用的组件,material库中的button组件都有一点奇怪——存在无法设置的内外边距,我们做一个简单的展示,选几个常见button,统一使用Text做child,外加一个带红色的Container组件,观察margin和padding.

你会发现,除了InkWell,即使padding设置为0,仍然无法消除消除上下padding,这其实不是padding属性没有生效,而是这些按钮有默认大小的约束。这点可以通过源码和不设置child的UI来佐证。

MaterialButton设置它的高度属性,看源码的使用,是修改高度约束,但是小到一定程度还是无法修改,是因为有别的地方进一步作出了限制,这就是我觉得奇怪的一些地方。这会给使用者带来不便,所以我设计基础组件的基本原则之一就是不要去干涉外界的使用,比如我做了一个Card组件,我就不会给它一个默认margin。
MaterialButton(
  onPressed: () {

  },
  // child: Text("MaterialButton"),
  padding: EdgeInsets.all(0),
  height: 10,
)

其实上面所有的button都是对Inkwell的进一步封装,它包含点击特效(水波纹),以及各种手势识别,而它的本质也是在GestureDetector的基础上加了一个动画层,所以如果不需要动画效果,你大可以直接使用GestureDetector。进阶一点的做法就是基于这两者来创建你自己的Button。

InkWell的build部分源码(ink_well.dart)

这时你可能会觉得直接使用InkWell不就好了,假如你把它放在一个container里面,并且container具有背景色,你会发现水波纹效果消失了,你需要再套上一个Material组件,水波纹才会出现,这时你又回发现,这个组件自己具有形状背景色,你还得去消除,是不是很蛋疼。所以最终我是自己做了一个带有点击效果的Button组件,默认支持按钮禁用,背景色,大小,圆角等常用属性设置,供大家参考

import 'package:flutter/material.dart';

class UIButton extends StatefulWidget {

  final Widget? child;

  final bool disabled;

  final double? width;
  final double? height;

  final EdgeInsetsGeometry? padding;

  final Color? backgroundColor;
  final Color? disabledColor;
  final BorderRadiusGeometry? borderRadius;
  //大部分时间只需要统一四角圆角, 和borderRadius二选一
  final double? allRadius;

  final GestureTapCallback? onTap;
  final GestureTapCallback? onDoubleTap;
  final GestureLongPressCallback? onLongPress;
  final GestureTapCancelCallback? onTapCancel;

  final Clip? clipBehavior;

  UIButton({
    Key? key,
    this.child,
    this.disabled = false,
    this.width,
    this.height,
    this.padding,
    this.borderRadius,
    this.allRadius,
    this.backgroundColor,
    this.disabledColor,
    this.onTap,
    this.onDoubleTap,
    this.onLongPress,
    this.onTapCancel,
    this.clipBehavior
  }) : assert(allRadius == null || borderRadius == null), super(key: key);

  @override
  State<StatefulWidget> createState() => _UIButton();

}

class _UIButton extends State<UIButton> {

  bool _isTap = false;

  @override
  Widget build(BuildContext context) {
    BorderRadiusGeometry radiusGeometry = widget.borderRadius ?? BorderRadius.all(Radius.circular(widget.allRadius ?? 0));

    return GestureDetector(
      child: Container(
        child: Center(child: widget.child,),
        width: widget.width,
        height: widget.height,
        clipBehavior: widget.clipBehavior ?? Clip.none,
        foregroundDecoration: _isTap || widget.disabled ? BoxDecoration(
          color: widget.disabledColor ?? Color(0x85ffffff),
          borderRadius: radiusGeometry
        ) : null,
        decoration: BoxDecoration(
          borderRadius: radiusGeometry,
          color: widget.backgroundColor
        ),
        padding: widget.padding,
      ),
      onTap: widget.disabled ? null : widget.onTap,
      onDoubleTap: widget.disabled ? null : widget.onDoubleTap,
      onLongPress: widget.disabled ? null : widget.onLongPress,
      onTapUp: (TapUpDetails details) {
        refreshTapState(false);
      },
      onLongPressEnd: (LongPressEndDetails details) {
        refreshTapState(false);
      },
      onTapDown: (TapDownDetails details) {
        refreshTapState(true);
      },
      onTapCancel: () {
        //TODO:会导致长按时自动移除前景色
        refreshTapState(false);
        if (widget.onTapCancel != null) widget.onTapCancel!();
      },
    );
  }

  void refreshTapState(bool state) {
    setState(() {
      _isTap = state;
    });
  }
}

 测试的代码

Column(children: [
        SizedBox(width: double.infinity,),

        addSpacer(),

        InkWell(child: Text("InkWell"), onTap: () {

        },).addRedBackground(),

        addSpacer(),

        TextButton(
          onPressed: () {}, 
          child: Text("TextButton"),
          style: ButtonStyle(
            padding: MaterialStateProperty.all(EdgeInsets.zero)
          ),
        ).addRedBackground(),

        addSpacer(),

        MaterialButton(
          onPressed: () {

          },
          child: Text("MaterialButton"),
          padding: EdgeInsets.all(0),
        ).addRedBackground(),
        
        addSpacer(),
        
        OutlinedButton(
            onPressed: () {},
            child: Text("OutlinedButton"),
          style: ButtonStyle(
            padding: MaterialStateProperty.all(EdgeInsets.zero),
          ),
        ).addRedBackground(),
      ],
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
      ),


//空button
Column(children: [
        SizedBox(width: double.infinity,),

        addSpacer(),

        InkWell(child: Text(""), onTap: () {

        },).addRedBackground(),

        addSpacer(),

        TextButton(
          onPressed: () {}, 
          child: Text(""),
          style: ButtonStyle(
            padding: MaterialStateProperty.all(EdgeInsets.zero)
          ),
        ).addRedBackground(),

        addSpacer(),

        MaterialButton(
          onPressed: () {

          },
          // child: Text("MaterialButton"),
          padding: EdgeInsets.all(0),
        ).addRedBackground(),
        
        addSpacer(),
        
        OutlinedButton(
            onPressed: () {},
            child: Text(""),
          style: ButtonStyle(
            padding: MaterialStateProperty.all(EdgeInsets.zero),
          ),
        ).addRedBackground(),
      ],
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
      )

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter--Button浅谈 的相关文章

随机推荐

  • SQL注入简介和注入方法教学

    文章目录 SQL注入原理 SQL注入危害 SQL注入判断 SQL注入的分类 按参数类型分类 按数据库返回结果分类 按注入点位置分类 按参数类型分类 数字型 字符型 搜索型 按数据库返回结果分类 回显注入 报错注入 盲注 按注入点位置分类 G
  • DCDC升压boost电路输出电压问题

    boost输出电压 在稳定后 Vo Vin 1 d 该式子表明 输出电压唯一由占空比和输入电压决定 也就是说 在开环情况下 Vo不受负载大小的影响 但是实际体验是 Vo的稳定需要通过负反馈调节 这是什么原因造成的呢 其实造成上述现象的原因
  • 赠书啦

    随着 ChatGPT 面世并迅速风靡全球 AI 又一次进入寻常百姓家 而 ChatGPT 的一个重要支持正是自然语言处理中的大规模语言模型 GPT 由于自然语言是人类最方便 最重要的交流方式 是描述知识 传承文化的重要工具 因此对自然语言处
  • CodeSmith 使用教程(9): Progress对象

    使用Progress对象可以为CodeSmith生成代码的过程显示一个进度条 这对于生成比较费时的模板操作是非常有用的 如果你使用Visual Studio 可以在状态栏中显示一进度条 使用进度条的方法是通过CodeTemplate对象的P
  • 软件测试开发学习——第六天

    静态白盒测试 检查设计和代码 静态白盒测试 在不执行软件的条件下有条理地仔细审查软件设计 体系结构和代码 从而找出软件的缺陷的过程 有时称为结构化分析 进行白盒测试的首要原因是尽早发现软件缺陷 以找出动态黑盒测试难以发现或隔离的软件缺陷 白
  • elasticsearch7.17.3实现按terms传入内容排序,类似mysql中order by filed()的排序方式

    现有一个需求 需要在elasticsearch中实现用terms筛选内容 并且按terms传入的内容顺序排列 类型于mysql中order by filed 的排序方式 具体实现如下 目录 一 需求 二 整体思路 三 es查询语句 四 ja
  • (Hibernate学习篇)Web 项目搭建Hibernate框架

    第一步 Web项目搭建Hibnate框架 myeclipse集成hibernate框架 如图 第二 选择Hibernate版本 DB 驱动 myeclipse database Expler中创建 myeclipse 默认的版本是hiber
  • matlab中求特征值的eig函数说明

    matlab中求特征值的eig函数说明 1 基本用法 e eig A 返回一个列向量 其中包含方阵 A 的特征值 示例 V D eig A 返回特征值的对角矩阵 D 和矩阵 V 其列是对应的右特征向量 使得 AV VD 示例 V D W e
  • IPSEC VPN知识点总结

    具体的实验 使用IPSEC VPN实现隧道通信 使用IPSEC VPN在有防火墙和NAT地址转换的场景下实现隧道通信 DS VPN实验 目录 1 什么是数据认证 有什么作用 有哪些实现的技术手段 2 什么是身份认证 有什么作用 有哪些实现的
  • iOS 设置项目的version和build号

    设置项目的version和build号 Version 1 0 1 Build 1 0 1 1 Version是显示对外的版本号 itunesconect和Appstore用户可以看到 对应O C中获取version的值 NSBundle
  • Servlet 中 session 的创建、销毁及监听

    1 session 和 cookie 关于session和cookie详细的内在机制和区别 请另行查阅资料 可参看 Session机制详解 当客户端首次请求session对象时候 服务器会为其创建一个session 并计算出具有唯一性的se
  • Ceph—报错锦集(mgr2、pgs、mgr依赖缺失等)

    Ceph 手动部署Ceph报错锦集 mgr2 pgs mgr依赖缺失等 报错锦集 1 执行 do cmake sh时的报错提示 2 do cmake sh 的note 3 导入一些链接库 4 No module named ceph mgr
  • Android Studio编译报错:sdk:minSdkVersion 1 cannot be smaller than version 7 declared in library

    背景 有一个以前的项目从Eclipse迁移到Android Studio 结果编译的时候报错如下 Error Execution failed for task lDrawer processDebugAndroidTestManifest
  • ListView动态加载数据

    当listview需要加载的数据过多时 若一次性载入则速度会相当缓慢 影响用户体验 这时候就需要动态加载数据 即每次载入固定长度的数据 android market的listview就是采用这种方式 使得加载看起来很平滑 响应速度很快 有助
  • 物联网的四种计算类型

    简介 从一个实践者的角度来看 我经常看到计算更加可用和分布的必要性 当我开始将物联网与OT和IT系统集成时 我面临的第一个问题是设备发送到我们服务器的数据量太大 我在一个工厂自动化场景中工作 我们集成了400个传感器 这些传感器每1秒发送3
  • Qt内存管理(三) Qt的智能指针

    智能指针则可以在退出作用域时 不管是正常流程离开或是因异常离开 总调用delete来析构在堆上动态分配的对象 Qt常用的智能指针有QPointer QScopedPointer QSharedPointer 关于这几个智能指针 网上的博客基
  • 每天一个linux命令(30): chown命令

    chown将指定文件的拥有者改为指定的用户或组 用户可以是用户名或者用户ID 组可以是组名或者组ID 文件是以空格分开的要改变权限的文件列表 支持通配符 系统管理员经常使用chown命令 在将文件拷贝到另一个用户的名录下之后 让用户拥有使用
  • 双系统卸载Linux,重装Deepin

    卸载掉之前的Linux系统 参考资料 https www bilibili com video av209430195 下载diskgenius https www diskgenius cn download php 删除Linux分区
  • StackExchange.Redis Timeout performing 超时问题

    最近在做的一个项目 用的 net core 2 1 然后缓存用的Redis 缓存相关封装是同事写的 用的驱动是StackExchange Redis version 2 0 571 一直听说这个驱动并发情况下有TimeOut bug 项目开
  • Flutter--Button浅谈

    作为一个常用到不能再常用的组件 material库中的button组件都有一点奇怪 存在无法设置的内外边距 我们做一个简单的展示 选几个常见button 统一使用Text做child 外加一个带红色的Container组件 观察margin