├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── FJEditTextCountLib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── fj │ │ └── edittextcount │ │ └── lib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── fj │ │ │ └── edittextcount │ │ │ └── lib │ │ │ └── FJEditTextCount.java │ └── res │ │ ├── layout │ │ └── fj_edittext_count.xml │ │ └── values │ │ ├── attrs.xml │ │ └── strings.xml │ └── test │ └── java │ └── fj │ └── edittextcount │ └── lib │ └── ExampleUnitTest.java ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── fj │ │ └── edittextcount │ │ └── test │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── fj │ │ │ └── edittextcount │ │ │ └── test │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── fj │ └── edittextcount │ └── test │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FJEditTextCountLib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /FJEditTextCountLib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 27 | exclude group: 'com.android.support', module: 'support-annotations' 28 | }) 29 | compile 'com.android.support:appcompat-v7:25.0.1' 30 | testCompile 'junit:junit:4.12' 31 | } 32 | -------------------------------------------------------------------------------- /FJEditTextCountLib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\android_studio\android_studio\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/androidTest/java/fj/edittextcount/lib/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package fj.edittextcount.lib; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("fj.edittextcount.lib.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/main/java/fj/edittextcount/lib/FJEditTextCount.java: -------------------------------------------------------------------------------- 1 | package fj.edittextcount.lib; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Color; 6 | import android.text.Editable; 7 | import android.text.InputFilter; 8 | import android.text.TextWatcher; 9 | import android.util.AttributeSet; 10 | import android.util.TypedValue; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.widget.EditText; 14 | import android.widget.RelativeLayout; 15 | import android.widget.TextView; 16 | 17 | /** 18 | * ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 19 | * ┃ ╭﹉﹊﹉╮ ╔═════╗╔═════╗╔═════╗┃ 20 | * ┃╭╯老斯基㊣╠╣淡漠de人生╠╣2016-10-09╠╣ 欢迎关注 ╣┃ 21 | * ┃╰⊙┈┈┈⊙╯╚◎═══◎╝╚◎═══◎╝╚◎═══◎╝┃ 22 | * ┣━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┫ 23 | * ┃GitHub┃https://github.com/FJ917 ┃ 24 | * ┃简 书┃http://www.jianshu.com/users/3d2770e6e489 ┃ 25 | * ┃Q Q┃511334686 ┃ 26 | * ┗━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ 27 | */ 28 | 29 | public class FJEditTextCount extends RelativeLayout { 30 | 31 | //类型1(单数类型):TextView显示总字数,然后根据输入递减.例:100,99,98 32 | //类型2(百分比类型):TextView显示总字数和当前输入的字数,例:0/100,1/100,2/100 33 | public static final String SINGULAR = "Singular";//类型1(单数类型) 34 | public static final String PERCENTAGE = "Percentage";//类型2(百分比类型) 35 | private EditText etContent;//文本框 36 | private TextView tvNum;//字数显示TextView 37 | private View vLineUp;//底部横线 38 | private View vLineDn;//底部横线 39 | private String TYPES = SINGULAR;//类型 40 | private int MaxNum = 100;//最大字符 41 | private String hint = "请输入内容";//提示文字 42 | private int MinHeight = 100;//最小高度 43 | private int LineColor = Color.BLACK;//横线颜色 44 | private int TextColor = Color.BLACK;//输入文字颜色 45 | private String text = "";//默认文字 46 | 47 | public FJEditTextCount(Context context) { 48 | this(context, null); 49 | } 50 | 51 | public FJEditTextCount(Context context, AttributeSet attrs) { 52 | super(context, attrs); 53 | LayoutInflater.from(context).inflate(R.layout.fj_edittext_count, this, true); 54 | etContent = (EditText) findViewById(R.id.etContent); 55 | tvNum = (TextView) findViewById(R.id.tvNum); 56 | vLineUp = findViewById(R.id.vLineUp); 57 | vLineDn = findViewById(R.id.vLineDn); 58 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FJEditTextCount); 59 | if (typedArray != null) { 60 | //默认文字 61 | text = typedArray.getString(R.styleable.FJEditTextCount_etText); 62 | etContent.setText(text); 63 | etContent.setSelection(etContent.getText().length()); 64 | //提示文字 65 | hint = typedArray.getString(R.styleable.FJEditTextCount_etHint); 66 | etContent.setHint(hint); 67 | //提示文字颜色 68 | etContent.setHintTextColor(typedArray.getColor(R.styleable.FJEditTextCount_etHintColor, Color.rgb(155,155,155))); 69 | //最小高度 70 | etContent.setMinHeight(px2dip(context, 71 | typedArray.getDimensionPixelOffset(R.styleable.FJEditTextCount_etMinHeight,200))); 72 | //最大字符 73 | MaxNum = typedArray.getInt(R.styleable.FJEditTextCount_etMaxLength, 100); 74 | //横线颜色 75 | LineColor = typedArray.getColor(R.styleable.FJEditTextCount_etLineColor, Color.BLACK); 76 | vLineDn.setBackgroundColor(LineColor); 77 | vLineUp.setBackgroundColor(LineColor); 78 | //输入文字大小 79 | etContent.setTextSize(px2sp(context, 80 | typedArray.getDimensionPixelOffset(R.styleable.FJEditTextCount_etTextSize,16))); 81 | //输入文字颜色 82 | TextColor = typedArray.getColor(R.styleable.FJEditTextCount_etTextColor, Color.BLACK); 83 | etContent.setTextColor(TextColor); 84 | //设置提示统计文字大小 85 | tvNum.setTextSize(px2sp(context, 86 | typedArray.getDimensionPixelSize(R.styleable.FJEditTextCount_etPromptTextSize,12))); 87 | //设置提示统计文字颜色 88 | tvNum.setTextColor(typedArray.getColor(R.styleable.FJEditTextCount_etPromptTextColor, Color.BLACK)); 89 | //设置提示统计显示类型 90 | int t = typedArray.getInt(R.styleable.FJEditTextCount_etType,0); 91 | if(t == 0)TYPES = SINGULAR; 92 | else TYPES = PERCENTAGE; 93 | if(TYPES.equals(SINGULAR)){//类型1 94 | tvNum.setText(String.valueOf(MaxNum)); 95 | }else if(TYPES.equals(PERCENTAGE)){//类型2 96 | tvNum.setText(0+"/"+MaxNum); 97 | } 98 | //设置提示位置 99 | int promptPosition = typedArray.getInt(R.styleable.FJEditTextCount_etPromptPosition,0); 100 | if(promptPosition == 0){//上方 101 | vLineDn.setVisibility(View.VISIBLE); 102 | vLineUp.setVisibility(View.GONE); 103 | }else{//下方 104 | vLineUp.setVisibility(View.VISIBLE); 105 | vLineDn.setVisibility(View.GONE); 106 | } 107 | typedArray.recycle(); 108 | } 109 | //设置长度 110 | etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(MaxNum)}); 111 | //监听输入 112 | etContent.addTextChangedListener(mTextWatcher); 113 | setLeftCount(); 114 | } 115 | 116 | private int px2sp(Context context, float pxValue) { 117 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 118 | return (int) (pxValue / fontScale + 0.5f); 119 | } 120 | private static int px2dip(Context context, float pxValue) { 121 | final float scale = context.getResources().getDisplayMetrics().density; 122 | return (int) (pxValue / scale + 0.5f); 123 | } 124 | 125 | /** 126 | * 设置显示 127 | * @return 128 | */ 129 | @Deprecated 130 | public FJEditTextCount show(){ 131 | if(TYPES.equals(SINGULAR)){//类型1 132 | tvNum.setText(String.valueOf(MaxNum)); 133 | }else if(TYPES.equals(PERCENTAGE)){//类型2 134 | tvNum.setText(0+"/"+MaxNum); 135 | } 136 | //设置长度 137 | etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(MaxNum)}); 138 | //监听输入 139 | etContent.addTextChangedListener(mTextWatcher); 140 | return this; 141 | } 142 | 143 | /** 144 | * 设置横线颜色 145 | * @param color --颜色值 146 | * @return 147 | */ 148 | @Deprecated 149 | public FJEditTextCount setLineColor(String color){ 150 | vLineUp.setBackgroundColor(Color.parseColor(color)); 151 | vLineDn.setBackgroundColor(Color.parseColor(color)); 152 | return this; 153 | } 154 | 155 | /** 156 | * 157 | * 设置类型 158 | * @param type --类型 159 | * @return 160 | */ 161 | @Deprecated 162 | public FJEditTextCount setType(String type){ 163 | TYPES = type; 164 | return this; 165 | } 166 | 167 | /** 168 | * 设置最大字数 169 | * @param num --字数 170 | * @return 171 | */ 172 | @Deprecated 173 | public FJEditTextCount setLength(int num){ 174 | this.MaxNum = num; 175 | return this; 176 | } 177 | 178 | /** 179 | * 设置文本框的Hint 180 | * @param str --设置内容 181 | * @return 182 | */ 183 | @Deprecated 184 | public FJEditTextCount setEtHint(String str){ 185 | etContent.setHint(str); 186 | return this; 187 | } 188 | 189 | /** 190 | * 设置文本框的最小高度 191 | * @param px --最小高度(单位px) 192 | * @return 193 | */ 194 | @Deprecated 195 | public FJEditTextCount setEtMinHeight(int px){ 196 | etContent.setMinHeight(px); 197 | return this; 198 | } 199 | 200 | /** 201 | * 获取输入内容 202 | * @return 内容 203 | */ 204 | public String getText(){ 205 | return etContent.getText().toString(); 206 | } 207 | 208 | /** 209 | * 设置默认内容 210 | * @param str --内容 211 | */ 212 | public void setText(String str){ 213 | etContent.setText(str); 214 | etContent.setSelection(etContent.getText().length()); 215 | } 216 | 217 | private TextWatcher mTextWatcher = new TextWatcher() { 218 | private int editStart; 219 | private int editEnd; 220 | public void afterTextChanged(Editable s) { 221 | editStart = etContent.getSelectionStart(); 222 | editEnd = etContent.getSelectionEnd(); 223 | // 先去掉监听器,否则会出现栈溢出 224 | etContent.removeTextChangedListener(mTextWatcher); 225 | // 注意这里只能每次都对整个EditText的内容求长度,不能对删除的单个字符求长度 226 | // 因为是中英文混合,单个字符而言,calculateLength函数都会返回1 227 | while (calculateLength(s.toString()) > MaxNum) { // 当输入字符个数超过限制的大小时,进行截断操作 228 | s.delete(editStart - 1, editEnd); 229 | editStart--; 230 | editEnd--; 231 | } 232 | // 恢复监听器 233 | etContent.addTextChangedListener(mTextWatcher); 234 | setLeftCount(); 235 | } 236 | 237 | public void beforeTextChanged(CharSequence s, int start, int count,int after) {} 238 | 239 | public void onTextChanged(CharSequence s, int start, int before,int count) {} 240 | }; 241 | 242 | /** 刷新剩余输入字数 */ 243 | private void setLeftCount() { 244 | if(TYPES.equals(SINGULAR)){//类型1 245 | tvNum.setText(String.valueOf((MaxNum - getInputCount()))); 246 | }else if(TYPES.equals(PERCENTAGE)){//类型2 247 | tvNum.setText(MaxNum-(MaxNum - getInputCount())+"/"+MaxNum); 248 | } 249 | 250 | } 251 | 252 | /** 获取用户输入内容字数 */ 253 | private long getInputCount() { 254 | return calculateLength(etContent.getText().toString()); 255 | } 256 | /** 257 | * 计算分享内容的字数,一个汉字=两个英文字母,一个中文标点=两个英文标点 258 | * 注意:该函数的不适用于对单个字符进行计算,因为单个字符四舍五入后都是1 259 | * @param cs 260 | * @return 261 | */ 262 | public static long calculateLength(CharSequence cs) { 263 | double len = 0; 264 | for (int i = 0; i < cs.length(); i++) { 265 | int tmp = (int) cs.charAt(i); 266 | if (tmp > 0 && tmp < 127) { 267 | len += 1; 268 | } else { 269 | len++; 270 | } 271 | } 272 | return Math.round(len); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/main/res/layout/fj_edittext_count.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 23 | 24 | 30 | 31 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FJEditTextCountLib 3 | 4 | -------------------------------------------------------------------------------- /FJEditTextCountLib/src/test/java/fj/edittextcount/lib/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package fj.edittextcount.lib; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | > ### 栗子——自定义EditText实现右下角计数控件 3 | 4 | --- 5 | 6 | ![栗子配图.png](http://upload-images.jianshu.io/upload_images/2071764-8d148e73b77178de.png) 7 | 8 | --- 9 | 10 | > ### 栗子惯例,先上GIF 11 | 12 | |PERCENTAGE百分比效果|SINGULAR单数效果| 13 | |:-------------:|:-------------:| 14 | |![百分比类型.gif](http://upload-images.jianshu.io/upload_images/2071764-9050fc9e607002a4.gif)|![单数类型.gif](http://upload-images.jianshu.io/upload_images/2071764-085344ba61616d59.gif)| 15 | 16 | 17 | 18 | > ### 使用姿势 19 | 20 | #### 1.引用 21 | 22 | ``` 23 | allprojects { 24 | repositories { 25 | ... 26 | maven { url 'https://jitpack.io' } 27 | } 28 | } 29 | dependencies { 30 | compile 'com.github.FJ917:FJEditTextCount:版本号' 31 | //compile 'com.github.FJ917:FJEditTextCount:v1.0.1' 32 | } 33 | ``` 34 | 35 | #### 2.使用 36 | 37 | ##### 支持参数&方法汇总 38 | 39 | |参数|说明| 40 | |---|---| 41 | |etText|xml参数,设置默认文字| 42 | |etTextSize|xml参数,输入文字大小| 43 | |etTextColor|xml参数,输入文字颜色| 44 | |etPromptTextSize|xml参数,提示统计文字大小| 45 | |etPromptTextColor|xml参数,提示统计文字颜色| 46 | |etHintColor|xml参数,提示文字颜色| 47 | |etHint|xml参数,设置提示文字| 48 | |etMinHeight|xml参数,设置最小高度| 49 | |etMaxLength|xml参数,设置最大长度(总字数)| 50 | |etType|xml参数,设置提示统计显示类型(单数singular;百分percentage)| 51 | |etLineColor|xml参数,设置横线颜色| 52 | |getText()|java方法,获取输入的文字| 53 | |setText|java方法,设置默认文字| 54 | |show()|v1.0.3(含)版本后不需要设置| 55 | |etPromptPosition|xml参数,设置提示统计显示类型位置(promptUp上方;下方promptDn)| 56 | 57 | --- 58 | 59 | ##### v1.0.4版本 60 | 61 | 新增设置提示统计显示类型位置在横线上方或者横线下方 62 | 63 | --- 64 | 65 | ##### v1.0.3版本 66 | 67 | 这个版本有较大的改动,一些以往在java中设置的参数,移到了xml中进行设置,但是保留了java中设置的方法,但是不建议使用! 68 | 69 | **变动的参数** 70 | 71 | |变动前(java中的方法)|变动后(xml参数)|参数说明| 72 | |---------|---------|---------| 73 | |setEtHint()|etHint|设置提示文字| 74 | |setEtMinHeight()|etMinHeight|设置最小高度| 75 | |setLength()|etMaxLength|设置最大长度(总字数)| 76 | |setType()|etType|设置提示统计显示类型(单数singular;百分percentage)| 77 | |setLineColor()|etLineColor|设置横线颜色| 78 | |show()|无|属性移到xml不需要设置| 79 | |getText()|保留|获取输入的文字| 80 | 81 | **xml新增参数** 82 | 83 | |参数|说明| 84 | |---|---| 85 | |etText|xml参数,设置默认文字| 86 | |etTextSize|xml参数,输入文字大小| 87 | |etTextColor|xml参数,输入文字颜色| 88 | |etPromptTextSize|xml参数,提示统计文字大小| 89 | |etPromptTextColor|xml参数,提示统计文字颜色| 90 | |etHintColor|xml参数,提示文字颜色| 91 | |setText|java方法,设置默认文字| 92 | 93 | 94 | ###### xml示例 95 | 96 | ``` 97 | 111 | ``` 112 | 113 | --- 114 | 115 | ##### v1.0.2版本 116 | 117 | 使用方法和v1.0.1一致 118 | 新增获取输入内容的方法:` fjEdit.getText();` 119 | 120 | --- 121 | 122 | ##### v1.0.1版本 123 | 124 | 初次提交,实现基本功能~ 125 | 126 | ###### xml 127 | 128 | ``` 129 | 133 | ``` 134 | 135 | ###### java 136 | 137 | ``` 138 | fjEdit = (FJEditTextCount) findViewById(R.id.fjEdit); 139 | fjEdit.setEtHint("内容")//设置提示文字 140 | .setEtMinHeight(200)//设置最小高度,单位px 141 | .setLength(50)//设置总字数 142 | //TextView显示类型(SINGULAR单数类型)(PERCENTAGE百分比类型) 143 | .setType(FJEditTextCount.SINGULAR) 144 | .setLineColor("#3F51B5")//设置横线颜色 145 | .show(); 146 | ``` 147 | 148 | --- 149 | 150 | > ### 实现原理 151 | 152 | 首先通过`LayoutInflater.from`获取到layout,然后`findViewById`拿到里面的控件,这里用了三个控件`EditText,TextView,View`,View是最下面的横线 153 | 154 | ``` 155 | LayoutInflater.from(context).inflate(R.layout.anfq_num_edittext, this, true); 156 | etContent = (EditText) findViewById(R.id.etContent); 157 | tvNum = (TextView) findViewById(R.id.tvNum); 158 | vLine = findViewById(R.id.vLine); 159 | ``` 160 | 161 | 然后提供一些设置值的方法,如右下角的类型(这里有两种类型,即:单数类型和百分比类型)、最大字符的长度、EditText的Hint、横线的颜色。 162 | 163 | 设置`EditText`的监听TextWatcher(这里是参考了网上的一些代码,具体链接找不到了) 164 | 165 | ``` 166 | public void afterTextChanged(Editable s) { 167 | editStart = etContent.getSelectionStart(); 168 | editEnd = etContent.getSelectionEnd(); 169 | // 先去掉监听器,否则会出现栈溢出 170 | etContent.removeTextChangedListener(mTextWatcher); 171 | // 注意这里只能每次都对整个EditText的内容求长度,不能对删除的单个字符求长度 172 | // 因为是中英文混合,单个字符而言,calculateLength函数都会返回1 173 | 174 | // 当输入字符个数超过限制的大小时,进行截断操作 175 | while (calculateLength(s.toString()) > MaxNum) { 176 | s.delete(editStart - 1, editEnd); 177 | editStart--; 178 | editEnd--; 179 | } 180 | // 恢复监听器 181 | etContent.addTextChangedListener(mTextWatcher); 182 | setLeftCount(); 183 | } 184 | 185 | /** 刷新剩余输入字数 */ 186 | private void setLeftCount() { 187 | if(TYPES.equals(SINGULAR)){//类型1 188 | tvNum.setText(String.valueOf((MaxNum - getInputCount()))); 189 | }else if(TYPES.equals(PERCENTAGE)){//类型2 190 | tvNum.setText(MaxNum-(MaxNum - getInputCount())+"/"+MaxNum); 191 | } 192 | } 193 | /** 获取用户输入内容字数 */ 194 | private long getInputCount() { 195 | return calculateLength(etContent.getText().toString()); 196 | } 197 | /** 198 | * 计算分享内容的字数,一个汉字=两个英文字母,一个中文标点=两个英文标点 199 | * 注意:该函数的不适用于对单个字符进行计算,因为单个字符四舍五入后都是1 200 | * @param cs 201 | * @return 202 | */ 203 | public static long calculateLength(CharSequence cs) { 204 | double len = 0; 205 | for (int i = 0; i < cs.length(); i++) { 206 | int tmp = (int) cs.charAt(i); 207 | if (tmp > 0 && tmp < 127) { 208 | len += 1; 209 | } else { 210 | len++; 211 | } 212 | } 213 | return Math.round(len); 214 | } 215 | } 216 | ``` 217 | 218 | > ### 总结 219 | > 这种EditText显示输入字数的控件在开发中经常用到,但是如果在多个地方用到的话都要做监听代码重复太多,所以做了一下封装,以便以后使用 220 | 221 | --- 222 | 223 | 224 | > **个人博客:[WWW.FJ917.COM](http://www.fj917.com)**
225 | > **简书:[www.jianshu.com/u/3d2770e6e489](http://www.jianshu.com/u/3d2770e6e489)**
226 | > **CSDN:[blog.csdn.net/fj917](http://blog.csdn.net/fj917)** 227 | 228 | 229 | |欢迎加入QQ交流群657206000[点我加入](http://shang.qq.com/wpa/qunwpa?idkey=9b454a6f01bd94d97e4c3f2771447a989ec77794eb5a563422263153c00f700d)| 230 | |:---:| 231 | |![QQ交流群:657206000](http://upload-images.jianshu.io/upload_images/2071764-bce605159bbceb2a.png)| -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "fj.edittextcount.test" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | dependencies { 22 | compile fileTree(include: ['*.jar'], dir: 'libs') 23 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 24 | exclude group: 'com.android.support', module: 'support-annotations' 25 | }) 26 | compile 'com.android.support:appcompat-v7:25.0.1' 27 | testCompile 'junit:junit:4.12' 28 | compile project(':FJEditTextCountLib') 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\android_studio\android_studio\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/fj/edittextcount/test/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package fj.edittextcount.test; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("fj.edittextcount.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/fj/edittextcount/test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package fj.edittextcount.test; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.TextView; 8 | 9 | import fj.edittextcount.lib.FJEditTextCount; 10 | 11 | /** 12 | * ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 13 | * ┃ ╭﹉﹊﹉╮ ╔═════╗╔═════╗╔═════╗┃ 14 | * ┃╭╯老斯基㊣╠╣淡漠de人生╠╣2016-10-09╠╣ 欢迎关注 ╣┃ 15 | * ┃╰⊙┈┈┈⊙╯╚◎═══◎╝╚◎═══◎╝╚◎═══◎╝┃ 16 | * ┣━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┫ 17 | * ┃GitHub┃https://github.com/FJ917 ┃ 18 | * ┃简 书┃http://www.jianshu.com/users/3d2770e6e489 ┃ 19 | * ┃Q Q┃511334686 ┃ 20 | * ┗━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ 21 | */ 22 | public class MainActivity extends AppCompatActivity { 23 | 24 | private FJEditTextCount fjEdit; 25 | private Button btnGetText; 26 | private TextView tvText; 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | fjEdit = (FJEditTextCount) findViewById(R.id.fjEdit); 32 | btnGetText = (Button) findViewById(R.id.btnGetText); 33 | tvText = (TextView) findViewById(R.id.tvText); 34 | // fjEdit.setText("默认输入的文字"); 35 | // fjEdit.setEtHint("内容")//设置提示文字 36 | // .setEtMinHeight(200)//设置最小高度,单位px 37 | // .setLength(50)//设置总字数 38 | // //TextView显示类型(SINGULAR单数类型)(PERCENTAGE百分比类型) 39 | // .setType(FJEditTextCount.SINGULAR) 40 | // .setLineColor("#3F51B5")//设置横线颜色 41 | // .show(); 42 | 43 | btnGetText.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View view) { 46 | tvText.setText(fjEdit.getText());//获取值 47 | } 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 25 | 26 | 32 | 33 |