【问题标题】:Flutter - how to remove default padding (48 px as per doc) from widgets (IconButton, CheckBox, FlatButton)Flutter - 如何从小部件(IconButton、CheckBox、FlatButton)中删除默认填充(根据文档为 48 像素)
【发布时间】:2019-04-08 16:39:36
【问题描述】:

我遇到了小部件(IconButton、CheckBox、FlatButton)默认填充的问题。我已经为此问题进行了很多搜索,但没有成功。

在上图中,外部蓝色矩形是这些小部件的实际大小,我必须删除该空间。

Checkbox(
          onChanged: (value) {
            setState(() {
              _rememberMeFlag = !_rememberMeFlag;
            });
          },
          value: _rememberMeFlag,
          activeColor: const Color(0xff00bbff),
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
        )

以下是隐藏/显示小部件图标的小部件代码:

new Container(
          child: TextFormField(
            decoration: InputDecoration(
              labelText: "Password",
              suffixIcon: Padding(
                padding: EdgeInsetsDirectional.zero,
                child: GestureDetector(
                  child: Icon(
                    hidePassword ? Icons.visibility : Icons.visibility_off,
                    size: 20.0,
                    color: Colors.black,
                  ),
                ),
              ),
              contentPadding: const EdgeInsets.only(
                  left: 0.0, top: 6.0, bottom: 6.0, right: 0.0),
            ),
            obscureText: !hidePassword,
            maxLength: 20,
          ),
        )

我也尝试设置容器大小,但没有成功。还尝试了小部件的填充属性,但没有成功。

有没有办法从这些小部件中删除这个额外的间距?

【问题讨论】:

  • 为什么不使用标准的CheckboxListTile
  • @pskink 它导致的间距比所需的间距更大。项目所有者要求我们减少该空间。

标签: flutter flutter-layout padding flutter-widget


【解决方案1】:

CheckBox 包裹在SizedBox 中会调整复选框的填充大小

  SizedBox(
    height: 24.0,
    width: 24.0,
    child: Checkbox(...),
 )

【讨论】:

  • 简单而有效。在不依赖方法覆盖的情况下使用标准小部件的额外优势。
  • CheckboxListTile 不适合我,触摸空间区域没有变化并且重叠。我有 3 个 CheckboxListTile,如果在 SizedBox 上设置高度,它看起来就像我想要的那样,但是当点击一个复选框时,其他复选框会激活。
  • @Inmer FYI CheckboxistTile 我猜想在整个磁贴中都有触摸,如果你想自定义触摸空间等等,你必须创建自己的一行磁贴。
  • 即使对于 TabBar 不需要的顶部|底部标签填充也有效
【解决方案2】:

编辑

ma​​terialTapTargetSize的值设置为MaterialTapTargetSize.shrinkWrap

Checkbox(
   materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
    ...
 )

或者,您可以通过自定义 Checkbox 小部件来实现此目的。

  1. 使用来自的确切代码创建一个 CustomCheckbox flutter/packages/flutter/lib/src/material/checkbox.dart.

  2. 向您的 CustomCheckbox 小部件添加一个新字段

         final bool useTapTarget;
    
  3. 确保将新字段默认添加到构造函数中 值设置为 true。

         this.useTapTarget = true
    
  4. 修改_CheckboxState方法中的build方法。添加这个 返回调用上方的代码块。

         Size noTapTargetSize = Size(CustomCheckbox.width, 
         CustomCheckbox.width);
         final BoxConstraints additionalConstraints = 
         BoxConstraints.tight(widget
            .useTapTarget? size : noTapTargetSize);
    
  5. 最后,在您的代码中使用您的 CustomCheckbox 小部件,并设置您的 自定义字段为 false 以删除材料填充。例子

    Container(
            margin: EdgeInsets.only(right: 15),
            child:CustomCheckbox(
                value: _checked,
                onChanged: _onCheckBoxChange,
                useTapTarget: false,
                activeColor: Colors.teal),
          )
    

