我们注意到,在targetsdkversion 28期间,当输入非英语unicode(如中文、日语等)时,EditText
将倾向于在输入后“稍微向下推”行。
当代码为targetsdkversion 27或更低版本时,不会发生这种行为。
使用targetSdkVersion
27,在模拟器api 28上运行
(输入非英语Unicode之前)
(输入非英语Unicode后)
(确认间距正常)
使用targetSdkVersion
28,在模拟器api 28上运行
(输入非英语Unicode之前)
(输入非英语Unicode后)
(确认间距有问题。下推输入后的行)
这是我们使用的XML和代码。我们继承了androidx.appcompat.widget.AppCompatEditText
,来画线,使问题更加明显。
<com.yocto.wenote.note.LinedEditText
android:id="@+id/body_edit_text"
android:gravity="top"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:layout_marginBottom="12dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:scrollbars="vertical"
android:textSize="18sp"
android:singleLine="false"
android:lineSpacingMultiplier="1.4"
android:inputType="textMultiLine|textCapSentences"
android:textCursorDrawable="?attr/shorterCursor" />
linededitext.java
package com.yocto.wenote.note;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import com.yocto.wenote.R;
/**
* Created by yccheok on 24/3/2018.
*/
public class LinedEditText extends androidx.appcompat.widget.AppCompatEditText {
private final Paint mPaint = new Paint();
private int noteLineColor;
private static final float DEFAULT_LINE_SPACING_EXTRA = 0.0f;
private static final float DEFAULT_LINE_SPACING_MULTIPLIER = 1.4f;
private void initResource() {
Context context = getContext();
TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme();
theme.resolveAttribute(R.attr.noteLineColor, typedValue, true);
noteLineColor = typedValue.data;
}
public LinedEditText(Context context) {
super(context);
initResource();
initPaint();
}
public void setNoteLineColor(int noteLineColor) {
this.noteLineColor = noteLineColor;
}
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initResource();
initPaint();
}
public LinedEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initResource();
initPaint();
}
private void initPaint() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(noteLineColor);
mPaint.setStrokeWidth(1);
}
@Override
protected void onDraw(Canvas canvas) {
int left = getLeft();
int right = getRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
final int heightWithScrollY = getHeight() + getScrollY();
int lineHeight = getLineHeight();
int count = (heightWithScrollY-paddingTop-paddingBottom) / lineHeight;
mPaint.setColor(noteLineColor);
mPaint.setTypeface(this.getTypeface());
final float originalLineHeight;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
originalLineHeight = lineHeight / getLineSpacingMultiplier();
} else {
originalLineHeight = lineHeight / DEFAULT_LINE_SPACING_MULTIPLIER;
}
for (int i = 0; i < count; i++) {
float baseline = lineHeight * (i + 1) + paddingTop - mPaint.descent() - (lineHeight - originalLineHeight);
canvas.drawLine(
left + paddingLeft,
baseline,
right - paddingRight,
baseline,
mPaint
);
}
super.onDraw(canvas);
}
// https://stackoverflow.com/questions/49467579/workaround-for-edittext-ignoring-linespacingmultiplier
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if (lengthBefore != lengthAfter) {
float add;
float mul;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
add = getLineSpacingExtra();
mul = getLineSpacingMultiplier();
} else {
add = DEFAULT_LINE_SPACING_EXTRA;
mul = DEFAULT_LINE_SPACING_MULTIPLIER;
}
setLineSpacing(0f, 1f);
setLineSpacing(add, mul);
}
}
}
请注意,如果您使用
targetSdkVersion
28,但在Emulator API 27上运行,则不会出现此问题。关于解决办法有什么建议吗?
p/s我在https://issuetracker.google.com/issues/131284662
最佳答案
好吧,我设法做到了以下方式。我的OnDraw函数:
@Override
protected void onDraw(Canvas canvas) {
int left = getLeft();
int right = getRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
final int heightWithScrollY = getHeight() + getScrollY();
Log.d("Height Of View: ",String.valueOf(heightWithScrollY));
int lineHeight = getLineHeight();
Log.d("LineHeight: ",String.valueOf(lineHeight));
int count = (heightWithScrollY-paddingTop-paddingBottom) / lineHeight;
Log.d("Count: ",String.valueOf(count));
mPaint.setColor(noteLineColor);
mPaint.setTypeface(this.getTypeface());
Log.d("Descent: ",String.valueOf(mPaint.descent()));
for(int i=lineHeight;i<=count*lineHeight;i+=lineHeight)
{
float baseline = i + paddingTop + mPaint.descent();
canvas.drawLine(left+paddingLeft,baseline,right-paddingRight,baseline,mPaint);
Log.d("XYXY:",String.valueOf(left+paddingLeft)+" "+String.valueOf(baseline)+" "+String.valueOf(right-paddingRight));
}
super.onDraw(canvas);
}
我用视图
<com.yocto.wenote.note.LinedEditText
android:id="@+id/body_edit_text"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="top"
android:layout_marginBottom="12dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:textSize="18sp"
android:singleLine="false"
android:lineSpacingMultiplier="1.4"
android:inputType="textMultiLine|textCapSentences"/>
最后但并非最不重要的是,我在build.gradle依赖项中使用了这个实现(我个人认为使用这个alpha05版本有助于解决这个问题,但我没有检查其他版本)
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0-alpha05'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}