自动调整大小的EditText

23

1
请点击此链接查看 https://github.com/ViksaaSkool/AutoFitEditText 的相关编程内容。 - Ashish Ranjan
6个回答

9

我和你一样遇到了问题,EditText是TextView的子类,但不支持自动调整字体大小???

我通过某种方式解决了这个问题。起初,我查看了TextView的代码,并将其复制并作为扩展(在Kotlin中)实现到EditTextView上,但是...有大量的方法,所以最终我放弃了这个选项。

我的做法是使用一个不可见的TextView(是的,我知道这是一个完全的hack,我对此感到不太满意,但Google应该为此感到羞耻)。

这是我的xmls:

    <TextView android:id="@+id/invisibleTextView"
    android:layout_height="0dp"
    android:layout_width="match_parent"
    android:focusable="false"
    app:autoSizeTextType="uniform"
    app:autoSizeMinTextSize="@dimen/text_min"
    app:autoSizeMaxTextSize="@dimen/text_max"
    app:autoSizeStepGranularity="@dimen/text_step"
    android:textAlignment="center"
    app:layout_constraintLeft_toLeftOf="@id/main"
    app:layout_constraintRight_toRightOf="@id/main"
    app:layout_constraintTop_toBottomOf="@id/textCount"
    app:layout_constraintBottom_toBottomOf="@id/main"
    android:visibility="invisible"
    tool:text="This is a Resizable Textview" />


<EditText android:id="@+id/resizableEditText"
    android:layout_height="0dp"
    android:layout_width="match_parent"
    android:textAlignment="center"
    app:layout_constraintLeft_toLeftOf="@id/main"
    app:layout_constraintRight_toRightOf="@id/main"
    app:layout_constraintTop_toBottomOf="@id/textCount"
    app:layout_constraintBottom_toBottomOf="@id/main"
    android:maxLength="@integer/max_text_length"
    tool:text="This is a Resizable EditTextView" />

注意: 两个视图的宽度/高度必须相同。

然后在我的代码中,我使用这个TextView的自动计算值来应用于我的EditTextView。

private fun setupAutoresize() {
    invisibleTextView.setText("a", TextView.BufferType.EDITABLE) //calculate the right size for one character
    resizableEditText.textSize = autosizeText(invisibleTextView.textSize)
    resizableEditText.setHint(R.string.text_hint)

    resizableEditText.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            resizableEditText.textSize = autosizeText(invisibleTextView.textSize)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            textCount.text = currentCharacters.toString()
            val text = if (s?.isEmpty() ?: true) getString(R.string.text_hint) else s.toString()
            invisibleTextView.setText(text, TextView.BufferType.EDITABLE)
        }
    })
}

private fun autosizeText(size: Float): Float {
    return size / (resources.displayMetrics.density + MARGIN_FACTOR /*0.2f*/)
}

作为注意事项,我使用了这个Android EditText提示文本大小来更改提示文本的大小。
我知道这是一个艰难的解决方法,但至少我们可以确保即使在将来版本中调整大小时,它仍然可以继续工作,而专有或已弃用的GitHub库将会失败。
我希望有一天,谷歌能够听取我们的声音,在子类中实现这个美妙的功能,这样我们就可以避免所有这些麻烦。
希望这可以帮助到您。

2

1
这是一个可怕的库! - Ishaan

1
你可以使用RelativeLayout将一个TextView隐藏在EditText后面,两者的高度和宽度相等。 TextView将具有android:autoSizeTextType="uniform" 通过在EditText上使用setOnTextChangedListener,您可以将TextView的文本设置为EditText中的任何内容。然后TextView的文本大小将自动调整。然后您需要将EditText的文本大小设置为与TextView相同。这是布局:
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

android:layout_height="match_parent" tools: context=".MainActivity">

<TextView

android:id="@+id/test"

android:layout_width="match_parent" android:layout_height="match_parent" android:padding="0dp"

android:layout_margin="0dp"

android: autoSizeTextType="uniform"

android: autosizeMaxTextSize="500sp" android: autosizestepGranularity="1sp"/>

<EditText

android:id="@+id/edit"

android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="0dp"/>

android:padding="0dp"

</RelativeLayout>

而且代码:

public void code(){

edit.setMovement Method (null);

edit.addTextChangedListener(new Textwatcher() {

@Override

public void onTextChanged (CharSequence s, int start, int before, int count) { test.setText (edit.getText().tostring()); edit.setTextSize(pixel2dip(test.getTextSize()));

}

public static float pixel2dip(float a) {

int b = (int) (a);

int c = (int) (b / Resources.getSystem().getDisplayMetrics ().scaledDensity); return (float) (c);

});

}

0

这对我有效。在xml中添加:

<EditText
            android:id="@+id/editTextMsg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="0.1"
            android:background="@drawable/edit_corner_white"
            android:gravity="start|top"
            android:inputType="textMultiLine"
            android:minLines="1"
            android:lines="1"
            android:maxLines="20"
            android:textSize="18dp"
            android:padding="10dp"
            android:hint="@string/napisz_cos"
            android:imeOptions="actionSend"
            />

然后在活动代码中:

 editTextMsg.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {


                int div   = editTextMsg.getText().toString().length() % 25;   //max 25chars in line

                if(div == 0 ) {
                    String tx = editTextMsg.getText().toString().trim() + "\n";
                    editTextMsg.setText(tx);

                    int pxH = (int)( editTextMsg.getLineCount() * 24 * getResources().getDisplayMetrics().density);

                    editTextMsg.setHeight (pxH );

                    //set cursor to end of text..
                    editTextMsg.setSelection(editTextMsg.length());
                }
            }
        });

0

这里有一个针对单行EditText视图的选项,它在每次更改后计算文本宽度并根据需要缩放textScale,遵循最大和最小大小。

也许有人可以改进它,使其适用于多行EditText。

// set up auto-text-size
val maxTextScale = binding.editText.textSize
val minTextScale = 0.2 * maxTextScale // ensure text doesn't get too small.
binding.editText.addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        val paint = TextPaint(binding.editText.paint)
        val desiredTextWidth = StaticLayout.getDesiredWidth(s, paint)

        // added so that the text isn't slightly too big
        val ensureWiggleRoom = 0.95F
        val scaleFactor = binding.editText.width / desiredTextWidth
        val candidateTextSize = truncate(binding.editText.textSize * scaleFactor * ensureWiggleRoom)
        if (candidateTextSize > minTextScale && candidateTextSize < maxTextScale) {
            binding.editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, candidateTextSize)
        }
    }

    override fun afterTextChanged(s: Editable?) {}
})

-1
你可以试试我的AutoSizeEditText:
   /**
 * Wrapper class for {@link EditText}.
 * It helps to achieve auto size behaviour which exists in {@link AppCompatTextView}.
 * The main idea of getting target text size is measuring {@link AppCompatTextView} and then
 * extracting from it text size and then applying extracted text size to target {@link EditText}.
 */
public class AutoSizeEditText extends FrameLayout {

    private static final String TEST_SYMBOL = "T";

    private static final boolean TEST = false;

    /**
     * Vertical margin which is applied by default in {@link EditText} in
     * comparison to {@link AppCompatTextView}
     */
    private static final float VERTICAL_MARGIN = convertDpToPixel(4);

    /**
     * {@link TextMeasure} which helps to get target text size for {@link #wrappedEditTex}
     * via its auto size behaviour.
     */
    @NonNull
    private final TextMeasure textMeasurer;

    /**
     * {@link AppCompatEditText} we want to show to the user
     */
    @NonNull
    private final EditText wrappedEditTex;

    public AutoSizeEditText(Context context) {
        this(context, null);
    }

    public AutoSizeEditText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoSizeEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        // don't clip children
        setClipChildren(false);
        setClipToOutline(false);
        setClipToPadding(false);

        // using AttributeSet of TextView in order to apply it our text views
        wrappedEditTex = createWrappedEditText(context, attrs);

        textMeasurer = createTextMeasure(context, attrs, wrappedEditTex);