【讨论】:

    【解决方案3】:

    对于那些寻找复制和粘贴的人;),这是我使用的

    import 'package:flutter/material.dart';
    
    class NoPaddingCheckbox extends StatelessWidget {
      final bool isMarked;
      final Function(bool newValue) onChange;
      final double size;
    
      NoPaddingCheckbox({
        @required this.isMarked,
        @required this.onChange,
        this.size = 24,
      });
    
      @override
      Widget build(BuildContext context) {
        return ConstrainedBox(
          constraints: BoxConstraints(maxHeight: size, maxWidth: size),
          child: RawMaterialButton(
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
            child: Icon(_getIconData(), size: size),
            onPressed: () => onChange(!isMarked),
          ),
        );
      }
    
      IconData _getIconData() {
        if (isMarked) {
          return Icons.check_box;
        }
    
        return Icons.check_box_outline_blank;
      }
    }
    

    【讨论】:

      【解决方案4】:

      共有三个选项:

      1.

       // or Checkbox()
      Radio( 
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
      )
      
      
       // or Checkbox()
      Radio(
          visualDensity: VisualDensity(horizontal: -4, vertical: -4),
      )
      
      
      SizedBox(
          height: 20, 
          width: 20, 
       // or Checkbox()
          child: Radio()
          )
      
      

      【讨论】:

        【解决方案5】:
        Wrap(
            children: <Widget>[
                Text('radio'),
                Radio(
                    groupValue: _character,
                    onChanged: (value){},
                    materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                )
            ],
            crossAxisAlignment: WrapCrossAlignment.center,
        ),
        
        

        这会删除很多空格

        【讨论】:

          【解决方案6】:

          将您的 CheckBox 包裹在 SizedBox Widget 中,并根据您的需要为它们指定高度或宽度。

          SizedBox(
                   height: 20.0,
                    width: 20.0,
                    child: Checkbox(
                        value: _checkBoxValue, onChanged: (value){
                      setState(() {
                        _checkBoxValue = value;
                      });
                    }),
                  ),
          

          【讨论】:

            【解决方案7】:

            我发现的最简单的方法是创建您的小部件版本,通常是通过将GestureDetector Widget 与某些东西结合起来。例如,下面是 IconButton 的一个版本,它没有默认的 Material Design 填充:

            GestureDetector(
              onTap: () {
                //do stuff here
              },
              child: Icon(
                Icons.icon_choice
              ),
            )
            

            【讨论】:

            • 这将不支持默认的复选框动画
            • 不要重蹈覆辙是一个应该遵循的好原则
            【解决方案8】:

            您可以尝试通过在 Windows 中按下 ctrl 的同时单击 IconButton 打开 IconButton 类来更改内容。然后你会发现一个变量 Padding = EdgeConsts.all(8.0) 。不断改变它并根据您的需要使用它。

            【讨论】:

              【解决方案9】:

              Checkbox 小部件的默认尺寸为 48x48。因此,根据上述答案,如果我们将 Checkbox 包裹在 SizedBox 内,则白色间距会减小。我尝试了 24x24 并且所有间距都消失了。

              SizedBox(
                width: 24.0,
                height: 24.0,
                child: Checkbox(),
              

              在此之后,我将 SizedBox 包裹在 Padding 小部件中,以提供我想要的任何一侧的间距。

              Padding(
                padding: const EdgeInsets.only(right: 8.0),
                child: SizedBox(
                  width: 24.0,
                  height: 24.0,
                  child: Checkbox(),
                ),
              )
              

              【讨论】:

                【解决方案10】:

                您可以通过自定义 Checkbox 小部件的 _outerRectAt 方法来实现:

                RRect _outerRectAt(Offset origin, double t) {
                    final double inset = 1.0 - (t - 0.5).abs() * 2.0;
                    final double size = _kEdgeSize - inset * _kStrokeWidth;
                    //final Rect rect = Rect.fromLTWH(origin.dx + inset, origin.dy + inset, size, size); //ORIGINAL
                    final Rect rect = Rect.fromLTWH(0, origin.dy + inset, size, size); //CUSTOM
                    return RRect.fromRectAndRadius(rect, _kEdgeRadius);
                }
                

                修改后的结果是:

                最后但同样重要的是,您需要像这样更改 _drawCheck 方法:

                void _drawCheck(Canvas canvas, Offset origin, double t, Paint paint) {
                    assert(t >= 0.0 && t <= 1.0);
                    // As t goes from 0.0 to 1.0, animate the two check mark strokes from the
                    // short side to the long side.
                    final Path path = Path();
                    const Offset start = Offset(_kEdgeSize * 0.15, _kEdgeSize * 0.45);
                    const Offset mid = Offset(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
                    const Offset end = Offset(_kEdgeSize * 0.85, _kEdgeSize * 0.25);
                    if (t < 0.5) {
                        final double strokeT = t * 2.0;
                        final Offset drawMid = Offset.lerp(start, mid, strokeT);
                
                        //NEW
                        path.moveTo(0 + start.dx, origin.dy + start.dy);
                        path.lineTo(0 + drawMid.dx, origin.dy + drawMid.dy);
                
                        //OLD
                        /*path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
                        path.lineTo(origin.dx + drawMid.dx, origin.dy + drawMid.dy);*/
                    } else {
                        final double strokeT = (t - 0.5) * 2.0;
                        final Offset drawEnd = Offset.lerp(mid, end, strokeT);
                
                        //NEW
                        path.moveTo(0 + start.dx, origin.dy + start.dy);
                        path.lineTo(0 + mid.dx, origin.dy + mid.dy);
                        path.lineTo(0 + drawEnd.dx, origin.dy + drawEnd.dy);
                
                        //OLD
                        /*path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
                        path.lineTo(origin.dx + mid.dx, origin.dy + mid.dy);
                        path.lineTo(origin.dx + drawEnd.dx, origin.dy + drawEnd.dy);*/
                    }
                    canvas.drawPath(path, paint);
                }
                

                【讨论】:

                  【解决方案11】:

                  截图:


                  代码(也解决了圆形点击效果的大小):

                  @override
                  Widget build(BuildContext context) {
                    var size = 20.0; // Your desired size.
                    return Scaffold(
                      body: Center(
                        child: SizedBox.fromSize(
                          size: Size.fromRadius(size / 2),
                          child: IconButton(
                            padding: EdgeInsets.zero,
                            splashRadius: size,
                            iconSize: size,
                            icon: Icon(Icons.mail),
                            onPressed: () {},
                          ),
                        ),
                      ),
                    );
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2018-10-27
                    • 2021-11-28
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-04-23
                    • 2019-11-22
                    • 2022-08-23
                    • 1970-01-01
                    • 2015-11-11
                    相关资源
                    最近更新 更多