自定义View之入门(一)

我们知道在android的世界各种优美而又炫酷控件和动画精彩纷呈,这个得益于大Google将android开源,市场上android智能手机也是大方色彩,不仅有华为、联想、三星、小米,魅族还有现在异军突起的vivo、oppo,他们基于android系统定制属于自己的系统,这使得android在不到十年的时间疯狂掠夺手机市场份额,预计未来andriod智能手机仍然占领智能手机主要市场,android系统的快速普及使得Google对Android系统变革步伐加快,拿几年前和现在的android手机对比使用,不难发现老版本的android手机真是卡到家了,这是Google被吐槽最多的缺憾,而如今的android已经在很多方面都进行过几次优化,例如2012年的黄油计划,以及针对4.4版本对电池性能的优化,Android Runtim虚拟机,Material Design风格,运行时权限,以及针对未来智能设备的Android Go系统!!!

纳闷,说了那么多,好像跟本节要讲的内容有毛线干系,,,(不假思索 ) 好像是耶,说了那么多把android几次改变捋一下下而已,那我们就此入题吧....  (废话那么多!!!---抱怨         大虾,见谅,见谅)

自定义控件是每个android工程师成长的必经之路,狭路相逢勇者胜,看到自定义控件不要怕,抽出神刀果断亮剑,多次交锋下来,你会发现你越来越厉害了,自定义View需要练习,现在的我也经常看相关的内容,时间长了不用不写就忘了,跟大家目前一块学习自定义View,请大虾以后多多关照....


自定义一般分为三种,难易程度由易到难,首先难度系数较低的是自定义扩展控件,就是对已有控件进行再次封装,以满足自己特殊“癖好”,接着就是自定义组合控件,这个有的时候还是比较容易,有的需要多动动脑筋,那么高潮来了,最难的就是完全自定义View,我们通过直接继承View/ViewGroup(其实也是继承View),对控件进行完全自定义,那么今天我们一块分享难度系数比较低的自定义组合控件吧,后面跟大家在分享一些对已有控件进行拓展,以及最后一起学习和探讨姿势高难度的完全自定义View.

假设一个应用场景,我们需要一个控件,这个控件能够输入内容并且根据接口校验输入数据正确与否,并对结果不同提示也不同,大家有时候会用到的输入校验框,不说话上图

输入状态
校验状态
1不可用状态 2检验状态
2 检验成功状态



整个过程如上图,接下来我们一点一点分析:

首先自定义一个控件继承自RelativeLayout,然后自定义属性,在values目录下创建attrs资源文件,自定义属性根节点为

定义的属性如下,如图:

自定义属性

我们来看一下比较重要的属性,

input_hintText:提示文字,跟EditText属性hint一样

input_hintColor:提示文字颜色

inputType:输入内容类型

input_state:枚举输入状态

接着看如何自定义控件:

接触过自定义控件的同学都知道,构造函数有多个重载,

public WmsInputView(Context context) {    super(context);    this.context = context;    init(null, 0);}

public WmsInputView(Context context, AttributeSet attrs) {    super(context, attrs);    this.context = context;    init(attrs, 0);}

public WmsInputView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);  this.context = context;    init(attrs, defStyle);}

第一个构造是在代码中直接创建而调用,第二个以及第三个是在布局文件中创建调用,这里分attrs是我们在布局文件中定义的属性集,后面我们要从这个属性集里面取出属性,defStyleAttr是定义在theme中的一个引用,这个引用指向一个style资源,而这个style资源包含了一些TypedArray的默认值,一般我们默认就行。

注意,我们分别在三个构造函数中init()来初始化属性,

private void init(AttributeSet attrs, int defStyle) {

LayoutInflater.from(context).inflate(R.layout.layout_wms_input_view, this, true);

rlInputView = (RelativeLayout) findViewById(R.id.rl_input);

iconInner = (ImageView) findViewById(R.id.icon_checked_inner);

progressBar = (ProgressBar) findViewById(R.id.progress_bar);

edtInput = (EditText) findViewById(R.id.et_input);    // Load attributes

final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WmsInputView, defStyle, 0);

inputState = a.getInt(R.styleable.WmsInputView_input_state, STATE_INPUT);

hintText = a.getString(R.styleable.WmsInputView_input_hintText);

hintColor = a.getColor(R.styleable.WmsInputView_input_hintColor, hintColor);

inputColor = a.getColor(R.styleable.WmsInputView_inputColor, getResources().getColor(R.color.home_header_check_store));

inputSize = a.getDimensionPixelSize(R.styleable.WmsInputView_inputSize, inputSize);

inputType = a.getInteger(R.styleable.WmsInputView_android_inputType, InputType.TYPE_CLASS_TEXT);

maxLength = a.getInt(R.styleable.WmsInputView_android_maxLength, maxLength);

maxLines = a.getInt(R.styleable.WmsInputView_android_maxLines, maxLines);

