组合控件--实现Ip地址的输入与校验
2017-03-29 13:05
756 查看
自定义组合控件实现Ip地址的输入与校验
额,为什么要写这个东西呢,正常市面上的软件真想不到会让用户去输入Ip地址,但是为了准备比赛,看到有Ip地址校验的一道题目,于是说干就干试着模仿着写一个组合控件,实现上述的功能。题目:
上面的题目上的效果看上去还是可以的吧,下面看一下我的版本的运行效果:
偷个懒,没有美化……
下面进入主题,介绍一下实现了那些功能,以及在书写代码的过程中所遇到的问题:
实现的功能:
Ip地址的合法性校验 每一个区段 0-255焦点的自动获取,当每一个区段中的三个数输入完毕后自动跳转到下一个Ip区段
当输入的数据不合法时,会播放左右晃动动画进行提示用户
对于组合控件也算是涉及到自定义View的相关内容了,这里面用于存放EditText的ViewGroup我们继承自 已有的LinearLayout,这样就不需要处理ViewGroup的测量和布局了。
haha,适当的偷懒^_^
实现代码:
/** * 组合控件Ip地址输入框 * @author wangke */ public class IpEditText extends LinearLayout { private EditText mEditText1; private EditText mEditText2; private EditText mEditText3; private EditText mEditText4; 4000 //EditText在父View中对应的下标的位置 private int[] edtIndex = new int[]{0, 2, 4, 6}; public IpEditText(Context context) { super(context); InitUI(); //检查Ip地址的输入是否正确 checkInput(); } public IpEditText(Context context, @Nullable AttributeSet attrs) { super(context, attrs); InitUI(); //检查Ip地址的输入是否正确 checkInput(); } public IpEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); InitUI(); //检查Ip地址的输入是否正确 checkInput(); } /** * 初始化控件布局 */ private void InitUI() { mEditText1 = new EditText(getContext()); mEditText1.setTag(0); mEditText2 = new EditText(getContext()); mEditText2.setTag(1); mEditText3 = new EditText(getContext()); mEditText3.setTag(2); mEditText4 = new EditText(getContext()); mEditText4.setTag(3); TextView tvPoint1 = new TextView(getContext()); tvPoint1.setText("."); tvPoint1.setTextSize(30); TextView tvPoint2 = new TextView(getContext()); tvPoint2.setText("."); tvPoint2.setTextSize(30); TextView tvPoint3 = new TextView(getContext()); tvPoint3.setText("."); tvPoint3.setTextSize(30); addView(mEditText1); //0 addView(tvPoint1); addView(mEditText2); //2 addView(tvPoint2); addView(mEditText3); //4 addView(tvPoint3); addView(mEditText4); //6 //遍历子View设置布局样式 for (int i = 0; i < getChildCount(); i++) { if (getChildAt(i) instanceof EditText) { ((EditText) getChildAt(i)).setGravity(Gravity.CENTER); //设置EditText最大的输入字符数为3 ((EditText) getChildAt(i)).setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)}); LinearLayout.LayoutParams params = (LayoutParams) getChildAt(i).getLayoutParams(); ((EditText) getChildAt(i)).setInputType(InputType.TYPE_CLASS_NUMBER); params.weight = 1; params.width = 0; } } } private int currentFoucsIndex = 0; /** * 检查Ip地址的输入是否正确 */ private void checkInput() { for (int i = 0; i < getChildCount(); i++) { if (getChildAt(i) instanceof EditText) { final EditText edtText = (EditText) getChildAt(i); edtText.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus == true) { int tag = (int) v.getTag(); //记录当前获取焦点的下标 currentFoucsIndex = tag; } } }); /** * EdtText内容发生改变的监听 */ edtText.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) { Log.i("wk", this.toString() + "改变的:" + s + "count:" + count); if (s.length() > 0) { int ipValue = Integer.valueOf(s.toString()); if (ipValue > 255 || ipValue < 0) { Toast.makeText(getContext(), "输入的Ip不合法!", Toast.LENGTH_SHORT).show(); //添加警告动画 addWarnAnim(edtText); } else { //如果输入的长度为3表示当前Ip的区段已经输入完成,将焦点递给下一个EditText if (s.toString().length() == 3) { currentFoucsIndex += 1; if (currentFoucsIndex <= edtIndex.length - 1) { //申请当前正在输入的下一个EditText获取焦点 getChildAt(edtIndex[currentFoucsIndex]).requestFocus(); } } } } else { Toast.makeText(getContext(), "不能为空!", Toast.LENGTH_SHORT).show(); } } @Override public void afterTextChanged(Editable s) { } }); } } } /** * 创建一个用于提醒输入出错的动画效果 * * @param editText */ private void addWarnAnim(EditText editText) { AnimationSet animationSet = new AnimationSet(true); animationSet.setRepeatCount(8); TranslateAnimation rightAnim = new TranslateAnimation(0, 30, 0, 0); rightAnim.setDuration(60); TranslateAnimation leftAnim = new TranslateAnimation(30, 0, 0, 0); rightAnim.setDuration(60); animationSet.addAnimation(rightAnim); animationSet.addAnimation(leftAnim); editText.startAnimation(animationSet); } /** * 判断当前Ip地址的每个区段是否都不为空 * * @return 为空返回true/不为空返回false */ public Boolean isHaveEmpty() { Boolean isHaveEmpty = false; for (int i = 0; i < getChildCount(); i++) { if (getChildAt(i) instanceof EditText) { EditText edt = (EditText) getChildAt(i); if (edt.getText().toString().equals("")) { isHaveEmpty = true; break; } else { isHaveEmpty = false; } } } return isHaveEmpty; } /** * 获取用户当前输入的Ip地址 * * @return */ public String getIpAddress() { StringBuffer sb = new StringBuffer(); for (int i = 0; i < getChildCount(); i++) { if (getChildAt(i) instanceof EditText) { EditText edtText = (EditText) getChildAt(i); sb.append(edtText.getText()); if (i != getChildCount() - 1) { sb.append("."); } } } return sb.toString(); } }
感觉上面的代码没有什么好解释的,注释写的也比较明确。下面记录一下
书写代码时遇到的问题:
AddView时出现的问题,当添加显示“.”的TextView的时候,由于考虑到既然都是一样的那么就new一个好了然后直接添加这一个,想法太天真,于是报出了下面的错误:Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
在网上查了下资料,发现: 当一个View已经作为一个子View添加到父View中了,再次添加到当前的View就会出现上面的错误。
将charsequence直接强转成String,于是就报错了%>_<%
java.lang.ClassCastException: android.text.SpannableStringBuilder cannot be cast to java.lang.String
当返回值为父类,而我需要的值为子类的时候,才能够进行强制转换不出现错误,也就是所说的向下转型,查看了下String类的源码发现String是实现了CharSequence接口。也就是说只要按照向下转型的原则就不会出现上面的错误(╮(╯▽╰)╭,有必要花时间把Java基础再复习一遍了)。
使用editText.requestFocus()来进行焦点的获取
EditText中setFilters的使用方法:
对于限制EditText输入长度,对于在Xml中直接加上android:maxLength="3"属性即可,在代码中进行设置需要通过EditText的setFilters方法。
InputFilter的作用是对输入的字符进行过滤处理,可以实现InputFilter接口进行指定任意的匹配规则。
使用方法:
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)});
setFilters( )的参数是一个InputFilter类型的数组,如果直接添加限制输入字符长度的规则,直接new InputFilter.LengthFilter(3),使用系统提供好的方法。
下面让我们定义一个过滤A-Z之外字符的InputFilter,运行效果:
代码 :
/** * 过滤A-Z以外的字符 */ class MyFilter implements InputFilter{ @Override public CharSequence filter(CharSe bc4a quence source, int start, int end, Spanned dest, int dstart, int dend) { //A-Z ArrayList<Character> filterChar = new ArrayList<>(); for(int i=65;i<=90;i++){ filterChar.add((char) i); } //source 一次从键盘上录入的字符的串的长度 Log.i("wk","输入字符长度:"+source.toString().length()); if(source.length()>1) { //只允许单个字符的输入 return ""; } if(source.length()>0) { if (filterChar.contains(source.charAt(0))) { //如果匹配成功返回null return null; } else{ //匹配失败返回false return ""; } } return null; } }
filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) 方法中的参数含义:
source :当前新输入的字符串
start :当前输入字符串的起始下标,通常为0
end : 当前输入字符串的终点下标,长度为source.length-1
dest : 下一次输前的文本框中的字符内容
dstart : 原内容的起始下标,通常为0
dend : 原内容的终点下标,通常为 dest.length()-1
这样一个简单的组合控件就实现了,还有很多不足,比如Ip地址的区段只有输入三位数才能自动跳转到下一个EditText,当然这个只能用来作为提升自己的小例子,真正在项目中使用的话要考虑到方方面面。写博客的习惯不能丢,虽然目前的文章质量很差,也就当做是用来作为学习笔记来翻看,如果大家看到什么错误的地方,欢迎指出,感激不尽^_^。
相关文章推荐
- Delphi来实现一个IP地址输入控件
- Qt实现的IP地址输入控件
- vue input 输入校验字母数字组合且长度小于30的实现代码
- Delphi版 关于QQ输入控件无法Spy到句柄的实现方案可行性研究
- 用Office VBA实现多控件一次性组合
- IP地址输入控件 V1.0.1.1版(For Win From)
- 用javascript实现的日期时间输入控件
- 通用Delphi数据库输入控件DBPanel的实现
- ASP.NET中DataList控件和AspNetPager控件的组合使用并实现分页
- javascript ip地址 输入控件
- C#通用类实现 读取xml控制Asp.net控件输入信息长度(TextBox,FileUpload)
- 用回车键实现MFC对话框中TAB键控制输入焦点在控件中跳转的效果
- 用javascript实现的日期时间输入控件
- [转]一种通用的输入校验方法和气球泡提示的实现(键盘用户界面模块)
- JavaScript实现的日期输入控件
- 用Office VBA实现多控件一次性组合
- 利用反射实现ASP.NET控件和数据实体之间的双向绑定,并且在客户端自动验证输入的内容是否合法
- 给大家介绍一个日期输入控件javascript实现,我修改了下,符合我的习惯了,^_^!
- 实现按ENTER,TAB可以按程序输入的控件顺序顺序移动
- 用DELPHI、RxRichEdit控件实现类似QQ的表情输入方法