TextView自动适配文本大小的几种方案

2023-10-31

标题太难取了,其实本文主要就是讲如何控制文本大小,让其自动适配宽度,其次我们还需要精准控制Text的高度和宽度间距等属性。

一般我们的布局都是分 match parent 和 wrap content 而他们的自动方式又有所不同。下面看看都有哪些方式来实现!

一、Autosizing的方式(固定宽度)

官方推出的TextView的Autosizing方式,在宽度固定的情况下,可以设置最大文本Size和最小文本Size和每次缩放粒度,非常方便的就能实现该功能。

 <TextView
        android:layout_width="340dp"
        android:layout_height="50dp"
        android:background="@drawable/shape_bg_008577"
        android:gravity="center_vertical"
        android:maxLines="1"
        android:text="这是标题,该标题的名字比较长,产品要求不换行全部显示出来"
        android:textSize="18sp"
        android:autoSizeTextType="uniform"
        android:autoSizeMaxTextSize="18sp"
        android:autoSizeMinTextSize="10sp"
        android:autoSizeStepGranularity="1sp"/>
复制代码
  1. autoSizeTextType:设置 TextView 是否支持自动改变文本大小,none 表示不支持,uniform 表示支持。
  2. autoSizeMinTextSize:最小文字大小,例如设置为10sp,表示文字最多只能缩小到10sp。
  3. autoSizeMaxTextSize:最大文字大小,例如设置为18sp,表示文字最多只能放大到18sp。
  4. autoSizeStepGranularity:缩放粒度,即每次文字大小变化的数值,例如设置为1sp,表示每次缩小或放大的值为1sp。

效果:

如果在Java代码中使用,我们也可以这么用

TextView tvText = findViewById(R.id.tv_text);
TextViewCompat.setAutoSizeTextTypeWithDefaults(tvText,TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM);
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(tvText,10,18,1, TypedValue.COMPLEX_UNIT_SP);
复制代码

二、自定义View的方式(固定宽度)

github上有很多这种的TextView自定义,类似这样的。

其核心思想和上面的 Autosizing 的方式类似,一般是测量 TextView 字体所占的宽度与 TextView 控件的宽度对比,动态改变 TextView 的字体大小。

它们的类似用法如下:

    <ru.igla.widget.AutoSizeTextView
        android:id="@+id/tvFullscreen"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Long ancestry"
        android:textColor="@android:color/black"
        android:background="@android:color/white"
        android:textSize="500sp"
        android:maxLines="500"
        android:gravity="center"
        android:ellipsize="@null"
        android:autoText="false"
        android:autoLink="none"
        android:linksClickable="false"
        android:singleLine="false"
        android:padding="0px"
        android:includeFontPadding="false"
        android:textAlignment="center"
        android:typeface="normal"
        android:layout_gravity="center"
        android:textStyle="normal"
        app:minTxtSize="8sp"
        />
复制代码

效果和方案一类似

三、使用工具类自行计算(非控件固定宽度)

把第二步中自定义View计算宽度的方法抽取出来,我们可以可以得到一个工具类如下:

private void adjustTvTextSize(TextView tv, int maxWidth, String text) {
        int avaiWidth = maxWidth - tv.getPaddingLeft() - tv.getPaddingRight();


        if (avaiWidth <= 0) {
            return;
        }

        TextPaint textPaintClone = new TextPaint(tv.getPaint());
     
        float trySize = textPaintClone.getTextSize();


        while (textPaintClone.measureText(text) > avaiWidth) {
            trySize--;
            textPaintClone.setTextSize(trySize);
        }


        tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, trySize);
    }
复制代码

Demo如下:

右侧的LinearLayout中需要包含2个文本 一个14sp 一个是30sp,同时居中但是要金额的文本自动适配大小。

            <LinearLayout        
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/d_15dp"
                android:layout_marginRight="@dimen/d_15dp"
                android:gravity="center"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/tv_job_detail_dollar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="$"
                    android:textColor="@color/black"
                    android:textSize="@dimen/job_detail_message_size"/>

                <TextView
                    android:id="@+id/text_view_hourly_rate"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="@dimen/d_2dp"
                    android:singleLine="true"
                    android:text="-"
                    android:textColor="@color/job_detail_black"
                    android:textSize="30sp" />

            </LinearLayout>
复制代码

可以看到2个都是wrap content,那么如何实现这种适应宽度+多布局的变长宽度效果呢。其实就是需要我们调用方法手动的计算金额TextView的宽度

    int mFullNameTVMaxWidth = CommUtils.dip2px(60);

    //    mTextViewHourlyRate.setText(totalMoney);
    //     while (true) {
    //         float measureTextWidth = mTextViewHourlyRate.getPaint().measureText(totalMoney);

    //         if (measureTextWidth > mFullNameTVMaxWidth) {
    //             int textSize = (int) mTextViewHourlyRate.getTextSize();
    //             textSize = textSize - 2;
    //             mTextViewHourlyRate.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
    //         } else {
    //             break;
    //         }
    //     }

    adjustTvTextSize(mTextViewHourlyRate,mFullNameTVMaxWidth,totalMoney)
