How to adjust text font size to fit textview

后端 未结 22 1777
無奈伤痛
無奈伤痛 2020-11-22 05:15

Is there any way in android to adjust the textsize in a textview to fit the space it occupies?

E.g. I\'m using a TableLayout and adding several Te

22条回答
  •  被撕碎了的回忆
    2020-11-22 05:45

    Here is my solution which works on emulator and phones but not very well on Eclipse layout editor. It's inspired from kilaka's code but the size of the text is not obtained from the Paint but from measuring the TextView itself calling measure(0, 0).

    The Java class :

    public class FontFitTextView extends TextView
    {
        private static final float THRESHOLD = 0.5f;
    
        private enum Mode { Width, Height, Both, None }
    
        private int minTextSize = 1;
        private int maxTextSize = 1000;
    
        private Mode mode = Mode.None;
        private boolean inComputation;
        private int widthMeasureSpec;
        private int heightMeasureSpec;
    
        public FontFitTextView(Context context) {
                super(context);
        }
    
        public FontFitTextView(Context context, AttributeSet attrs) {
                this(context, attrs, 0);
        }
    
        public FontFitTextView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
    
                TypedArray tAttrs = context.obtainStyledAttributes(attrs, R.styleable.FontFitTextView, defStyle, 0);
                maxTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_maxTextSize, maxTextSize);
                minTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_minTextSize, minTextSize);
                tAttrs.recycle();
        }
    
        private void resizeText() {
                if (getWidth() <= 0 || getHeight() <= 0)
                        return;
                if(mode == Mode.None)
                        return;
    
                final int targetWidth = getWidth();
                final int targetHeight = getHeight();
    
                inComputation = true;
                float higherSize = maxTextSize;
                float lowerSize = minTextSize;
                float textSize = getTextSize();
                while(higherSize - lowerSize > THRESHOLD) {
                        textSize = (higherSize + lowerSize) / 2;
                        if (isTooBig(textSize, targetWidth, targetHeight)) {
                                higherSize = textSize; 
                        } else {
                                lowerSize = textSize;
                        }
                }
                setTextSize(TypedValue.COMPLEX_UNIT_PX, lowerSize);
                measure(widthMeasureSpec, heightMeasureSpec);
                inComputation = false;
        }
    
        private boolean isTooBig(float textSize, int targetWidth, int targetHeight) {
                setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
                measure(0, 0);
                if(mode == Mode.Both)
                        return getMeasuredWidth() >= targetWidth || getMeasuredHeight() >= targetHeight;
                if(mode == Mode.Width)
                        return getMeasuredWidth() >= targetWidth;
                else
                        return getMeasuredHeight() >= targetHeight;
        }
    
        private Mode getMode(int widthMeasureSpec, int heightMeasureSpec) {
                int widthMode = MeasureSpec.getMode(widthMeasureSpec);
                int heightMode = MeasureSpec.getMode(heightMeasureSpec);
                if(widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY)
                        return Mode.Both;
                if(widthMode == MeasureSpec.EXACTLY)
                        return Mode.Width;
                if(heightMode == MeasureSpec.EXACTLY)
                        return Mode.Height;
                return Mode.None;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                if(!inComputation) {
                        this.widthMeasureSpec = widthMeasureSpec;
                        this.heightMeasureSpec = heightMeasureSpec;
                        mode = getMode(widthMeasureSpec, heightMeasureSpec);
                        resizeText();
                }
        }
    
        protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
                resizeText();
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                if (w != oldw || h != oldh)
                        resizeText();
        }
    
        public int getMinTextSize() {
                return minTextSize;
        }
    
        public void setMinTextSize(int minTextSize) {
                this.minTextSize = minTextSize;
                resizeText();
        }
    
        public int getMaxTextSize() {
                return maxTextSize;
        }
    
        public void setMaxTextSize(int maxTextSize) {
                this.maxTextSize = maxTextSize;
                resizeText();
        }
    }
    

    The XML attribute file :

    
        
            
            
        
    
    

    Check my github for the latest version of this class. I hope it can be useful for someone. If a bug is found or if the code needs explaination, feel free to open an issue on Github.

提交回复
热议问题