Android字数限制的EditText实现方案研究

在应用开发中,有时需要实现有字数限制的EditText,首先来分析下市面上存在的类似实现方案吧,好有个感性的认识。

【方案一:腾讯微博】

每个中文字符算一个字数,每两个英文字符算一个字数,当用户输入内容时,实时显示剩余的字数,当超出字数限制时,剩余字数显示为负数,但此时用户仍然可以继续在EditText中输入内容,直到用户点击菜单中的“发送”按钮时,才会弹出对话框或者Toast显示用户输入的字数超标,如下图所示:

 

这个方案实现起来很简单,只需要给EditText设置TextWatcher监听器,然后判断输入的是中文字符还是英文字符,实时更新剩余输入字数显示即可,不需要限制EditText的输入。

【方案二:百度旅游】

中英文字符都算一个字数,当用户输入内容时,实时显示剩余的字数,当超出字数限制时,剩余字数显示为0,不会出现负数的情况,这时EditText再也不接收用户输入的任何内容了。

这个方案由于中英文都占一个字数,因此可以直接给EditText设置InputFilter.LengthFilter,这时LengthFilter会自动帮EditText限制用户输入的内容;再给EditText设置TextWatcher监听器,就可以实时更新剩余字数了。

本文综合上面两个方案,给出【方案三】,每个中文字符算一个字数,每两个英文字符算一个字数,当用户输入内容时,实时显示剩余的字数,当超出字数限制时,剩余字数显示为0,不会出现负数的情况,这时EditText再也不接收用户输入的任何内容了。

方案三可用于app需要集成第三方sns分享功能,且必须自己实现分享界面的情况。由于中英文所占的字数不一样,就不能使用LengthFilter来限制用户再EditText中输入内容(因为在用户完成内容输入之前,是不知道要给lengthFilter设置的最大值的)。因此只能在TextWatcher中做些手脚了。方案三界面如下:

 

整个功能的核心实现都在EditText的TextWatcher监听器里面的afterTextChanged回调函数中。代码如下所示:

  1. package com.hust.demo;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.text.Editable;
  5. import android.text.TextWatcher;
  6. import android.widget.EditText;
  7. import android.widget.TextView;
  8. public class MainActivity extends Activity {
  9. private EditText mEditText = null;
  10. private TextView mTextView = null;
  11. private static final int MAX_COUNT = 140;
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.main);
  16. mEditText = (EditText) findViewById(R.id.content);
  17. mEditText.addTextChangedListener(mTextWatcher);
  18. mEditText.setSelection(mEditText.length()); // 将光标移动最后一个字符后面
  19. mTextView = (TextView) findViewById(R.id.count);
  20. setLeftCount();
  21. }
  22. private TextWatcher mTextWatcher = new TextWatcher() {
  23. private int editStart;
  24. private int editEnd;
  25. public void afterTextChanged(Editable s) {
  26. editStart = mEditText.getSelectionStart();
  27. editEnd = mEditText.getSelectionEnd();
  28. // 先去掉监听器,否则会出现栈溢出
  29. mEditText.removeTextChangedListener(mTextWatcher);
  30. // 注意这里只能每次都对整个EditText的内容求长度,不能对删除的单个字符求长度
  31. // 因为是中英文混合,单个字符而言,calculateLength函数都会返回1
  32. while (calculateLength(s.toString()) > MAX_COUNT) { // 当输入字符个数超过限制的大小时,进行截断操作
  33. s.delete(editStart - 1, editEnd);
  34. editStart--;
  35. editEnd--;
  36. }
  37. // mEditText.setText(s);将这行代码注释掉就不会出现后面所说的输入法在数字界面自动跳转回主界面的问题了,多谢@ainiyidiandian的提醒
  38. mEditText.setSelection(editStart);
  39. // 恢复监听器
  40. mEditText.addTextChangedListener(mTextWatcher);
  41. setLeftCount();
  42. }
  43. public void beforeTextChanged(CharSequence s, int start, int count,
  44. int after) {
  45. }
  46. public void onTextChanged(CharSequence s, int start, int before,
  47. int count) {
  48. }
  49. };
  50. /**
  51. * 计算分享内容的字数,一个汉字=两个英文字母,一个中文标点=两个英文标点 注意:该函数的不适用于对单个字符进行计算,因为单个字符四舍五入后都是1
  52. *
  53. * @param c
  54. * @return
  55. */
  56. private long calculateLength(CharSequence c) {
  57. double len = 0;
  58. for (int i = 0; i < c.length(); i++) {
  59. int tmp = (int) c.charAt(i);
  60. if (tmp > 0 && tmp < 127) {
  61. len += 0.5;
  62. } else {
  63. len++;
  64. }
  65. }
  66. return Math.round(len);
  67. }
  68. /**
  69. * 刷新剩余输入字数,最大值新浪微博是140个字,人人网是200个字
  70. */
  71. private void setLeftCount() {
  72. mTextView.setText(String.valueOf((MAX_COUNT - getInputCount())));
  73. }
  74. /**
  75. * 获取用户输入的分享内容字数
  76. *
  77. * @return
  78. */
  79. private long getInputCount() {
  80. return calculateLength(mEditText.getText().toString());
  81. }
  82. }

但是上面代码存在一个bug,给EditText设置TextWatcher之后,由于afterTextChanged的代码实现会导致输入法界面刷新,从而使得每次输入字符,输入法界面都会跳转到他的主界面去,

例如我们当我们要输入数字时,首先要转到数字输入界面,正常情况下可以连续输入多个数字,数字输入完成后,界面仍然维持在数字输入界面,输入数字1前后界面对比图(正常情况):

 

