写点什么

Android 自定义 TextView 实现高度和宽度,解决字体适配问题

作者:芝麻粒儿
  • 2022 年 7 月 07 日
  • 本文字数:3743 字

    阅读完需:约 12 分钟

Android自定义TextView实现高度和宽度,解决字体适配问题

👉关于作者

众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!

专注于 Android/Unity 和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)

👉即将学会

利用 TextView 的 onTextChanged 方法来实现宽度高度自适应的控件,目前只适用于单行。

👉背景

🙈小空:出现的原因是项目需要的设备广(涉及到手机/平板/大电视/无数的定制设备)。如果是知名的品牌还好,关键客户还是一些乱七八糟的品牌,无数尺寸造成的屏幕密度。

🙎小芝:你说气人不气人。我都炸了。

🙈小空(叹气):关键又没给更多的适配开始时间。这就很伤人了,如果使用资源文件 values 适配的话,那烧香都怕香不够,甚至引发一连串的事故。

🙎小芝(疑问):所以呢?有解决办法吗!

🙈小空:那当然,虽然是取巧的形式,但好歹解决了问题。最开始的时候也是没有思路,在 GitHub 上搜索了半天,终于找到了类似的开源:AutoFitTextView,截止 2021-8-2 拥有 800 多 Star。其他也搜索到了不少,但是并不满足解决需求。

🙎小芝(很开心):哇,感谢开源。

👉实践过程

目前适应的范围:TextView 无宽高限制;无其他限制; 不过项目中使用的权重布局,可根据情况调整!实现的结果:在下方图的控件上回自动填充满,控件大,字体大,控件小,字体小!



程序:注释解释很全


import android.content.Context;import android.graphics.Paint;import android.support.annotation.Nullable;import android.text.TextPaint;import android.util.AttributeSet;import android.view.Gravity;import android.widget.TextView;/**  * Created by akitaka on 2018-07-05. * https://zhima.blog.csdn.net/  * https://juejin.cn/user/4265760844943479/columns  * https://www.zhihu.com/people/zhimalier  * @filename FitHeightTextView  * @describe 根据高度自适应字体文字大小  * @email 960576866@qq.com */public class FitHeightTextView extends TextView {    private Paint mTextPaint;    private float mMaxTextSize; // 获取当前所设置文字大小作为最大文字大小    private float mMinTextSize = 8;    //最小的字体大小     public FitHeightTextView(Context context) {        super(context);    }     public FitHeightTextView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        setGravity(getGravity() | Gravity.CENTER_VERTICAL); // 默认水平居中        setLines(1);        initialise();    }     private void initialise() {        mTextPaint = new TextPaint();        mTextPaint.set(this.getPaint());        //默认的大小是设置的大小,如果撑不下了 就改变        mMaxTextSize = this.getTextSize();    }     //文字改变的时候    @Override    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {        refitText(text.toString(), this.getHeight());   //textview视图的高度        super.onTextChanged(text, start, lengthBefore, lengthAfter);    }     private void refitText(String textString, int height) {        if (height > 0) {            //减去边距为字体的实际高度            int availableHeight = height - this.getPaddingTop() - this.getPaddingBottom();               float trySize = mMaxTextSize;            mTextPaint.setTextSize(trySize);            while (mTextPaint.descent()-mTextPaint.ascent() > availableHeight) {                  //测量的字体高度过大,不断地缩放                trySize -= 1;  //字体不断地减小来适应                if (trySize <= mMinTextSize) {                    trySize = mMinTextSize;  //最小为这个                    break;                }                mTextPaint.setTextSize(trySize);            }            setTextSize(px2sp(getContext(), trySize));        }    }     //大小改变的时候    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        if (h != oldh) {            refitText(this.getText().toString(), h);        }    }     /**     * 将px值转换为sp值,保证文字大小不变     */    public static float px2sp(Context context, float pxValue) {        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;        return (pxValue / fontScale);    }}
复制代码


在布局中使用的话,注意按照你最大的设备来设置字体大小,这样在小设备上回自动缩放


 android:textSize  保持为支持最大设备的字体大小
复制代码


  <cn.jucheng.www.cpr.util.FitHeightTextView                            android:layout_width="wrap_content"                            android:layout_height="wrap_content"                            android:gravity="center_vertical"                            android:text="设置"                            android:textSize="28sp"                            android:textColor="#56BBe0" />
复制代码


试验后就会发现,真的很神奇;


有根据高度,就有根据宽度的自动适配,这个是网上的,同时 github 上也大多是这种效果;上个简单的代码

/**  * Created by akitaka on 2018-07-05. * https://zhima.blog.csdn.net/  * https://juejin.cn/user/4265760844943479/columns  * https://www.zhihu.com/people/zhimalier  * @filename FitHeightTextView  * @describe 根据高度自适应字体文字大小  * @email 960576866@qq.com */public class FitTextView extends TextView{	 private Paint mTextPaint;	    private float mMaxTextSize; // 获取当前所设置文字大小作为最大文字大小	    private float mMinTextSize = 3; 	    public FitTextView(Context context) {	        this(context, null);	    } 	    public FitTextView(Context context, AttributeSet attrs) {	        super(context, attrs);	        setGravity(getGravity() | Gravity.CENTER_VERTICAL); // 默认水平居中	        setLines(1);	        initialise();	    } 	    @Override	    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {	        refitText(text.toString(), this.getWidth());	        super.onTextChanged(text, start, lengthBefore, lengthAfter);	    } 	    private void initialise() {	        mTextPaint = new TextPaint();	        mTextPaint.set(this.getPaint());	        // 最大的大小默认为特定的文本大小,除非它太小了	        mMaxTextSize = this.getTextSize();//	        mMinTextSize = 8;	    } 	    @Override	    protected void onSizeChanged(int w, int h, int oldw, int oldh) {	        if (w != oldw) {	            refitText(this.getText().toString(), w);	        }	    } 	    /**	     * Resize the font so the specified text fits in the text box	     * assuming the text box is the specified width.	     *    	     */	    private void refitText(String text, int textWidth) {	        if (textWidth > 0) {	            int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();	            float trySize = mMaxTextSize; 	            mTextPaint.setTextSize(trySize);	            while (mTextPaint.measureText(text) > availableWidth) { 	                trySize -= 1;	                if (trySize <= mMinTextSize) {	                    trySize = mMinTextSize;	                    break;	                }	                mTextPaint.setTextSize(trySize);	            } 	            // setTextSize参数值为sp值	            setTextSize(px2sp(getContext(), trySize));	        }	    } 	    /**	     * 将px值转换为sp值,保证文字大小不变	     */	    public static float px2sp(Context context, float pxValue) {	        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;	        return (pxValue / fontScale);	    } }
复制代码


主要的区别在于:TextPaint 的方法:measureText(text) descent ascent!

👉其他

📢作者:小空和小芝中的小空

📢转载说明-务必注明来源:https://www.infoq.cn/profile/DB2492B85795C4/publish

📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

发布于: 刚刚阅读数: 3
用户头像

芝麻粒儿

关注

尺有所短;寸有所长。 2020.08.29 加入

👑CSDN博客专家-华为云享专家-Android/Unity领域优质作者 🏅目前在模拟医学行业做Android/Unity双端开发 🏆微信公众号:【空名先生】 🏆QQ交流群:204918251或877807592

评论

发布
暂无评论
Android自定义TextView实现高度和宽度,解决字体适配问题_Android Studio_芝麻粒儿_InfoQ写作社区