复制代码

效果如下:(该效果是去除边距之后的对齐效果)

 

四、去除TextView的边距

我们都知道TextView绘制的时候并非是我们平常自定义View那种drawText,而是分为几块区域,基于基线绘制文本,并加入了上下左右的间距。

 

而不同的TextSize 它的间距还不同,比如上文中我们一个很小的 TextView 和一个很大的 TextView 在一起排列的时候,特别是大的 TextView 还是 AutoSize 的情况下,实现一些对齐效果就很难实现,并且本来宽度就极其有限了,再加上这么多无用的间距,搞得我们很难实现效果嘛!那我们就需要考虑到去除间距,只保留上图灰色的矩形框来绘制文本。

代码如下:

public class NoPaddingTextView extends AppCompatTextView {
    private Paint mPaint = getPaint();
    private Rect mBounds = new Rect();

    private Boolean mRemoveFontPadding = false;//是否去除字体内边距,true:去除 false:不去除

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

    public NoPaddingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttributes(context, attrs);
    }

    public NoPaddingTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttributes(context, attrs);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mRemoveFontPadding) {
            calculateTextParams();
            setMeasuredDimension(mBounds.right - mBounds.left, -mBounds.top + mBounds.bottom);
        }
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    protected void onDraw(Canvas canvas) {
        drawText(canvas);
    }

    /**
     * 初始化属性
     */
    private void initAttributes(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NoPaddingTextView);
        mRemoveFontPadding = typedArray.getBoolean(R.styleable.NoPaddingTextView_removeDefaultPadding, false);
        typedArray.recycle();
    }

    /**
     * 计算文本参数
     */
    private String calculateTextParams() {
        String text = getText().toString();
        int textLength = text.length();
        mPaint.getTextBounds(text, 0, textLength, mBounds);
        if (textLength == 0) {
            mBounds.right = mBounds.left;
        }
        return text;
    }

    /**
     * 绘制文本
     */
    private void drawText(Canvas canvas) {
        String text = calculateTextParams();
        int left = mBounds.left;
        int bottom = mBounds.bottom;
        mBounds.offset(-mBounds.left, -mBounds.top);
        mPaint.setAntiAlias(true);
        mPaint.setColor(getCurrentTextColor());
        canvas.drawText(text, (float) (-left), (float) (mBounds.bottom - bottom), mPaint);
    }
}
复制代码

使用:

            <LinearLayout           
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/d_15dp"
                android:layout_marginRight="@dimen/d_15dp"
                android:gravity="center"
                android:orientation="horizontal">

                <com.guadou.componentservice.widget.view.NoPaddingTextView
                    android:id="@+id/tv_job_detail_dollar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="$"
                    android:textColor="@color/black"
                    android:background="@color/yellow"
                    android:textSize="@dimen/job_detail_message_size"
                    app:removeDefaultPadding="true" />

                <com.guadou.componentservice.widget.view.NoPaddingTextView
                    android:id="@+id/text_view_hourly_rate"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="@dimen/d_2dp"
                    android:singleLine="true"
                    android:text="-"
                    android:background="@color/red"
                    android:textColor="@color/job_detail_black"
                    android:textSize="30sp"
                    app:removeDefaultPadding="true" />

            </LinearLayout>
复制代码

效果如下:


 

到此我们就能随心的控制 TextView 的大小和间距,想让文本多大就多大,想在哪展示就在哪展示,很方便的实现对齐和绝大部分文本的展示效果了。

 


 

