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