Android进阶之路 - EditText输入字体自适应

遇到这么一个需求:“控件宽度有限,随着输入内容,动态修改字体大小”,如果是你,只如何来实现?又有几种方式?

嗯,就是这么一个简单的需求,让我记录了俩篇blog
在这里插入图片描述

  • Android进阶之路 - 去除EditText内边距
  • Android进阶之路 - EditText输入字体自适应

起初我曾尝试通过监听TextChanged + 字体自适应 的方式,来实现 输入字体自适应 ,但是效果并不理想 ,所以最终换了别的方式

    • 简单、直接、有点low
    • AutoAdjustSizeEditText
    • AutoAdaptSizeEditText

该篇通过我所使用的几种方式,看看能否帮助大家,具体采用了以下几种方式,先简单介绍一下

  • 监听TextChanged,在一定规则内直接设置字体大小(字体过度不自然)
  • AutoAdjustSizeEditText 自定义控件(基本满足场景,不过单行可支持无线输入,可无限滑动)
  • AutoAdaptSizeEditText 控件借鉴于前者,稍加修改,用于满足某一场景(设置单行场景,超过固定宽度,则不可继续输入)

AutoAdjustSizeEditText、AutoAdaptSizeEditText 效果与布局引入

效果

请添加图片描述

布局引入

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><com.example.edittextdemo.AutoAdjustSizeEditTextandroid:layout_width="230dp"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:hint="AutoAdjustSizeEditText"android:textSize="20sp"app:maxTextSize="30sp"app:minTextSize="15sp" /><com.example.edittextdemo.AutoAdaptSizeEditTextandroid:layout_width="230dp"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="10dp"android:hint="AutoAdaptSizeEditText"android:singleLine="true"android:textSize="20sp"app:maxSize="30sp"app:minSize="15sp" />
</androidx.appcompat.widget.LinearLayoutCompat>

简单、直接、有点low

这种方式就想我说的使用起来很简单,唯一不足可能在于首先需要了解输入规则的要求,同时字体适应时会生硬一些(目前因为框架原因,我先使用了该方式)

因为框架原因,我直接提供伪代码用于各位借鉴吧

EditText - addTextChangedListener

在这里插入图片描述

通过规则,自行定义字体大小

在这里插入图片描述

splitties框架EditText.setTextIfDifferent扩展函数,内部会自行设置焦点位置

在这里插入图片描述


AutoAdjustSizeEditText

我看了很多篇关于 EditText 输入字体自适应 Blog,大多好像都脱胎于早期这款 AutoAdjustSizeEditText 自定义控件,我直接将源码跑完后发现基本可以适用于大部分场景,其中有优点有不足(仅个人认为),但依旧不可否认可以从前辈的代码中学习和成长(为表尊重,源码不做任何修改)

适用大部分场景,如果对单行显示长度有限定或许不太满足

自定义属性(之前一直没记录过自定义属性的相关blog,等有时间我必须补充一篇)

    <!-- 文本自动调整大小显示自定义属性 --><declare-styleable name="AutoAdjustTextSize"><attr name="minTextSize" format="dimension" /><attr name="maxTextSize" format="dimension" /></declare-styleable>

AutoAdjustSizeEditText