而给EditText设置我们定义的Textwatcher监听器之后,在数字输入界面,每输入一个数字,输入法都会跳回主界面,需要用户再点击才能回到数字输入界面,如下图所示(引入的bug),也是输入数字1前后界面对比图:

 

如果有哪位知道怎么解决的,欢迎在评论中予以指出。

附:上面代码中对Editable作操作前,必须先将自身的监听器去使能,否则会引起EditText自身的死循环,从而导致堆栈溢出,将函数afterTextChanged中去掉监听器和添加监听器两行代码注释掉,再次运行程序,在输入内容超出字数限制时,如下代码将被执行到:

  1. while (calculateLength(s.toString()) > MAX_COUNT) { // 当输入字符个数超过限制的大小时,进行截断操作
  2. s.delete(editStart - 1, editEnd);
  3. editStart--;
  4. editEnd--;
  5. }

这时Demo出现Crash,异常信息如下:

Demo源码参见:http://download.csdn.net/detail/ace1985/4757626

时间: 2024-08-06 13:49:39

Android字数限制的EditText实现方案研究的相关文章

Android开发中给EditText控件添加TextWatcher监听实现对输入字数的限制

做这个功能是因为开发项目的时候,由于后台接口的一些参数的值的长度有要求,不能超过多少个字符,所以在编辑框中输入的字符是要有限制的. 下面就来看一下demo的实现过程: 首先,在xml控件中放置一个EditText控件,然后初始化该控件并对该控件添加文本监听.xml自己简单的设计一下,代码较为简单,直接上代码: package com.example.edittext; import android.app.Activity; import android.os.Bundle; import an

Android应用程序通用自动脱壳方法研究

Author: @爱博才会赢 本文为乌云峰会上<Android应用程序通用自动脱壳方法研究>的扩展延伸版. 0x00 背景及意义 Android应用程序相比传统PC应用程序更容易被逆向,因为被逆向后能够完整的还原出Java代码或者smali中间语言,两者都具有很丰富的高层语义信息,理解起来更为容易,让程序逻辑轻易暴露给技术能力甚至并不需要很高门槛的攻击者面前.因此Android应用程序加固保护服务随之应运而生.从一开始只有甲方公司提供服务到现在大型互联网公司都有自己的加固保护服务,同时与金钱相

[转载]Android应用程序通用自动脱壳方法研究

本文转载自: http://drops.wooyun.org/tips/9214 Author: @爱博才会赢 本文为乌云峰会上<Android应用程序通用自动脱壳方法研究>的扩展延伸版. 0x00 背景及意义 Android应用程序相比传统PC应用程序更容易被逆向,因为被逆向后能够完整的还原出Java代码或者smali中间语言,两者都具有很丰富的高层语义信息,理解起来更为容易,让程序逻辑轻易暴露给技术能力甚至并不需要很高门槛的攻击者面前.因此Android应用程序加固保护服务随之应运而生.从

前端编程提高之旅(十八)----移动端web流行交互技术方案研究

   在停止实习后,生活最大变化在于没有项目的压力,可以根据兴趣场景,探索技术实现.这个过程对于个人来说,动力自内而外,需求自上而下,都由个人把握.    生活在移动互联网井喷的今天,同时又关注前端技术,平常对微信端流行的交互(或者说玩法)有着特殊的敏感性.如果说之前接触MVC框架还是对单页面网站.CSS3前沿特效有一个概念的话,微信朋友圈及好友分享网页,则把国内网页构建的流行趋势,从幕后推向前台.    乐帝通过研究移动端web流行交互,构建起了一个初步可行的技术方案,用来实现单页面与DOM动

Android给TextView和EditText等控件设置透明背景、圆角边框

第一种方法:在drawable文件夹下新建一个文件设置背景样式 代码: 在drawable文件夹下面新建textviewborder.xml <?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#80858

android 中如何限制 EditText 最大输入字符数

方法一: 在 xml 文件中设置文本编辑框属性作字符数限制 如:android:maxLength="10" 即限制最大输入字符个数为10 方法二: 在代码中使用InputFilter 进行过滤 //editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)}); 即限定最大输入字符数为20 [java] view plaincopy public class TextEditActivity exten

Android apk动态加载机制的研究(二):资源加载和activity生命周期管理

出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了更好地阅读本文,你需要先阅读Android apk动态加载机制的研究这篇文章,在此文中,博主分析了Android中apk的动态加载机制,并在文章的最后指出需要解决的两个复杂问题:资源的访问和activity生命周期的管理,而本文将会分析这两个复杂问题的解决方法.需要说明的一点是,我们不可能调起任何一个未安装的

Android高清巨图加载方案

1.今天看了鸿洋的<Android高清巨图加载方案>一文,对加载高清巨图时的解决方案有了一定的认识. 思路为: 提供一个设置图片的入口. 重写onTouchEvent,在里面根据用户移动的手势,去更新显示区域的参数. 每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,去draw. 2.除此之外,对安卓的手势事件分发以及手势监听做了进一步学习. 2.1.手势事件分发 详见<Android手势事件分发过程分析

Android实习札记(1)---EditText属性之ImeOption详解

Android实习札记(1)---EditText属性之ImeOption详解 1)这个属性拿来干嘛的? 答:当我们往EditText等可以输入文字的UI控件的地方输入时,弹出的小键盘的 右下角的Enter键!你没听错,这个属性就是关于Enter键的!!! 我们可以通过ImeOption属性来设置enter键显示的内容,以及进行事件监听~ 2)如何修改Enter键显示的内容: 答:直接设置ImeOption属性即可,另外,使用第三方输入法可能出现不同的结果, 或者没变化,这里只以搜狗输入法为参考