Flutter TextField 竟然可以用这种方式解决输入框单行垂直居中问题!

2,365 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

背景

使用Flutter之后,相信很多人都会遇到输入框居中问题,只要设置了Box高度或者设置了下行高,输入框内的文字居然就不居中了!总不能跟设计同学说,你这输入框按我的高度来,不能指定!

然后就开始找资料,研究,发现设置contentPadding虽然可以欺骗一下测试,但还是治标不治本不同机型就会有不同的“高度”,气都气死了!还有什么TextAlignVertical.bottomOutlineInputBorder来调整,依旧还是偏的。

那就自己来想法子吧。

浅浅分析一下

当我们不设置高度,或者行高,或者contentPadding时,可以神奇的发现,无论什么fontSize,输入框的文字都是默认居中的!

TextField(
  style: const TextStyle(
    fontSize: 13,
  ),
  decoration: const InputDecoration(
    hintText: "TEST",
    hintStyle: TextStyle(
      fontSize: 13,
    ),
    border: InputBorder.none,
  ),
),

image.png

TextField(
  style: const TextStyle(
    fontSize: 20,
  ),
  decoration: const InputDecoration(
    hintText: "TEST",
    hintStyle: TextStyle(
      fontSize: 20,
    ),
    border: InputBorder.none,
  ),
)

image.png 如上面最简单的输入框,线条是Debug Paint辅助线,可以看到,不同size的文字输入框,他都是位于中间的,并且测试了多部机型,都是居中的。但在我们加个固定高度的Container之后,我们再看看

Container(
  height: 40,
  alignment: Alignment.centerLeft,
  child: TextField(
    controller: _contentController,
    style: const TextStyle(
      fontSize: 20,
    ),
    decoration: const InputDecoration(
      hintText: "TEST",
      hintStyle: TextStyle(
        fontSize: 20,
      ),
      border: InputBorder.none,
    ),
  ),
)

image.png

给个高度限制,他就歪了,所以我们可以认为输入框自带有一个默认高度,并且,无法在外部进行调整,他一般情况下会自动根据这个高度来调整文字的默认上下间距,动态居中。可通过内部的contentPadding来调整与外部Box的间距来达到一个假的居中,经测试,每个机型很可能会不一样。

TextAlignVertical看了下源码的解释,他是指定文本与自身的框的对齐方式,跟我们给予外层布局的框的高度无关,简单来说,人家只是让你设置下,他与自身默认Box的对齐方式是顶部,中间,还是底部,设置底部那必然不是真正的居中了,直接不用继续考虑这种方案了。

一种神奇的解决方案

那我们就想哦,怎么保留他自动适配居中的机制,又给他设置底部自定高度的盒子呢?

很简单,其实我们要设置一个自定高度的盒子,无非就是为了设置一个输入框的背景,那这个背景一定得是设置输入框的背景吗?那倒并不,不是其实也没有关系。

我们就可以利用Stack,先画好背景,再将输入框放置在背景上,那就能够得到一个有自定高度背景,且文字自动居中的输入框了!

示例代码:

Stack(
  alignment: Alignment.centerLeft,
  children: [
    Container(
      height: 40,
      margin: const EdgeInsets.symmetric(vertical: 10),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(5),
      ),
    ),
    Container(
      alignment: Alignment.centerLeft,
      padding: const EdgeInsets.symmetric(horizontal: 10),
      child: const TextField(
        style: TextStyle(
          fontSize: 20,
        ),
        decoration: InputDecoration(
          hintText: "TEST",
          hintStyle: TextStyle(
            fontSize: 20,
          ),
          border: InputBorder.none,
        ),
      ),
    )
  ],
)

效果: image.png image.png

是不是很简单,再也不用设置什么contentPadding一点一点的调来调去,还不能适配机型了~

虽然好像很魔幻的操作,但很有效。觉得有用的话可以自行套一层封装成一个新的输入框插件,就能很方便的写需要单行垂直居中的输入框了,然后避开contentPadding设置,因为只要设置了这个,就会打破他的自适应居中。padding其实类似上边,用Container的padding即可。