        addView(wrappedEditTex, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));

        addView(textMeasurer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

    @NonNull
    private TextMeasure createTextMeasure(Context context, AttributeSet attrs, EditText editText) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.AutoSizeEditText);
        final int minSize = (int) typedArray.getDimension(R.styleable.AutoSizeEditText_autoSizeMinTextSize, convertDpToPixel(10));
        final int maxSize = (int) typedArray.getDimension(R.styleable.AutoSizeEditText_autoSizeMaxTextSize, convertDpToPixel(18));
        final int step = (int) typedArray.getDimension(R.styleable.AutoSizeEditText_autoSizeStepGranularity, convertDpToPixel(1));
        typedArray.recycle();

        TextMeasure textMeasurer = new TextMeasure(context);
        final Editable text = editText.getText();
        final CharSequence hint = editText.getHint();
        if (!TextUtils.isEmpty(text)) {
            textMeasurer.setText(text);
        } else if (!TextUtils.isEmpty(hint)) {
            textMeasurer.setText(hint);
        } else {
            textMeasurer.setText(TEST_SYMBOL);
        }

        TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
                textMeasurer, minSize, maxSize, step, TypedValue.COMPLEX_UNIT_PX);

        textMeasurer.setVisibility(View.INVISIBLE);
        textMeasurer.setPadding(0, 0, 0, 0);
        if (TEST) {
            textMeasurer.setTextColor(Color.RED);
            final ColorDrawable background = new ColorDrawable(Color.YELLOW);
            background.setAlpha(50);
            textMeasurer.setBackground(background);
            textMeasurer.setAlpha(0.2f);
            textMeasurer.setVisibility(View.VISIBLE);
        }
        return textMeasurer;
    }

    /**
     * Creating {@link EditText} which user will use and see
     *
     * @param attrs {@link AttributeSet} which comes from most likely from xml, which can be user for {@link EditText}
     *              if attributes of {@link TextView} were declared in xml
     * @return created {@link EditText}
     */
    @NonNull
    protected EditText createWrappedEditText(Context context, AttributeSet attrs) {
        return new AppCompatEditText(context, attrs);
    }

    @NonNull
    public EditText getWrappedEditTex() {
        return wrappedEditTex;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        wrappedEditTex.measure(
                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));

        final int targetHeight = (int) (height
                - VERTICAL_MARGIN * 2
                - wrappedEditTex.getPaddingTop()
                - wrappedEditTex.getPaddingBottom());

        final int targetWidth = (width
                - wrappedEditTex.getTotalPaddingStart()
                - wrappedEditTex.getTotalPaddingEnd());

        textMeasurer.measure(
                MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(targetHeight, MeasureSpec.EXACTLY)
        );

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        final int layoutHeight = getMeasuredHeight();
        final int layoutWidth = getMeasuredWidth();

        wrappedEditTex.layout(0, 0, layoutWidth, layoutHeight);

        if (changed) {
            final int measuredHeight = textMeasurer.getMeasuredHeight();
            final int measuredWidth = textMeasurer.getMeasuredWidth();
            final int topCoordinate = (int) (wrappedEditTex.getPaddingTop() + VERTICAL_MARGIN);
            final int leftCoordinate = wrappedEditTex.getTotalPaddingStart();

            textMeasurer.layout(
                    leftCoordinate,
                    topCoordinate,
                    measuredWidth + leftCoordinate,
                    topCoordinate + measuredHeight);

            wrappedEditTex.setTextSize(TypedValue.COMPLEX_UNIT_PX, textMeasurer.getTextSize());
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return wrappedEditTex.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return wrappedEditTex.onTouchEvent(event);
    }

    /**
     * Adjust text size due to the fact we want hint to be always visible
     *
     * @param hint Hint for {@link #wrappedEditTex}
     */
    public void setHint(CharSequence hint) {
        wrappedEditTex.setHint(hint);
        textMeasurer.setText(hint);
    }

    /**
     * Adjust text size for TypeFace, because it can change calculations
     *
     * @param typeface for {@link #wrappedEditTex}
     */
    public void setTypeface(Typeface typeface) {
        wrappedEditTex.setTypeface(typeface);
        textMeasurer.setTypeface(typeface);
    }

    public void setTextColor(Integer textColor) {
        wrappedEditTex.setTextColor(textColor);
    }

    public void setHintTextColor(Integer hintTextColor) {
        wrappedEditTex.setHintTextColor(hintTextColor);
    }

    public void setText(CharSequence text) {
        wrappedEditTex.setText(text);
    }

    private static class TextMeasure extends AppCompatTextView {

        public TextMeasure(Context context) {
            super(context);
        }

        @Override
        public void setInputType(int type) {

        }

        @Override
        public void setRawInputType(int type) {

        }

        @Override
        public int getInputType() {
            return EditorInfo.TYPE_NULL;
        }

        @Override
        public int getMaxLines() {
            return 1;
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            return true;
        }

        @Override
        public int getMinLines() {
            return 1;
        }
    }
}

以下是使用我的组件的示例:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.vladislavkarpman.autosizeedittext.AutoSizeEditText
        android:layout_width="300dp"
        android:layout_height="100dp"
        app:autoSizeMaxTextSize="50dp"
        app:autoSizeMinTextSize="4dp"
        app:autoSizeStepGranularity="1dp"
        app:autoSizeTextType="uniform"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接