Autosizing TextViews in RecyclerView causes text size to decrease

我的未来我决定 提交于 2020-12-29 09:21:05

问题


I am trying to use Autosizing TextViews in a RecyclerView, but when I scroll a few times the text gets so small that it's obviously not working properly.

Example of my TextView:

<android.support.v7.widget.AppCompatTextView
        android:id="@+id/textview_unit_title"
        android:layout_width="@dimen/tile_image_size"
        android:layout_height="wrap_content"
        android:maxLines="2"
        android:textSize="@dimen/medium_size"
        android:textColor="@color/color_text"
        android:paddingTop="@dimen/padding_title"
        android:layout_marginRight="2dp"
        android:layout_marginEnd="2dp"
        app:autoSizeMaxTextSize="@dimen/style_medium"
        app:autoSizeTextType="uniform"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@id/imageview_unit_icon"
        app:layout_constraintTop_toTopOf="parent"/>

Should I update this scaling somewhere else programmatically or is there another solution?


回答1:


Autosizing TextViews

Android 8.0 (API level 26) allows you to instruct a TextView to let the text size expand or contract automatically to fill its layout based on the TextView's characteristics and boundaries.

Note: If you set autosizing in an XML file, it is not recommended to use the value "wrap_content" for the layout_width or layout_height attributes of a TextView. It may produce unexpected results.

You should bound height

 android:layout_height="30dp"



回答2:


The issue I've seen with this is that setting your view height to be wrap_content allows the text size to get smaller, but the text will never get bigger again. This is why the documentation recommends to not use wrap_content for the view size. However, I've found that if you turn off the auto-resizing, set the text size to whatever the max is, then re-enable auto-resizing, the text size resets to the largest size and scales down as necessary.

So my view in XML would look like:

<android.support.v7.widget.AppCompatTextView
    android:id="@+id/text_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:textAllCaps="true"
    android:textColor="@android:color/white"
    android:textSize="42sp"
    app:autoSizeMinTextSize="26dp"
    app:autoSizeMaxTextSize="42dp"
    app:autoSizeTextType="none"/>

Then in my ViewHolder when I bind my text to the view:

TextView title = view.findViewById(R.id.text_title);
String titleValue = "Some Title Value";

// Turn off auto-sizing text.
TextViewCompat.setAutoSizeTextTypeWithDefaults(title, 
    TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);

// Bump text size back up to the max value.
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 42);

// Set your text as normal.
title.setText(titleValue);

// Post a runnable to re-enable auto-sizing text so that it occurs
// after the view is laid out and measured at max text size.
title.post(new Runnable() {
    @Override
    public void run() {     
        TextViewCompat
            .setAutoSizeTextTypeUniformWithConfiguration(title,
                    26, 42, 1, TypedValue.COMPLEX_UNIT_DIP);
    }
});



回答3:


Pavel Haluza's answer's approach was great. However, it didn't work, probably because he missed a line setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);.

Here is my updated version:

public class MyTextView extends AppCompatTextView {

private int minTextSize;
private int maxTextSize;
private int granularity;

public MyTextView(Context context) {
    super(context);
    init();
}

public MyTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public MyTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init() {
    minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
    maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
    granularity = Math.max(1, TextViewCompat.getAutoSizeStepGranularity(this));
}

@Override
public void setText(CharSequence text, BufferType type) {
    // this method is called on every setText
    disableAutoSizing();
    setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);
    super.setText(text, type);
    post(this::enableAutoSizing); // enable after the view is laid out and measured at max text size
}

private void disableAutoSizing() {
    TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
}

private void enableAutoSizing() {
    TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this,
            minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
}}



回答4:


I packaged Michael Celey's answer into a class. The parameters app:autoSizeMinTextSize, app:autoSizeMaxTextSize, app:autoSizeTextType are taken from xml.

public class AutosizingTextView extends AppCompatTextView {

    private int minTextSize;
    private int maxTextSize;
    private int granularity;

    public AutosizingTextView(Context context) {
        super(context);
        init();
    }

    public AutosizingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AutosizingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
        maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
        granularity = TextViewCompat.getAutoSizeStepGranularity(this);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        // this method is called on every setText
        disableAutosizing();
        super.setText(text, type);
        post(this::enableAutosizing); // enable after the view is laid out and measured at max text size
    }

    private void disableAutosizing() {
        TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
    }

    private void enableAutosizing() {
        TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this,
                minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
    }
}```



回答5:


the above solutions didn't work for me so here's mine

public class MyTextView extends AppCompatTextView {
    ...
    @Override
    public final void setText(CharSequence text, BufferType type) {
        // work around stupid auto size text not *growing* the font size we re binding in a RecyclerView if previous bind caused a small font
        int minTextSize = 0, maxTextSize = 0, granularity = 0;
        boolean doHack = TextViewCompat.getAutoSizeTextType(this) != TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE;
        if (doHack) {
            minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
            maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
            if (minTextSize <= 0 || maxTextSize <= minTextSize) { // better than validateAndSetAutoSizeTextTypeUniformConfiguration crashing
                if (BuildConfig.DEBUG)
                    throw new AssertionError("fix ya layout");
                doHack = false;
            } else {
                granularity = TextViewCompat.getAutoSizeStepGranularity(this);
                if (granularity < 0)
                    granularity = 1; // need this else setAutoSizeTextTypeUniformWithConfiguration barfs. TextView.UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = 1.
                // make the TextView have 0 size so setAutoSizeTextTypeUniformWithConfiguration won't do calculations until after a layout pass using maxSize
                TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
                setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);
                measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
                setRight(getLeft());
                setBottom(getTop());
                requestLayout();
            }
        }
        super.setText(text, type);
        if (doHack)
            TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this, minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
    }
    ...
}



回答6:


Just .setText("") before resetting the text size you want. That ensures that you are not setting the textsize and then immediately autoresizing using the previous text value in the TextView. Like this:

TextView wordWordTextView = getView().findViewById(R.id.wordWordTextView);
wordWordTextView.setAlpha(0.0f);
wordWordTextView.setText("");
wordWordTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 50);
wordWordTextView.setText(wordStr);
wordWordTextView.animate().alpha(1.0f).setDuration(250);


来源:https://stackoverflow.com/questions/50696258/autosizing-textviews-in-recyclerview-causes-text-size-to-decrease

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!