We notice that, during targetSdkVersion 28, EditText will tend to "slightly push down" the line after input, when non-English unicode (Like Chinese, Japanese, ...) is being entered.
Such behavior doesn't happen, when the code is targetSdkVersion 27 or below.
targetSdkVersion 27, run on emulator API 28(Before input non-English unicode)

(After input non-English unicode)

(Confirm spacing is OK)

targetSdkVersion 28, run on emulator API 28(Before input non-English unicode)

(After input non-English unicode)

(Confirm spacing is problematic. Lines after input are being pushed down)

This is the XML and code used by us. We inherit from androidx.appcompat.widget.AppCompatEditText, to paint the lines, to make the problem more obvious.
<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" />
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);
}
// 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);
}
}
}
Take note that, if you use targetSdkVersion 28, BUT run on emulator API 27, this problem will not occur too.
Any suggestion on the workaround?
p/s I filed an issue at https://issuetracker.google.com/issues/131284662
Well i managed to do it in the following manner. My onDraw function:
@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);
}
and i used view as
<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"/>
And last but not the least i used this implementation in my build.gradle dependencies (I personally think using this alpha05 version helped it to solve the issue but i have not checked otherwise)
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'
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With