package com.example.edittextdemo;import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.EditText;
import android.widget.TextView;/*** 自动调整字体文本输入框* * @author 蒋庆意* @date 2015-11-4* @time 上午11:02:32*/
@SuppressLint("AppCompatCustomView")
public class AutoAdjustSizeEditText extends EditText {/*** 默认文字字体大小最小值(单位:像素)*/private static final float DEFAULT_TEXT_SIZE_MIN = 20;/*** 默认文字字体大小最大值(单位:像素)(貌似用不上)*/@SuppressWarnings("unused")private static final float DEFAULT_TEXT_SIZE_MAX = 60;/*** 画笔(用来测量已输入文字的长度)*/private Paint paint;/*** 文字字体大小最小值*/private float minTextSize = 0;/*** 文字字体大小最大值*/private float maxTextSize = 0;/*** 判断输入文本字体是否变小过*/private boolean hasScaleSmall = false;public AutoAdjustSizeEditTextBefore(Context context) {super(context);paint = new Paint();}public AutoAdjustSizeEditTextBefore(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint();//读取自定义属性, 获取设置的字体大小范围if (null != attrs) {TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AutoAdjustTextSize);if (null != array) {minTextSize = array.getDimension(R.styleable.AutoAdjustTextSize_minTextSize, DEFAULT_TEXT_SIZE_MIN);//如果未设置字体最大值,则使用当前字体大小作为最大值maxTextSize = array.getDimension(R.styleable.AutoAdjustTextSize_maxTextSize, this.getTextSize());//回收 TypedArrayarray.recycle();}}//未设置字体最小值,则使用默认最小值if (0 == minTextSize) {minTextSize = DEFAULT_TEXT_SIZE_MIN;}//未设置字体最大值,则使用当前字体大小作为最大值if (0 == maxTextSize) {//            maxTextSize = DEFAULT_TEXT_SIZE_MAX;maxTextSize = this.getTextSize();}//如果设置的值不正确(例如minTextSize>maxTextSize),则互换if (minTextSize > maxTextSize) {float minSize = maxTextSize;maxTextSize = minTextSize;minTextSize = minSize;}Log.d("AutoScaleSizeEditText","minTextSize=" + String.valueOf(minTextSize));Log.d("AutoScaleSizeEditText","maxTextSize=" + String.valueOf(maxTextSize));}@Overrideprotected void onTextChanged(CharSequence text, int start,int lengthBefore, int lengthAfter) {// 根据需要调整字体大小adjustTextSize(this);super.onTextChanged(text, start, lengthBefore, lengthAfter);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// 根据需要调整字体大小if (w != oldw) {adjustTextSize(this);}super.onSizeChanged(w, h, oldw, oldh);}/*** 调整文本的显示*/private void adjustTextSize(TextView textView) {if (null == textView) {//参数错误,不与处理return;}//已输入文本String text = textView.getText().toString();//已输入文本长度int textWidth = textView.getWidth();if (null == text || text.isEmpty() || textWidth <= 0) {return;}//获取输入框总的可输入的文本长度float maxInputWidth = textView.getWidth() - textView.getPaddingLeft() - textView.getPaddingRight();//获取当前文本字体大小float currentTextSize = textView.getTextSize();Log.d("AutoScaleSizeEditText","currentTextSize=" + String.valueOf(currentTextSize));//设置画笔的字体大小paint.setTextSize(currentTextSize);/** 循环减小字体大小* 当  1、文本字体小于最大值*     2、可输入文本长度小于已输入文本长度* 时*/while ((currentTextSize > minTextSize) && (maxInputWidth < paint.measureText(text))) {hasScaleSmall = true;Log.d("AutoScaleSizeEditText","TextSizeChange=" + String.valueOf(currentTextSize));--currentTextSize;if (currentTextSize < minTextSize) {currentTextSize = minTextSize;break;}//设置画笔字体大小paint.setTextSize(currentTextSize);}/** 循环增大字体大小* 当  1、文本字体小于默认值*     2、可输入文本长度大于已输入文本长度* 时*/while (hasScaleSmall && (currentTextSize < maxTextSize)&& (maxInputWidth > paint.measureText(text))) {Log.d("AutoScaleSizeEditText","TextSizeChangeSmall=" + String.valueOf(currentTextSize));++currentTextSize;if (currentTextSize > maxTextSize) {currentTextSize = maxTextSize;break;}//设置画笔字体大小paint.setTextSize(currentTextSize);}//设置文本字体(单位为像素px)textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, currentTextSize);Log.d("AutoScaleSizeEditText","currentTextSize2=" + String.valueOf(currentTextSize));}
}

AutoAdaptSizeEditText

之所以修改原始 AutoAdjustSizeEditText 控件,主要是考虑到我当前场景为单行场景,且宽度固定,如果一直对输入内容不做限制,用户体验上可能不太好(感觉部分朋友应该也会遇到类似场景)

自定义属性(因为我Demo中这俩款自定义控件都用到了自定义属性;而自定义属性不可重复,所以这里命名稍有改变)

