我们注意到,在targetsdkversion 28期间,当输入非英语unicode(如中文、日语等)时,EditText将倾向于在输入后“稍微向下推”行。
当代码为targetsdkversion 27或更低版本时,不会发生这种行为。
使用targetSdkVersion27,在模拟器api 28上运行
(输入非英语Unicode之前)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
(输入非英语Unicode后)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
(确认间距正常)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
使用targetSdkVersion28,在模拟器api 28上运行
(输入非英语Unicode之前)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
(输入非英语Unicode后)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
(确认间距有问题。下推输入后的行)
android - 处理非英语Unicode时,目标API 28中的EditText行间距行为不正确(如中文,日文)-LMLPHP
这是我们使用的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);
        }
    }

}

请注意,如果您使用targetSdkVersion28,但在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'
}

07-26 02:07