一行代码搞定EditText:限制最多输入 30 个字符,实时显示 0/30,超出自动截断

总结:

方案优点适用场景
工具类:LimitedEditTextHelper​​(当前封装)✅ 代码简洁,一行接入
✅ 灵活,不侵入布局
✅ 易扩展、易维护
绝大多数需要限制字数 + 显示计数器的场景
自定义控件(组合 EditText + TextView✅ 更高度封装,像一个整体组件
✅ 可复用 UI 布局
需要反复在 XML 中使用「带计数器的输入框」时

下面就列出

LimitedEditTextHelper方案,推荐使用:

package com.bg.widget;
import android.graphics.Color;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.TextView;

/*

EditText editText = findViewById(R.id.editText);
        TextView tvCharCount = findViewById(R.id.tvCharCount);

        // ✅ 一行代码搞定:限制最多输入 30 个字符,实时显示 0/30,超出自动截断
        new LimitedEditTextHelper(editText, tvCharCount, 30);


// 初始化:最多允许输入 30 个字
LimitedEditTextCountHelper helper = new LimitedEditTextCountHelper(editText, tvCharCount, 30);

// 用户点击某个按钮后,你决定把最大字数改为 50
helper.setMaxCharCount(50); // ✅ 自动检查当前输入是否超限,超出则截断,同时更新UI
helper.getCurrentText();      // 获取输入内容
helper.setMaxChars(50);       // 动态修改最大字数
helper.setHint("新提示文案");   // 动态设置输入框提示
 */
/**
 * 封装一个带字数限制和实时统计的 EditText 辅助类
 */
public class LimitedEditTextCountHelper {

    private final EditText editText;
    private final TextView charCountTextView;
    private int maxCharCount; // 改为非 final,支持动态修改
    private LimitedEditTextCountHelper mLimitedEditTextHelperListener;
    /**
     * 构造函数
     *
     * @param editText           要限制的 EditText
     * @param charCountTextView  显示字数统计的 TextView,格式如 "当前/最大"
     * @param maxCharCount       最大允许输入的字数,比如 30
     */
    public LimitedEditTextCountHelper(EditText editText, TextView charCountTextView, int maxCharCount) {
        if (editText == null || charCountTextView == null) {
            throw new IllegalArgumentException("EditText 和 TextView 不能为 null");
        }
        if (maxCharCount <= 0) {
            throw new IllegalArgumentException("最大字数必须 > 0");
        }

        this.editText = editText;
        this.charCountTextView = charCountTextView;
        this.maxCharCount = maxCharCount;

        setup();
    }

    private void setup() {
        // 初始化显示
        updateCharCount(0);

        // 监听输入变化
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

            @Override
            public void afterTextChanged(Editable s) {
                int currentLength = s.length();
                updateCharCount(currentLength);

                // 如果当前内容超出最大字数限制,则截断
                if (currentLength > maxCharCount) {
                    String limitedText = s.subSequence(0, maxCharCount).toString();
                    editText.setText(limitedText);
                    editText.setSelection(maxCharCount); // 光标移到末尾
                    updateCharCount(maxCharCount);

                    if (null != mLimitedEditTextHelperListener) {
                        mLimitedEditTextHelperListener.onMaxCharCountCall(maxCharCount, currentLength);
                    }
                }
            }
        });
    }

    /**
     * 更新字数显示,并根据是否超限设置颜色
     */
    private void updateCharCount(int current) {
        charCountTextView.setText(current + "/" + maxCharCount);
        // 超出限制时显示红色,否则默认灰色
        charCountTextView.setTextColor(current > maxCharCount ? Color.RED : Color.GRAY);
    }

    /**
     * 获取当前输入框中的文本内容
     */
    public String getCurrentText() {
        return editText.getText().toString();
    }
    /**
     * ✅ 动态设置输入框提示文案
     */
    public void setHint(String hintText) {
        if (editText != null) {
            editText.setHint(hintText);
        }
    }

    /**
     * 动态设置新的最大字数限制
     *
     * @param newMaxCharCount 新的最大字数,必须 > 0
     */
    public void setMaxCharCount(int newMaxCharCount) {
        if (newMaxCharCount <= 0) {
            throw new IllegalArgumentException("最大字数必须 > 0");
        }

        this.maxCharCount = newMaxCharCount;

        // 获取当前输入内容
        Editable currentText = editText.getText();
        int currentLength = currentText != null ? currentText.length() : 0;

        // 如果当前内容超出新的最大限制,则进行截断
        if (currentLength > newMaxCharCount) {
            String trimmedText = currentText.subSequence(0, newMaxCharCount).toString();
            editText.setText(trimmedText);
            editText.setSelection(newMaxCharCount); // 光标移到新限制的末尾
        }

        // 更新 UI 显示的字数和颜色状态
        updateCharCount(Math.min(currentLength, newMaxCharCount));
    }

    public void setLimitedEditTextCountHelperListener(LimitedEditTextHelperListener mLimitedEditTextHelperListener) {
        this.mLimitedEditTextHelperListener = mLimitedEditTextHelperListener;
    }

    /**
     * [相关回调监听]
     */

    public interface LimitedEditTextCountHelperListener {
        /**
        * [超过最大字数限制回调]
         */
        void onMaxCharCountCall(int limitCharCount, int currentCharCount);
    }
}