链接:https://juejin.cn/post/7106714269730914312
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TextView自动适配文本大小的几种方案 的相关文章

  • 将数据从服务传递到活动

    我有自行运行的服务 服务自动启动 我有活动 在此 Activity 按钮中启动该方法DoIt Button setOnClickListener new OnClickListener public void onClick View v
  • Android主线程的IO操作

    我的问题有两个 是否建议在 Android 的主线程上进行 IO 操作 或者它是否有可能导致我的应用程序崩溃 如果在主线程上执行 IO 操作不理想 我可以使用哪些其他框架 以便当我的应用程序加载时它可以执行一些基本的 IO 文件读取并将值存
  • 如何从Firebase Firestore实时更新文档中获取修改后的字段或数据? [复制]

    这个问题在这里已经有答案了 我有多个文档 我的问题是我无法获取修改的特定数据 我正在获取完整的文档 db collection employees whereEqualTo OID OID addSnapshotListener new E
  • Android 中的 Fragment-Fragment 通信

    我在Android编程方面处于初级水平 所以我需要你真诚的帮助 请任何人帮助我 我正在尝试使用片段构建滑动用户界面 所以我真正的疑问是 我有一个Fragment say FragmentA 它有一个TextView and Button在其
  • Android 图表[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在开发一个项目 其中有一些图表 图形 刻度图 烛台图和范围图 但问题是 没有该图表的库 我有烛台图的
  • Android 全屏对话框确认和拒绝操作

    材料设计中的全屏对话框应该在操作栏 工具栏上有确认和拒绝操作 我的问题是 我该怎么做 显示对话框 getFragmentManager beginTransaction add R id container new MyDialogFrag
  • Ionic 2 RC0 和 Angular 2 最新的 Android 构建错误(ngc:错误:静态解析符号值时遇到错误)

    当我使用构建android时出现错误ionic build android命令 ngc 错误 静态解析符号值时遇到错误 引用本地 非导出 符号 字典 考虑导出符号 原始 ts文件中的位置14 8 解析符号TRANSLATION PROVID
  • HMS 核心地图套件在我的 Android 应用程序上根本无法工作

    我正在尝试在我的应用程序中使用华为 HMS 地图套件 我对整体地图很陌生 无论是来自谷歌还是华为 我按照文档中的教程以及华为提供的代码实验室中的说明进行操作 并将我的代码在一起 但是当我运行地图活动时 什么也没有出现 我得到的只是一个空白活
  • 透明 9patch 图像:显示出线条

    我得到了一个透明的 9 补丁图像 其中有 9 条补丁线显示槽 This is the output 显然我不希望水平线可见 这就是我创建 9patch 的方式 This is the final image that is used in
  • 控制 OverlayItem 大小

    我正在构建一个在单个 ItemizedOverlay 中包含几十个 OverlayItems 的地图 我的地图设计为可以非常近距离地查看 大约缩放级别 18 并且 OverlayItems 彼此非常接近 地图放大时看起来不错 但是 如果用户
  • 如何使用 SharedPreferences 保存多个值?

    我正在开发一个字典应用程序 在我的应用程序中 我假设用户想要保存最喜欢的单词 我决定使用共享首选项保存这些值 我知道 SQLite 和文件更好 但我坚持使用 SharedPreferences 所以继续使用它 下面是我的代码 Overrid
  • 在android中,将相机预览流到视图上

    我想将 Android 相机的相机预览流式传输到视图上 目的是随后使用 onDraw 将各种内容添加到视图中 我不需要随时实际捕捉图像 它不必是最高质量或每秒最大数量的帧 有谁知道如何做到这一点 将其添加到您的 xml 中
  • Android 上的 MIDI:Java 和/或 AIR 库

    一段时间以来 我一直在考虑在 iPad 上 重新 构建一个应用程序 其中我将使用 Objective C 和DSMI http dsmi tobw net 将 MIDI 信号发送到主机 这还不错 我的意思是 除了实际编写应用程序之外 现在我
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 如何为我的 Android Market APK 创建证书?

    我想将我的第一个 APK 应用程序上传到 Android Market 但我收到了此错误 顺便说一下 在 stackoverflow 中搜索时并没有引导我找到正确的链接 市场不接受使用调试证书签名的 APK 创建有效期至少 50 年的新证书
  • Android 中的 OpenGL 缩小

    我正在使用 3D 对象并渲染它并通过扩展 GLSurfaceView 实现渲染器来显示它 问题是如何通过捏合和捏合进行缩小 下面是我的班级 package com example objLoader import java nio Byte
  • Android SearchView 在启动时隐藏键盘

    我有一个小问题正在尝试解决 当我打开应用程序时 键盘会显示输入搜索视图的查询 不过 我只想在单击搜索视图时显示键盘 我该如何解决 Thanks 这对我有用 用于隐藏焦点的代码 searchView SearchView view findV
  • Android:GestureDetector 无法与选项卡(TabActivity、Tabwidget)一起工作(gestureDetector.onTouchEvent(event) 始终为 false)

    我已经用不同的子活动实现了 TabActivity intent new Intent setClass this MyChildTabActiviy class Initialize a TabSpec for each tab and
  • 受信任的网络活动 - 地址栏不隐藏(Android 72 的 Chrome)

    我已经关注了this https developers google com web updates 2017 10 using twa了解如何使用受信任的 Web 活动的指南 一切正常 但地址栏仍然出现 一开始我认为这是因为当应用程序正在
  • fs-extra:源和目标不能相同。 (科尔多瓦)

    我在使用 cordova 构建时遇到错误 Error Source and destination must not be the same 构建系统 Ionic ionic cli 4 10 1 ionic framework ionic

随机推荐