    <!-- 文本自动调整大小显示自定义属性 --><declare-styleable name="AutoAdaptTextSize"><attr name="minSize" format="dimension" /><attr name="maxSize" format="dimension" /></declare-styleable>

AutoAdaptSizeEditText (感觉改的还行,不过还能优化一些写法,有时间再说吧)

package com.example.edittextdemo;import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.EditText;
import android.widget.TextView;/*** 自动调整字体文本输入框,限制单行输入宽度** @author ly* @date 2023*/
@SuppressLint("AppCompatCustomView")
public class AutoAdaptSizeEditText extends EditText {/*** 默认文字字体大小最小值(单位:像素)*/private static final float DEFAULT_TEXT_SIZE_MIN = 20;/*** 默认文字字体大小最大值(单位:像素)(貌似用不上)*/@SuppressWarnings("unused")private static final float DEFAULT_TEXT_SIZE_MAX = 60;/*** 画笔(用来测量已输入文字的长度)*/private Paint paint;/*** 文字字体大小最小值*/private float minTextSize = 0;/*** 文字字体大小最大值*/private float maxTextSize = 0;/*** 判断输入文本字体是否变小过*/private boolean hasScaleSmall = false;/*** 可输出文本的最大长度*/private int length = 0;/*** 可编辑状态*/private boolean editState = false;public AutoAdaptTextSize(Context context) {super(context);paint = new Paint();}public AutoAdaptTextSize(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs);}public void init(Context context, AttributeSet attrs) {paint = new Paint();editState = true;//读取自定义属性, 获取设置的字体大小范围if (null != attrs) {TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AutoAdaptTextSize);if (null != array) {minTextSize = array.getDimension(R.styleable.AutoAdaptTextSize_minSize, DEFAULT_TEXT_SIZE_MIN);//如果未设置字体最大值,则使用当前字体大小作为最大值maxTextSize = array.getDimension(R.styleable.AutoAdaptTextSize_maxSize, this.getTextSize());//回收 TypedArrayarray.recycle();}}//未设置字体最小值,则使用默认最小值if (0 == minTextSize) {minTextSize = DEFAULT_TEXT_SIZE_MIN;}//未设置字体最大值,则使用当前字体大小作为最大值if (0 == maxTextSize) {//            maxTextSize = DEFAULT_TEXT_SIZE_MAX;maxTextSize = this.getTextSize();}//如果设置的值不正确(例如minTextSize>maxTextSize),则互换if (minTextSize > maxTextSize) {float minSize = maxTextSize;maxTextSize = minTextSize;minTextSize = minSize;}}@Overrideprotected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {// 根据需要调整字体大小autoAdaptTextSize(this);super.onTextChanged(text, start, lengthBefore, lengthAfter);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// 对比前后输入前后字体大小if (w != oldw) {autoAdaptTextSize(this);}super.onSizeChanged(w, h, oldw, oldh);}/*** 调整文本的显示*/private void autoAdaptTextSize(TextView textView) {if (null == textView) {//参数错误,不与处理return;}//已输入文本String text = textView.getText().toString();//已输入文本长度int textWidth = textView.getWidth();if (text.isEmpty() || textWidth <= 0) {return;}//获取输入框总的可输入的文本长度float maxInputWidth = textView.getWidth() - textView.getPaddingLeft() - textView.getPaddingRight();//获取当前文本字体大小float currentTextSize = textView.getTextSize();Log.d("AutoScaleSizeEditText", "currentTextSize=" + String.valueOf(currentTextSize));//设置画笔的字体大小paint.setTextSize(currentTextSize);/** 循环减小字体大小,条件如下* 1、文本字体小于最大值* 2、可输入文本长度小于已输入文本长度*/while ((currentTextSize > minTextSize) && (paint.measureText(text) > maxInputWidth)) {Log.e("tag", "paint.measureText(text)=" + paint.measureText(text) + "maxInputWidth:" + maxInputWidth);hasScaleSmall = true;--currentTextSize;if (currentTextSize < minTextSize) {currentTextSize = minTextSize;break;}//设置画笔字体大小paint.setTextSize(currentTextSize);}/** 循环增大字体大小,条件如下* 1、文本字体小于默认值* 2、可输入文本长度大于已输入文本长度*/while (hasScaleSmall && (currentTextSize < maxTextSize) && (maxInputWidth > paint.measureText(text))) {++currentTextSize;if (currentTextSize > maxTextSize) {currentTextSize = maxTextSize;break;}//设置画笔字体大小paint.setTextSize(currentTextSize);}/** 限制输入,条件如下* 1、当前字体大小已经为我们设置的最小字体(兼容最小值)* 2、所有字体的宽度对比控件的最大宽度*/Log.e("tag", "当前字体Size=" + currentTextSize + "最小字体Size:" + minTextSize);Log.e("tag", "字体宽度=" + paint.measureText(text) + "控件宽度:" + maxInputWidth);if (currentTextSize <= minTextSize && paint.measureText(text) > maxInputWidth) {Log.e("tag", "超过预设值,不支持继续输入");if (editState) {editState = false;length = text.length();}if (text.length() > length) {this.setText(text.substring(0, length));this.setSelection(length); //光标位于尾部}//最大可输出入字符数,限制输入的关键点this.setEms(length);} else {editState = true;}//设置文本字体(单位为像素px)textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, currentTextSize);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/83665.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

象小朋友学识字一样建构战略

战略认知派: 就像小孩子学识字的过程一样【安志强趣讲268期】 趣讲大白话&#xff1a;提高认知中长大 **************************** 基于认知心理学 战略的形成是认知构建的过程 最找连战略这个词都不一定知道 慢慢有些概念 慢慢形成整体的认知 战略认知派分两个分支 第一分支…

sql server删除历史数据

1 函数 datediff函数: DATEDIFF ( datepart , startdate , enddate )datepart的取值可以是year,quarter,Month,dayofyear,Day,Week,Hour,minute,second,millisecond startdate 是从 enddate 减去。如果 startdate 比 enddate 晚&#xff0c;返回负值。 2 例子 删除2023年以…

运维高级学习--Kubernetes(K8s 1.28.x)部署

一、基础环境配置&#xff08;所有主机操作&#xff09; 主机名规划 序号 主机ip 主机名规划1 192.168.1.30 kubernetes-master.openlab.cn kubernetes-master2 192.168.1.31 kubernetes-node1.openlab.cn kubernetes-node13 192.168.1.32 kubernetes-node2…

生成模型 -- GAN

文章目录 1. 生成模型与判别模型1.1 生成模型 2. VAE3. GAN3.1 GAN-生成对抗网络3.2 GAN-生成对抗网络的训练3.2.1 判别模型的训练&#xff1a;3.2.2 生成网络的训练&#xff1a; 4. LeakyReLU5. GAN代码实例 1. 生成模型与判别模型 生成模型与判别模型 我们前面几章主要介绍了…

验证码服务(使用提供好的项目)

1、先生成一个指定位数的验证码&#xff0c;根据需要可能是数字、数字字母组合或文字。 2、根据生成的验证码生成一个图片并返回给页面 3、给生成的验证码分配一个key&#xff0c;将key和验证码一同存入缓存。这个key和图片一同返回给页面。 4、用户输入验证码&#xff0c;连…

【宝藏系列】一文带你梳理 Linux 的五种 IO 模型

【宝藏系列】一文带你梳理 Linux 的五种 IO 模型 文章目录 【宝藏系列】一文带你梳理 Linux 的五种 IO 模型&#x1f468;‍&#x1f3eb;前言1️⃣用户态和核心态1️⃣1️⃣用户态和核心态的切换 2️⃣进程切换3️⃣进程阻塞4️⃣文件描述符(fd, File Descriptor)5️⃣缓存I/O…

定州市社会保险待遇手机app-定州社会保障

社会保险的缴纳主要包括养老保险、医疗保险、生育保险&#xff0c;单位职工还有工伤保险和失业保险的缴纳&#xff0c;社会保险的缴纳一般都在当地人力资源和社会保障部门&#xff0c;在定州&#xff0c;社会保险登记的流程是怎样走的&#xff1f;下面由法律指南小编为大家解答…

根据案例写PLC程序-红绿灯控制

案例&#xff1a; 1、南北方向红灯点亮30s后熄灭&#xff1b; 2、在点亮南北方向红灯的同时点亮东西方向绿灯&#xff0c;并在点亮25s后&#xff0c;以0.5s熄灭0.5s点亮的时间闪烁3次后熄灭&#xff1b; 3、在东西方向绿灯熄灭后&#xff0c;东西方向黄灯点亮2s后熄灭&#xff…

【KingSCADA】问题处理:记录KS历史报警查询异常

哈喽&#xff0c;大家好&#xff01;我是雷工。 本篇记录KingSCADA的历史报警应用中的一个问题&#xff0c;及处理过程。 一、问题描述 最近客户遇到这么一个问题&#xff1a;当打开历史报警窗界面&#xff0c;自动加载的报警信息中有显示最近几天的报警信息&#xff0c;但当…

react18+antd5.x(1):Notification组件的二次封装

antdesign已经给我们提供了很好的组件使用体验,但是我们还需要根据自己的项目业务进行更好的封装,减少我们的代码量,提升开发体验 效果展示 开起来和官网的使用没什么区别,但是我们在使用的时候,进行了二次封装,更利于我们进行开发 MyNotification.jsx,是我们的业务页面…

VUE笔记(四)vue的组件

一、组件的介绍 1、组件的作用 整个项目都是由组件组成 可以让代码复用&#xff1a;相似结构代码可以做成一个组件&#xff0c;直接进行调用就可以使用&#xff0c;提高代码复用性 可以让代码具有可维护性&#xff08;只要改一处&#xff0c;整个引用的部分全部都变&#xf…

Java——一个Java实体类,表示一个试题的模型

这段代码是一个Java实体类&#xff0c;表示一个试题的模型。 该实体类具有以下属性&#xff1a; id&#xff1a;题号&#xff0c;表示试题的编号。title&#xff1a;题目&#xff0c;表示试题的题目内容。optionA&#xff1a;选项A&#xff0c;表示试题的选项A。optionB&#…