如果你在使用
textCursorDrawable
和
lineSpacingExtra
时,会遇到另一个问题:当你的应用程序在Lollipop以上的版本运行时,由于最后一行的行高不会改变,如果在自定义的
textCursorDrawable
中定义了负底部填充,则光标会在最后一行缩小,如下图所示:
![enter image description here](https://istack.dev59.com/fAelt.webp)
为了达到更惊人的效果,我将
lineSpacingExtra
设置为
8dp
,并且我的自定义
textCursorDrawable
的一部分是
<padding android:bottom="-8dp"/>
。因此,您可以看到小光标出现在最后一行。
当然,我们不喜欢这个。我在互联网上搜索了数小时和数天,但没有任何页面能够帮助我。但是,如果您看到了这个答案,就不必为此担心,因为我已经用我的方式解决了这个问题,虽然有点hacky,但据我所知很好用。
我们问题的根本原因在于我们为
textCursorDrawable
设置了底部填充,并将其缩短了
所有行。假设文本大小为12dp,则原始行高也为12dp(只是为了方便)。在我们定义了
lineSpacingExtra="8dp"
之后,行高将增加到20dp。如果我们不对
textCursorDrawable
进行任何操作,则光标高度现在也将变为20dp,显然比文本大小长,因此我们缩短它,通过在自定义的
textCursorDrawable
形状XML文件中定义
<padding android:bottom="-8dp"/>
来剪切底部的8dp。然而,在Lollipop以上版本中,
lineSpacingExtra
会忽略最后一行,因此该行的行高仍保持在12dp。如果我们不使用自定义光标,则最后一行的光标也是如此。然后我们削减了那个8dp,现在我们看到一个4dp的光标,这是错误的,正确的操作是停止在自定义
textCursorDrawable
中设置-8dp的底部填充。
因此解决方案是:对于普通行和最后一行使用不同的
textCursorDrawable
,充分尊重特殊的一行。
那么,什么时候应该更改
textCursorDrawable
呢?我的答案是:当用户单击
EditText
的最后一行时。这很合理,因为光标只能在此操作之后出现(如果用户在此之后点击“enter”可能不是最后一个操作,但这并不影响我们的解决方案)。
下一步是监听用户在最后一行上的单击。我的解决方案很简单:
mEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
EditText et = (EditText) v;
int lastLineHeight = (int) (et.getLineHeight() - et.getLineSpacingExtra());
if (et.getHeight() - event.getY() <= lastLineHeight) {
setTextCursorDrawable(et, lastLineCursorRes);
} else {
setTextCursorDrawable(et, normalCursorRes);
}
return true;
}
return false;
}
});
以下是不太优雅的(但我们必须这样做)setTextCursorDrawable
实现:
public void setTextCursorDrawable(EditText et, @DrawableRes int res) {
try {
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(et, res);
} catch (Exception ignored) {}
}
最后,lastLineCursorRes
的特殊部分:
<padding android:bottom="0dp"/>
好的,就是这样。请注意,我在尝试此解决方案并发现它有效后立即编写了此答案,这意味着我没有仔细检查它。如果您在使用此解决方案时遇到任何问题,请留言评论。
参考资料
要了解为什么在 TextView
及其子类的最后一行中忽略 lineSpacingExtra/Multiplier
,请参阅:How LineSpace Affects StaticLayout Height in One Line Text、Android TextView 行间距解析(in Chinese) 和 StaticLayout源码解析(in Chinese)。