Android梳理不常用widget篇
2016-07-27 16:36
696 查看
闲得蛋疼,折腾折腾android源码包下面widget包下面很少用以及几乎没听说过的控件(针对自己而言,莫要批斗(⊙o⊙)哦丫)。
实现原理
TextClock继承自TextView,扩展自定义属性三个(主要是显示格式相关属性控制)
在onAttachedToWindow和onDetachedFromWindow方法注册了广播和取消注册,监听时间发生变化了,接收到广播,调用onTimeChanged方法更新UI,下面是简要代码块
实现原理
Space控件继承自View,在构造函数直接把控件设置为INVISIBLE模式,修改测量方法onMeasure,取消了draw方法的canvas绘制渲染的处理,下面是测量宽高相关核心代码
如果在以前你喜欢用View控件,setVisiblity占用屏幕空间,建议以后替换成Space控件,好处在于draw方法的重写,具体不解释。
实现原理
ZoomButton内部就一个核心点,设置ZoomSpeed,默认速度值1000,ZoomControl是一个自定义的ViewGroup,布局控件默认inflater预先定义好的布局,如下
如果你想改变着丑陋的UI,你可以尝试拷贝源码出来,修改Inflater的布局即可。这个空间提供的show 、hide方法只是在执行透明动画,关键代码块如下
该类对ZoomSpeed值提供了一个方法setZoomSpeed设置,其他的没什么好关注的,Listener的监听回调也略过吧,就这样吧。(merge没用过的可以去了解一下)
实现原理
AdapterViewFlipper可以实现轮播图片,虽然有点撇脚,不能手动滑动,也无法感知轮播到了那个界面,关于这一点可以重写控件,修改showNext回调位置,至于手动滑动需要手势拦截处理这块怎么说呢,你若有兴趣自己造轮子可以试试。
这里要区别两个类:ViewFlipper和AdapterViewFlipper,这是两个不同的类,下面是他们的继承体系
AdapterViewFlipper的自定义属性在他的父类有定义自己也有定义,下面来看看具体的含义与代码调用方法
下面是对照自定义属性的说明和方法调用
当你使用默认播放动画切换视图感觉不是1秒,不要觉得奇怪,动画执行也需要时间的,默认in 、out 动画时常都是200。对于代码功能性调用来说我们只需要关注下面这几个方法即可
startFlipping开启轮播没啥好说的,该类同样使用了上面提到的注册广播,注册了屏幕关闭和唤醒广播,关闭屏幕就暂停轮播,唤醒时如果之前是轮播状态,那么继续开始轮播。(相关代码块就不贴,自己查看源代码)
StackView虽说也是AdapterViewAnimator子类,但是其实现效果与AdapterViewFlipper不同,具体效果图就不贴了,实在是原生控件在实际得出的效果拿不出手,而且感觉在应用场景上来说也找不到对应的,于是乎在github检索了一会,找到了一个还算不错的开源,下面是地址和效果图:https://github.com/blipinsk/FlippableStackView
他们之间的的关系到底有多深呢,且听我一一道来。最上层ViewGrou抽象下来的Adapter,拥有很多子类,Spinner的具体实现,跟踪源代码发现内部有实例化出一个ListPopuWindow、DialogPopup(根据不同的mode选择不同的实例,本质区别一个是popuwindow一个是AlertDialog),而ListPopuWindow类让我发现了这么个东西DropDownListView 的实例(AlertDialog同样调用了getLitView方法)
由此可以知道每个ListPopuWindow里面有一个LIstView,Spinner弹出来的其实就是ListView绑定适配器,而Spinner内部定义了一个DropDownAdapter,ListView绑定Adapter,最后调用各自mode对应的popu.show就可以了。那么问题来了,Spinner在很么时候弹出ListPopuWindow?带着这个问题继续跟踪Spinner源码
ViewGroup继承自View,所以可以共享父类方法performClick,点击时会调用该方法,自然Spinner也不例外,具体调用代码块如下(当然还有其他地方有触发,这里暂不深入理解了)
用过的人都知道Spinner的Item预定义样式有点丑陋,主要是AbsSpinner搞鬼,下面是预定义的载入代码块(修改Spinner样式可以参考adapter这里的调用)
看完Spinner有了个大概的认知,再看AutoCompleteTextView(他的子类同理略过了),内部同样实例了ListPopuWindow,添加了一个EditText输入内容的监听
如果你对这个方法不陌生应该秒懂了吧,根据输入内容,当输入内容有变化立即执行过滤匹配适配器,这里过滤具体实现暂不涉及。
https://github.com/akbarsha03/Custom_CheckedTextView
1.在onAttachedToWindow和onDetachedFromWindow方法注册广播和取消注册,接收到广播,来做一些回调或者更新UI
2.了解了Spinner AutoCompleteTextView ListView等相关类的相关实现。
TextClock
效果图实现原理
TextClock继承自TextView,扩展自定义属性三个(主要是显示格式相关属性控制)
在onAttachedToWindow和onDetachedFromWindow方法注册了广播和取消注册,监听时间发生变化了,接收到广播,调用onTimeChanged方法更新UI,下面是简要代码块
@Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; registerReceiver(); // .................略.................... } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { unregisterReceiver(); // .................略.................... } } private void registerReceiver() { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null, getHandler()); } private void unregisterReceiver() { getContext().unregisterReceiver(mIntentReceiver); } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { final String timeZone = intent.getStringExtra("time-zone"); createTime(timeZone); } onTimeChanged(); } }; private void onTimeChanged() { mTime.setTimeInMillis(System.currentTimeMillis()); setText(DateFormat.format(mFormat, mTime)); setContentDescription(DateFormat.format(mDescFormat, mTime)); }
Space
效果图实现原理
Space控件继承自View,在构造函数直接把控件设置为INVISIBLE模式,修改测量方法onMeasure,取消了draw方法的canvas绘制渲染的处理,下面是测量宽高相关核心代码
private static int getDefaultSize2(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: result = Math.min(size, specSize); break; case MeasureSpec.EXACTLY: result = specSize; break; } return result; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension( getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec)); }
如果在以前你喜欢用View控件,setVisiblity占用屏幕空间,建议以后替换成Space控件,好处在于draw方法的重写,具体不解释。
ZoomButton 、ZoomControls
效果图实现原理
ZoomButton内部就一个核心点,设置ZoomSpeed,默认速度值1000,ZoomControl是一个自定义的ViewGroup,布局控件默认inflater预先定义好的布局,如下
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <ZoomButton android:id="@+id/zoomOut" android:background="@android:drawable/btn_zoom_down" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ZoomButton android:id="@+id/zoomIn" android:background="@android:drawable/btn_zoom_up" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </merge>
如果你想改变着丑陋的UI,你可以尝试拷贝源码出来,修改Inflater的布局即可。这个空间提供的show 、hide方法只是在执行透明动画,关键代码块如下
public void show() { fade(View.VISIBLE, 0.0f, 1.0f); } public void hide() { fade(View.GONE, 1.0f, 0.0f); } private void fade(int visibility, float startAlpha, float endAlpha) { AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha); anim.setDuration(500); startAnimation(anim); setVisibility(visibility); }
该类对ZoomSpeed值提供了一个方法setZoomSpeed设置,其他的没什么好关注的,Listener的监听回调也略过吧,就这样吧。(merge没用过的可以去了解一下)
AdapterViewAnimator、AdapterViewFlipper、StackView
效果图实现原理
AdapterViewFlipper可以实现轮播图片,虽然有点撇脚,不能手动滑动,也无法感知轮播到了那个界面,关于这一点可以重写控件,修改showNext回调位置,至于手动滑动需要手势拦截处理这块怎么说呢,你若有兴趣自己造轮子可以试试。
这里要区别两个类:ViewFlipper和AdapterViewFlipper,这是两个不同的类,下面是他们的继承体系
AdapterViewFlipper的自定义属性在他的父类有定义自己也有定义,下面来看看具体的含义与代码调用方法
下面是对照自定义属性的说明和方法调用
自定义属性 | 注释 | 对应方法 |
---|---|---|
inAnimation | 组件显示时用的动画 | setInAnimation() |
outAnimation | 组件隐藏时用的动画 | setInAnimation() |
animateFirstView | 组件显示第一个View时是否播放动画 | setAnimateFirstView(),默认播放动画 |
loopViews | 循环到最后一个视图是否回到第一个视图 | AdapterViewFlipper强制设为了true |
flipInterval | 循环播放动画时间间隔 | setFlipInterval()默认1000间隔 |
autoStart | 是否自动播放动画 | setAutoStart() |
startFlipping开启轮播没啥好说的,该类同样使用了上面提到的注册广播,注册了屏幕关闭和唤醒广播,关闭屏幕就暂停轮播,唤醒时如果之前是轮播状态,那么继续开始轮播。(相关代码块就不贴,自己查看源代码)
StackView虽说也是AdapterViewAnimator子类,但是其实现效果与AdapterViewFlipper不同,具体效果图就不贴了,实在是原生控件在实际得出的效果拿不出手,而且感觉在应用场景上来说也找不到对应的,于是乎在github检索了一会,找到了一个还算不错的开源,下面是地址和效果图:https://github.com/blipinsk/FlippableStackView
QuickContactBadge
这个ImageView的扩展可以简单的了解一下,推荐农民伯伯大神博客地址:http://www.cnblogs.com/over140/archive/2010/09/28/1837287.html,开发中用的比较少,大概看看就行了ViewAnimator、ViewFlipper、ViewSwitcher、TextSwitcher
ViewFlipper、ViewSwitcher都是继承自ViewAnimator,ViewFlipper与AdapterViewFlipper差别不大略过,这里主要是关注一下ViewSwitcher相关类扩展一下视野。ViewAnimator是继承自FrameLayout,而ViewSwitcher是其子类,强制有且只能有2个childView,TextSwitcher限定childView必须是TextView.关于这类扩展控件自行检索Github.Spinner、AbsSpinner、AdapterView、AutoCompleteTextView、MultiAutoCompleteTextView、ListPopupWindow、ListView到底有多亲密的关系?
直接贴代码估计比较晦涩难懂了,能把人给绕晕了,我们还是先看图说话吧。他们之间的的关系到底有多深呢,且听我一一道来。最上层ViewGrou抽象下来的Adapter,拥有很多子类,Spinner的具体实现,跟踪源代码发现内部有实例化出一个ListPopuWindow、DialogPopup(根据不同的mode选择不同的实例,本质区别一个是popuwindow一个是AlertDialog),而ListPopuWindow类让我发现了这么个东西DropDownListView 的实例(AlertDialog同样调用了getLitView方法)
private static class DropDownListView extends ListView { }
由此可以知道每个ListPopuWindow里面有一个LIstView,Spinner弹出来的其实就是ListView绑定适配器,而Spinner内部定义了一个DropDownAdapter,ListView绑定Adapter,最后调用各自mode对应的popu.show就可以了。那么问题来了,Spinner在很么时候弹出ListPopuWindow?带着这个问题继续跟踪Spinner源码
ViewGroup继承自View,所以可以共享父类方法performClick,点击时会调用该方法,自然Spinner也不例外,具体调用代码块如下(当然还有其他地方有触发,这里暂不深入理解了)
@Override public boolean performClick() { boolean handled = super.performClick(); if (!handled) { handled = true; if (!mPopup.isShowing()) { mPopup.show(getTextDirection(), getTextAlignment()); } } return handled; }
用过的人都知道Spinner的Item预定义样式有点丑陋,主要是AbsSpinner搞鬼,下面是预定义的载入代码块(修改Spinner样式可以参考adapter这里的调用)
public AbsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initAbsSpinner(); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries); if (entries != null) { final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( context, R.layout.simple_spinner_item, entries); adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item); setAdapter(adapter); } a.recycle(); }
看完Spinner有了个大概的认知,再看AutoCompleteTextView(他的子类同理略过了),内部同样实例了ListPopuWindow,添加了一个EditText输入内容的监听
addTextChangedListener(new MyWatcher());
如果你对这个方法不陌生应该秒懂了吧,根据输入内容,当输入内容有变化立即执行过滤匹配适配器,这里过滤具体实现暂不涉及。
CheckedTextView
在之前我写过一篇关于ListView的单选和多选相关的分析的博客http://blog.csdn.net/analyzesystem/article/details/51319841,里面有提到一个非常重要的接口Checkable,这里就不多说废话了,同时提供一个开源库关于CheckedTextView相关的扩展库(别太当真,看看就好,扩展视野)https://github.com/akbarsha03/Custom_CheckedTextView
Chronometer
这是一个扩展子TextView的计时器控件,然而我不得不吐槽,官方提供的很多原生控件都不咋样,与开源项目同类型的开源控件没法比,关于计时器这个,在很久以前貌似我也写了一篇blog分析一个计时器开源项目做了个纪录,地址:http://blog.csdn.net/analyzesystem/article/details/50435228小结
收获了两点:1.在onAttachedToWindow和onDetachedFromWindow方法注册广播和取消注册,接收到广播,来做一些回调或者更新UI
2.了解了Spinner AutoCompleteTextView ListView等相关类的相关实现。
相关文章推荐
- mysql -- 区分apk包中,java包,android包,第三方包的方法
- [置顶] android 底层日志 开发框架 崩溃后进行记录 LogReport
- Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)
- ListView
- Android Fragment 详解 2016 干货
- android的ImageView动画自动播放
- Android TextView限制字数属性
- android textview
- Android 自定义View 图片按Path运动和旋转
- Kotlin开发Android笔记2:Kotlin与Java简单比较
- 通过addDataScheme("file") 浅析android事件过滤策略
- Android学习第一天
- Android实现滑动的七种方法
- 理解屏幕和资源的常见问题
- Android Studio 注释模板生成
- Android——超炫dialog弹窗效果,及自定义view dialog
- Android源码的Binder权限控制
- Android中自定义一个View的方法详解
- Android进阶之使用multidex(产生多个dex)解决Dex超出方法数65535的限制
- Android NDK开发指南(二)Android.mk文件