使用:

LimitedInputLayout方案

package com.bg.ui;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;

public class LimitedInputLayout extends LinearLayout {

    private EditText editText;
    private TextView tvCharCount;
    private int maxCharCount = 30; // 默认最大字数

    public LimitedInputLayout(Context context) {
        super(context);
        init(context);
    }

    public LimitedInputLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
        // TODO: 解析自定义属性,如 maxChars、hint 等(可后续扩展)
    }

    public LimitedInputLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        // 加载包含 EditText + TextView 的布局
        LayoutInflater.from(context).inflate(R.layout.limited_input_layout, this, true);

        // 假设布局中 EditText id = editText,TextView id = tvCharCount
        editText = findViewById(R.id.editText);
        tvCharCount = findViewById(R.id.tvCharCount);

        // 设置初始最大字数限制
        setMaxChars(maxCharCount);

        // 设置输入监听(限制字数、实时统计、截断逻辑)
        setupTextWatcher();
    }

    private void setupTextWatcher() {
        editText.addTextChangedListener(new SimpleTextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

            @Override
            public void afterTextChanged(Editable s) {
                int currentLength = s.length();
                updateCharCountDisplay(currentLength);

                if (currentLength > maxCharCount) {
                    String limited = s.subSequence(0, maxCharCount).toString();
                    editText.setText(limited);
                    editText.setSelection(maxCharCount);
                    updateCharCountDisplay(maxCharCount);
                }
            }
        });
    }

    /**
     * ✅ 动态设置最大字数限制
     */
    public void setMaxChars(int max) {
        if (max <= 0) throw new IllegalArgumentException("最大字数必须 > 0");
        this.maxCharCount = max;

        Editable currentText = editText.getText();
        int currentLength = currentText != null ? currentText.length() : 0;

        if (currentLength > max) {
            String trimmed = currentText.subSequence(0, max).toString();
            editText.setText(trimmed);
            editText.setSelection(max);
        }

        updateCharCountDisplay(Math.min(currentLength, max));
    }

    /**
     * ✅ 动态设置输入框提示文案
     */
    public void setHint(String hintText) {
        if (editText != null) {
            editText.setHint(hintText);
        }
    }

    /**
     * 获取当前输入内容
     */
    public String getCurrentText() {
        return editText != null ? editText.getText().toString() : "";
    }

    private void updateCharCountDisplay(int current) {
        if (tvCharCount != null) {
            tvCharCount.setText(current + "/" + maxCharCount);
            int color = (current > maxCharCount) ? Color.RED : Color.GRAY;
            tvCharCount.setTextColor(color);
        }
    }

    // 简化版 TextWatcher,只保留需要的方法
    private abstract class SimpleTextWatcher implements android.text.TextWatcher {
        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
        @Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
        @Override public void afterTextChanged(Editable s) {}
    }
}

布局文件示例:res/layout/limited_input_layout.xml

<!-- res/layout/limited_input_layout.xml -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入内容"
        android:inputType="text" />

    <TextView
        android:id="@+id/tvCharCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:text="0/30"
        android:textColor="#666666"
        android:textSize="12sp" />

</merge>

注意:使用 <merge>可以避免多余层级。

使用示例(在 Activity/Fragment 中)

LimitedInputLayout limitedInputLayout = findViewById(R.id.limitedInputLayout);

//  动态设置最大字数为 50
limitedInputLayout.setMaxChars(50);

//  动态设置输入框提示为 "请输入新内容"
limitedInputLayout.setHint("新提示文案");

// 获取输入内容
String content = limitedInputLayout.getCurrentText();

小结:

功能

是否实现 

封装 EditText + 字数统计 TextView 为一个自定义控件

支持动态设置最大字数:setMaxChars(50)

支持动态设置输入框提示:setHint("新提示文案")

自动限制输入、实时统计、超限截断

内部维护UI状态同步(如字数颜色)

可在XML或代码中灵活使用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值