inputText = a.getString(R.styleable.WmsInputView_android_text);

a.recycle();

initViews();

}

这里我们在布局文件写了一个该控件的布局,该控件是由textView,EditText,ProgressBar和imageView组成,然后通过布局加载器加载该布局,

LayoutInflater.from(context).inflate(R.layout.layout_wms_input_view, this, true);

然后我们将布局里面定义的属性通过getContext().obtainStyledAttributes()拿到TypedArray,再从这个属性集中拿出对应的属性。

记得后面要recycler一下,那为什么呢??

仁兄注意:使用recycle过后,是将我们之前创建的attrs属性进行回收等待下一次复用,这样,每次引用到我们自定义View的组件重新创建的时候,我们的自定义属性就不会重新的重建,GC就不用频繁的操作这个对象,防止了OOM的出现。

接着把我们自定义控件xml文件中对应属性值设置个控件中各个组件进行初始化,这里强行贴图,这样大家必须要动手操作了,咻咻~~~(动作要快,姿势要对)

这里我们进行简单分析内容,大家看到很多-1,到底是啥,我们再开始对变量进行了初始化是设置了默认值,当我们再xml文件中没有设置对应的属性时候,我们get的值就是这个默认值,要回举一反三哦,

inputFilters.add(new InputFilter.LengthFilter(maxLength));

edtInput.setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));

这里的InputFilter是过滤器,我们对EditText要多输入框进行长度控制时就需要创建这个LengthFilter过滤器,当然过滤器有很多,这里就不一一列举,



最后,我们对editText设置了键盘输入监听器(OnEditorActionListener),也就当我们按下确认的时候会进行回调,我们再回调中对输入的内容进行校验,所以这个监听很重要,想要对这个监听器了解更多的可以自行搜索,“多动动手哦,老司机都是撸出来的,,,,”(咻咻~~)

重点来了,墙裂敲黑板!!!

switchState(inputState);

这又是什么鬼??? 还记得·····那年大明湖畔~~~

oh myGod  串词了, 事情的经过是这样的,,, 还记得前面几张图片吗?

我们的控件有很多种状态,正常输入状态,不能输入状态,加载状态,和加载完成以及加载错误状态,没错,就是这个方法“惹的祸”,那我接下来就来“一一拷问”它究竟是如何作案的,肯定也没那么神奇,毕竟我们都猜到结局~~

立刻上码,扬鞭奔腾起来,当我们设置STATE_INPUT状态时都有哪些操作,我只分析一种情况后面的大家应该都能理解,首先我们对控件的背景颜色进行设置,例如控件是输入状态时背景设置成蓝色的,这个rlInputView是啥呢?


原来是个布局呀,也就是我们整个控件的外面的布局,

当控件状态是STATE_INPUT时,我们把其他验证成功和进度都设置为GONE,输入框通过postDelayed发送一个延时操作获取焦点,

edtInput.postDelayed(new Runnable() {

@Override

public void run() {

edtInput.requestFocus();

}}, 200);

接下来的状态设置跟这个差别不是很大,就是对布局种各组件进行状态设置,隐藏还是显示,颜色和背景以及字体等等的设置,大家细看就会的,

不过我们再设置状态为STATE_ERROR时候用到了高亮和全选,

void setErrorText(String errorText) {

if (TextUtils.isEmpty(errorText)) {

return;

}

edtInput.setTextColor(ContextCompat.getColor(context, R.color.text_error));

edtInput.selectAll();

edtInput.setHighlightColor(context.getResources().getColor(R.color.bg_text_error));}

这个作用时给用户一个显眼的提示,并且自动全选后可以点删除键一键全删,用户体验还是很好的,还是看图吧,

是不是看起来还不错呢,当你删除的时候就可以全部删掉,不用再长按选择全选或者不停的“抖手”,当然,我们这样在布局里面吧所有属性写死是不是感觉扩展性太差,我们对外也暴露了一些方法用来修改控件状态和属性值,

public void setText(String text) {

edtInput.setText(TextUtils.isEmpty(text) ? "" : text);

edtInput.setSelection(text.length());}/** * 获取输入文本 * * @return */

public String getInputText() {

return edtInput.getText().toString().trim();}/** * 获取输入控件 * @return */

public EditText getEditInputView() {

if (edtInput != null) return edtInput;

return null;

}

public interface OnCompleteListener {

void onComplete(String inputText);

}

看到这里我们控件基本说完了,是不是感觉没那么复杂吧,“真相”终究会大告天下,讲解的过程中我只是将一些重要的地方拿出来说了一下,当然还有其他地方没有说明,如果你还有点疑惑就看看代码吧,我会把代码放到github上去,本人是个github新人,分析的过程有的地方并不完美,希望大虾谅解,如有疑问和意见欢迎指正和提出,让我们再进阶的道路上一块进步,一起提高~~

github地址:github.com/Scus5761/-View-

祝大家周末愉快!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容