处理非英语Unicode(例如中文,日文)时,目标API 28中的EditText行间距行为不正确

Che*_*eng 5 unicode android android-edittext

我们注意到,在targetSdkVersion 28期间EditText,当输入非英语unicode(如中文,日语,...)时,输入后将趋于“稍微下推”该行。

当代码为targetSdkVersion 27或更低版​​本时,不会发生这种情况。


使用targetSdkVersion27,在模拟器API 28上运行

(在输入非英语unicode之前)

在此处输入图片说明

(输入非英文unicode后)

在此处输入图片说明

(确认间距确定)

在此处输入图片说明


使用targetSdkVersion28,在模拟器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" />
Run Code Online (Sandbox Code Playgroud)

LinedEditText.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);
    }

    // /sf/ask/3462730561/
    @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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您使用targetSdkVersion28,但在仿真器API 27上运行,也不会发生此问题。

关于解决方法有什么建议吗?

p / s我在https://issuetracker.google.com/issues/131284662提出了问题

Ján*_*iár 0

您必须查询每个现有行的基线才能在正确的位置绘制线条。我简化了你的代码,这个版本将解决你的问题,我在Android P和Android Q上进行了测试:

@Override
protected void onDraw(Canvas canvas) {
    int left = getLeft();
    int right = getRight();
    int paddingLeft = getPaddingLeft();
    int paddingRight = getPaddingRight();

    mPaint.setColor(noteLineColor);
    mPaint.setTypeface(this.getTypeface());

    Layout layout = getLayout();
    // 1. Draw line for existing rows
    for (int i = 0; i < layout.getLineCount(); i++) {
        int baseline = layout.getLineBaseline(i);
        canvas.drawLine(
                left + paddingLeft,
                baseline,
                right - paddingRight,
                baseline,
                mPaint
        );
    }

    // 2. Draw line for non-existing rows
    final int heightWithScrollY = getHeight() + getScrollY();
    int lineHeight = getLineHeight();
    int nextBaseline = layout.getHeight() + lineHeight;
    while(nextBaseline < heightWithScrollY){
        canvas.drawLine(
                left + paddingLeft,
                nextBaseline,
                right - paddingRight,
                nextBaseline,
                mPaint
        );
        nextBaseline += lineHeight;
    }

    super.onDraw(canvas);
}
Run Code Online (Sandbox Code Playgroud)