Autosizing TextViews in RecyclerView causes text size to decrease

后端 未结 6 830
野趣味
野趣味 2021-02-13 17:24

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

相关标签:
6条回答
  • 2021-02-13 17:35

    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);
    }}
    
    0 讨论(0)
  • 2021-02-13 17:35

    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);
    
    0 讨论(0)
  • 2021-02-13 17:40

    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);
        }
    });
    
    0 讨论(0)
  • 2021-02-13 17:42

    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);
        }
    }```
    
    0 讨论(0)
  • 2021-02-13 17:52

    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"
    
    0 讨论(0)
  • 2021-02-13 17:55

    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);
        }
        ...
    }
    
    0 讨论(0)
提交回复
热议问题