尚硅谷自定义View学习笔记-小白到实战
2017-05-18 12:23
435 查看
该笔记适合准备入手Android自定义View学习的小伙伴,对于大神的话,建议去其他地方逛逛哈,在此博主声明一下:我不是尚硅谷的什么托,只是一个菜鸟,现在在补着Java基础,搞了一套尚硅谷的Java视频以及Android视频,所以笔记可能会常出现这些字眼,请言语讽刺我是托的麻烦你闭嘴哈
尚硅谷Android自定义控件视频(实战),记得下载上面的链接视频,因为其涉及了基础(如果是小白)
视频格式转gif-Video to animated GIF converter
备用下载链接: https://pan.baidu.com/s/1jIytuCY 密码: ggty
Android_CustomSwitch at master · IamXiaRui/Android_Demo_View
View 的事件分发机制 | 一个写代码的地方
down : 手指按下
move : 手指在屏幕上移动
up : 手指从屏幕上离开
触屏操作的顺序: down->move->move->…->up
对屏幕的任何一个操作, 系统都会创建一个MotionEvent对象来对应这个操作
[b]MotionEvent 相关API[/b]
MotionEvent : 触屏事件
int ACTION_DOWN=0 : 代表down
Int ACTION_MOVE=2 ; 代表move
Int ACTION_UP=1 : 代表up
getAction() : 得到事件类型值
getX() : 得到事件发生的x轴坐标(相对于当前视图)
getRawX() :得到事件发生的x轴坐标(相对于屏幕左顶点)
getY() : 得到事件发生的y轴坐标(相对于当前视图)
getRawY() :得到事件发生的y轴坐标(相对于屏幕左顶点)
Activity
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调
View
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调方法
void setOnTouchListener(OnTouchListener l) : 设置事件监听器
void setOnClickListener(OnClickListener l) : 设置点击监听
void setOnLongClickListener(OnLongClickListener l) : 设置长按监听
void setOnCreateContextMenuListener(OnCreateContextMenuListener l) : 用于创建菜单
ViewGroup
boolean dispatchTouchEvent(MotionEvent ev) : 分发事件
boolean onInterceptTouchEvent(MotionEvent ev) : 拦截事件的回调方法
注意:其中View跟ViewGroup中都有dispatchTouchEvent方法,但View这个方法更多倾向于分发给自身的onTouchEvent跟setOnTouchListener方法,而ViewGroup中的这个方法是将事件分发给子View
[b]触摸事件的分发与处理[/b]
事件产生的顺序为: down–>move–>move…—>up
事件对象被系统创建后, 首先会调用对应Activity对象的dispatchTouchEvent()进行分发
down在分发给视图对象的过程中要确定消费者(onTouchEvent()返回true),如果都返回false, 那事件的消费者只能是Activity了
后面的move和up事件, 将事件分发给消费者(可能是视图对象,也可能是Activity)处理, 如果视图不消费, 直接交给Activity处理消费
当前事件的消费者只是决定了下一个事件优先交给它处理
每个事件都需要有一个消费者
优秀博客:Android事件分发机制完全解析,带你从源码的角度彻底理解(上) - 郭霖的专栏 - 博客频道 - CSDN.NET
down : 手指按下
up : 手指从按键上离开
* 按键操作的顺序: down->down->down->…->up
* 对按键的任何一个操作, 系统都会创建一个KeyEvent对象来对应这个操作
* 按键的长按监听: down之后一定时间还没有up时会触发长按监听回调
[b]按键操作的相关API[/b]
KeyEvent
int ACTION_DOWN = 0 : 标识down的常量
int ACTION_UP = 1 : 标识up的常量
int getAction() : 得到事件类型
int getKeyCode() : 得到按键的keycode(唯一标识)
startTracking() : 追踪事件, 用于长按监听 (在keyDown那里设置,event.startTracking()方法,这样onKeyLongPress方法才会有效,但特殊的是back键已经那只了这个方法)
Activity
boolean dispatchKeyEvent(KeyEvent event) : 分发事件
boolean onKeyDown(int keyCode, KeyEvent event) : 按下按键的回调
boolean onKeyUp(int keyCode, KeyEvent event) : 松开按键的回调
boolean onKeyLongPress(int keyCode, KeyEvent event) : 长按按键的回调
面试题:如何区别View与Activity ?
1.View是能显示到手机屏幕中UI组件
2.Activity是四大组件中唯一能与用户进行直接交互的应用组件
3.Activity只是控制和管理View, 真正显示和处理事件的是View本身来完成
创建对象
创建方式(2种)
new MyView(context)
加载布局文件(必须有自定义View的全类名标签)
流程方法
构造方法
Xxx(Context context)
Xxx(Context context, AttributeSet set)
onFinishInflate()-作用是得到子View对象,只有布局的方式才会调用即在xml创建布局这种
onAttachedToWindow()-作用也是得到子View对象,哪种创建对象的方式都会执行这个方法
Activity的onResume()执行之后才会进入后面的流程(onFinishInflate()之后执行, onAttachedToWindow()之前执行)
面试题:为什么在Activity的onCreate()方法里拿不到布局控件的宽高
因为执行完onResume()这个方法之后Activity界面才会执行后面如测量,布局等的方法
测量
作用:计算并确定视图的大小(width/height)
流程方法
measure()
系统在此方法中测量计算出当前视图的宽高
此方法为final类型,不能被重写
onMeasure()
当mearure()中计算出的视图的宽高就会调用此方法, 在此方法默认保存的视图宽高(里面它调用的setMeasuredDimension方法就是保存MeaSure测量出的宽高)
重写它, 做我们自己的工作, 比如得到当前视图测量的宽高, 保存我们指定的宽度
布局
作用:确定视图显示的坐标(left, top, right, bottom)
流程方法
layout(l, t, r, b)
不会重写此方法, 只会调用视图对象的此方法, 指定其新的显示位置(作用在自己的身上)
onLayout()
重写它, 在layout()的过程中, 如果视图的位置/强制重新布局就会调用此方法(作用在儿子身上)
强制重新布局
view.requestLayout()
绘制
作用:画出视图的样子
流程方法
draw()
绘制视图通用的部分
确定绘制的流程
一般不会重写此方法
onDraw()
重写此方法,绘制自己需要的样子
一些具体的View类(TextView/ImageView)都重写了此方法,而布局不会重写这个方法的
强制重绘
invalidate():只能在主线程执行
postInvalidate():可以在主线程或分线程执行
事件处理
流程方法
dispatchTouchEvent()
分发事件
从外向里一层一层分发, 分发到事件发生的最里面的视图对象
boolean onInterceptTouchEvent()
拦截请求, 只有return true才拦截成功
如果事件被拦截,事件不会再向内层分发, 交给当前的视图处理(但不一定是它消费)
boolean onTouchEvent()
处理事件
消费事件, 条件: return true
requestDisallowInterceptTouchEvent(true)
反拦截
view.getParent().requestDisallowInterceptTouchEvent(true)-View没有拦截事件的能力,ViewGruop才有拦截事件的能力
事件机制
分发
将TouchEvent对象从Activity对象开始,
由外向内分发给对应的布局和子View对象
处理
回调OnTouchListener的boolean onTouch()
回调boolean onTouchEvent()
消费
回调方法返回true
拦截
onInterceptTouchEvent()执行返回true
如果返回true, TouchEvent就不会再传入子View对象
反拦截
view.getParent().requestDisallowInterceptTouchEvent(true)
使父View不能再拦截, 事件就会分发到当前View对象
死亡
什么时候会死亡?
视图对象被移除
Activity死亡之前
流程方法
onDetachedFromWindow()
其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.
View对象是Android平台中用户界面体现的基础单位。
View类是它称为“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的UI对象的完整实现。
ViewGroup类同样为其被称为“Layouts(布局)”的子类奠定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。
一般来说,开发Android应用程序的UI界面都不会直接使用View和ViewGroup,而是使用这两大基类的派生类。
View派生出的直接子类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView, TextView,ViewGroup,ViewStub
View派生出的间接子类有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton
ViewGroup派生出的直接子类有AbsoluteLayout,AdapterView,FragmentBreadCrumbs,FrameLayout, LinearLayout,RelativeLayout,SlidingDrawer
ViewGroup派生出的间接子类有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView
这里特别指出,ImageView是布局具有图片效果的UI常用的类,SurfaceView是用来进行游戏开发的与一般View相比较为特殊的非常重要的类,而AbsoluteLayout、 FrameLayout,LinearLayout, RelativeLayout这几个ViewGroup的直接子类是Android UI布局中最基本的布局元素。
基于View的渐变动画,她只改变了View的绘制效果,而实际属性值未变。比如动画移动一个按钮位置,但按钮点击的实际位置仍未改变。在代码中定义动画,可以参考AnimationSet类和Animation的子类;而如果使用XML,可以在res/anim/文件夹中定义XML文件。
Drawable Animation(帧动画):
加载一系列Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放,就像电影胶片。在代码中定义动画帧,使用AnimationDrawable类;XML文件能更简单的组成动画帧,在res/drawable文件夹,使用采用来定义不同的帧。感觉只能设置的属性是动画间隔时间。
Property Animation(属性动画):
动画的对象除了传统的View对象,还可以是Object对象,动画之后,Object对象的属性值被实实在在的改变了。Property animation能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来试试刷新。
参考博客:
1. Android应用开发之所有动画使用详解 - 工匠若水 - 博客频道 - CSDN.NET
2. Android属性动画完全解析(上),初识属性动画的基本用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
3. Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
4. Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
5.
* 广告条效果
用到的控件:ViewPager
ViewPager详解(一)简单介绍和使用 - 简书
ViewPager详解(二)广告轮播图 - 简书
Android之——史上最简单图片轮播广告效果实现 - 博客频道 - CSDN.NET
自己造轮子–一款实用的Android广告栏实现过程(一) - 简书
最终效果
Android自定义带动画无限自动轮播的Banner控件 - 简书
可以考虑的第三方开源库:
Android-ConvenientBanner: 通用的广告栏控件,让你轻松实现广告头效果。
首页垂直滚动TextView广告效果,使用TextSwicher+animation实现 - 门徒07的博客 - 博客频道 - CSDN.NET
下拉框
更好的实现:
Android之——自定义下拉菜单的实现 - 刘亚壮的专栏 - 博客频道 - CSDN.NET
Android 自定义View修炼-如何打造Android自定义的下拉列表框控件 - Jamy Cai - 博客园
1.构造方法实例化类
2.测量-measure(int,int)–>onMeasure();
如果当前View是一个ViewGroup,还有义务测量孩子
孩子有建议权
3.指定位置-layout()–>onLayout();
指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
4.绘制视图–draw()–>onDraw(canvas)
根据上面两个方法参数,进入绘制
自定义开关
参考博客:
Android自定义控件系列二:自定义开关按钮(一) - 苦咖啡的自留地 - 博客频道 - CSDN.NET
Android自定义控件系列三:自定义开关按钮(二) - 苦咖啡的自留地 - 博客频道 - CSDN.NET
水波纹
参考博客:
1. Android5.0水波纹效果ripple实现 - wansho - 博客园
2. Android 自定义view实现水波纹效果 - 享受技术带来的快乐 - 博客频道 - CSDN.NET
3. Android 水波纹点击效果(Ripple Effect) - wingyip - 博客园
4. Android L中水波纹点击效果的实现 - 任玉刚 - 博客频道 - CSDN.NET
自定义属性
引用博客:
Android自定义View(二、深入解析自定义属性) - openXu的专栏 - 博客频道 - CSDN.NET
Android 自定义VIEW属性用法详解(attrs、TypedArray)_Windows Phone_IThao123
Android:自定义控件 — 自定义属性 枚举值(固定属性值) - 博客频道 - CSDN.NET
Android 中 Bitmap 和 Drawable 相互转换的方法 - 哦? - 博客频道 - CSDN.NET
面试题:Android Bitmap 和 BitmapDrawable的区别
Bitmap继承Parcelable,可见是一个可以跨进程传输的对象
BitmapDrawable继承Drawable,可Drawable只是一个抽象类,可见此类是一个存放数据流的载体
使用情况:如果想绑定imageView之类的控件,两者都可以用,而想要将图片数据转换成其它对象,Bitmap功能更强大,而BitmapDrawable只是一个流的载体,所以一般获取src资源文件的时候用得多,而想要把资源图片截入到Bitmap需要转换后才可得到Bitmap对象。两者之间有微妙的联系,又有微妙的区别,请看情况而定
参考博客:
android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明 - 未来之路 的专栏 - 博客频道 - CSDN.NET
实现3D翻转效果的仿ViewPager - KevinsCSDN的博客 - 博客频道 - CSDN.NET
让你的动画不再生硬 Android插值器Interpolator使用秘籍 - 旋转 跳跃 然后 团灭 - 博客频道 - CSDN.NET
android动画插值器Interpolator使用demo - 下载频道 - CSDN.NET
插补器Interpolator配图详解 - pengkv的专栏 - 博客频道 - CSDN.NET
Android-通过自定义ViewPager来高仿土巴兔选择装修风格效果(中间放大效果) - 泡在网上的日子
Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果 - Jamy Cai - 博客园
Android开发-自定义View-AndroidStudio(十三)仿ViewPager(3) - iwanghang(一个播音与主持艺术专业、干过网游打金工作室,做过海鲜小吃排挡的新手程序员) - 博客频道 - CSDN.NET
关于自定义ViewGroup的问题
1. Android自定义View(三、深入解析控件测量onMeasure) - openXu的专栏 - 博客频道 - CSDN.NET
2.自定义View 1:关于View,ViewGroup的测量和绘制流程 - Android开发社区 | CTOLib码库
3.Activtiy完全解析(三、View的显示过程measure、layout、draw) - openXu的专栏 - 博客频道 - CSDN.NET
联系人列表
参考博客:
Android 联系人列表界面(仿iphone、A~Z字母排列、过滤搜索) - 白雨-博客 - 博客频道 - CSDN.NET
Android自定义View——实现联系人列表字母索引 - 阿钟的博客 - 博客频道 - CSDN.NET
android中getWidth()和getMeasuredWidth()之间的区别 - 豌豆豆 - 博客园
发现一个写法更简洁的实现方式-gjiazhe/WaveSideBar: An Index Side Bar With Wave Effect
更为绚丽的联系人列表-kongnanlive/bubble-scroll: An animating scroll bar
侧滑删除菜单
参考博客:
1. 【android自定义控件】android ListView添加侧滑删除 - ___leng的专栏 - 博客频道 - CSDN.NET
更为优秀的做法:
1. ListView 侧滑菜单的实现 – 大道至简的SwipeMenuLayout - 简书
2. Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 - Hongyang - 博客频道 - CSDN.NET
3. RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载 - 严振杰 - 博客频道 - CSDN.NET
[b]联系人+侧滑菜单高度集成[/b]
[【Android】史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS。 - zxt0601的博客 - 博客频道 - CSDN.NET](http://blog.csdn.net/zxt0601/article/details/53157090)
![联系人+侧滑菜单高度集成](http://ac-mhke0kuv.clouddn.com/104ab70447af9b78832f.gif)
Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 - Hongyang - 博客频道 - CSDN.NET
用于做View的滑动,它可以比较方便实现滑动的效果,并且不影响内部元素的点击事件;它只能滑动View的内容,并不能滑动View本身。
调用View的scrollTo()和scrollBy()是用于滑动View中的内容,而不是把某个View的位置进行改变。如果想改变莫个View在屏幕中的位置,可以使用如下的方法。
使用动画
View动画是对View的影像做操作,它并不能真正改变View的位置参数,包括宽和高。
Android3.0以上使用属性动画可以解决,可以改变位置参数。
改变布局参数
适用于对View有交互的View.
使用场景:应用第一次进入时引导动画界面的小红点
MotionEvent.getX();
MotionEvent.getY();
以屏幕左上方原点坐标,getRawX()距离x轴心上的距离,getRawY()距离Y轴上的距离
MotionEvent.getRawX();
MotionEvent.getRawY();
图解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY() - bigconvience的专栏 - 博客频道 - CSDN.NET
Android中View中的scrollTo(),scrollBy(),getScrollX(), getScrollY()详解 - 博客频道 - CSDN.NET
Android getScrollX()详解 - znouy的博客 - 博客频道 - CSDN.NET
个人小理解:
1.getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量
如果是从左到右移动得到的值是负数,负数代表内容距离左边的偏移量;从右到左移动是正值
比如button里面的内容对于button而言的偏移量
幽默解析版:比如Button里面的内容text移动了,但对于Button的老爸LinearLayout以及爷爷RelativeLayout(一般都是爷爷管爸爸,爸爸管儿子的,所以这里不谈RelativeLayout),老爸LinearLayout从看到儿子Button位置没有改变,就认为他没事(此时Button的getScrollX()的偏移量是0),但是Button看到自己的内容text位置改变了,他认为text有事(此时text的getScrollX()的偏移量不是0了)
整体局部版:把Button当做一个整体,从Button外部看,Button的位置的确没有改变,至于他内部怎么改变(比如他内容text位置改变了),那是他自己的事情,所以Button的getScrollX是0;但仅仅看Button的时候,它内部的text的确位置改变了,那么text的getScrollX不是0(重点理解这句话:getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量,其实就是一个位移值)
PS:儿子的位置是由父亲作为坐标系确定的
android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明 - 未来之路 的专栏 - 博客频道 - CSDN.NET
view.scrollTo(x,y) 将整个父视图的左上角定为(0,0),再移动这个屏幕的左上角到父视图的点(x,y)处,注意此处的x和y是根据父视图的坐标系来定的。
四个参数分别表示起点的坐标和滑动的向量,即从(startX,startY)开始滑 动,横向滑动dx的距离,纵向滑动dy的距离(正值向左滑,负值向右滑),而这里的startX,startY又是参照的父视图左上角为原点坐标的坐标系,滑屏时经常使用getScrollX()和getScrollY()来代表屏幕左边缘和上边缘处于父视图坐标系的具体位置
公式:
int dx = 目标- getScrollX()
scroller.computeScrollOffset返回的是boolean值,false代表移动完成了
视频
尚硅谷事件机制以及自定义控件的绘制基础 (最需要下载的:15天安卓视频->视频->06_事件机制.zip以及07_四大应用组件之Service)尚硅谷Android自定义控件视频(实战),记得下载上面的链接视频,因为其涉及了基础(如果是小白)
视频格式转gif-Video to animated GIF converter
备用下载链接: https://pan.baidu.com/s/1jIytuCY 密码: ggty
博客
youlookwhat/CustomViewStudy: 自定义View从入门到进阶(集合Hongyang大神)).自定义控件的准备
Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent() - 张兴业的博客 - 博客频道 - CSDN.NETAndroid_CustomSwitch at master · IamXiaRui/Android_Demo_View
View 的事件分发机制 | 一个写代码的地方
触屏操作的理解
最基本的操作类型:down : 手指按下
move : 手指在屏幕上移动
up : 手指从屏幕上离开
触屏操作的顺序: down->move->move->…->up
对屏幕的任何一个操作, 系统都会创建一个MotionEvent对象来对应这个操作
[b]MotionEvent 相关API[/b]
MotionEvent : 触屏事件
int ACTION_DOWN=0 : 代表down
Int ACTION_MOVE=2 ; 代表move
Int ACTION_UP=1 : 代表up
getAction() : 得到事件类型值
getX() : 得到事件发生的x轴坐标(相对于当前视图)
getRawX() :得到事件发生的x轴坐标(相对于屏幕左顶点)
getY() : 得到事件发生的y轴坐标(相对于当前视图)
getRawY() :得到事件发生的y轴坐标(相对于屏幕左顶点)
Activity
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调
View
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调方法
void setOnTouchListener(OnTouchListener l) : 设置事件监听器
void setOnClickListener(OnClickListener l) : 设置点击监听
void setOnLongClickListener(OnLongClickListener l) : 设置长按监听
void setOnCreateContextMenuListener(OnCreateContextMenuListener l) : 用于创建菜单
ViewGroup
boolean dispatchTouchEvent(MotionEvent ev) : 分发事件
boolean onInterceptTouchEvent(MotionEvent ev) : 拦截事件的回调方法
注意:其中View跟ViewGroup中都有dispatchTouchEvent方法,但View这个方法更多倾向于分发给自身的onTouchEvent跟setOnTouchListener方法,而ViewGroup中的这个方法是将事件分发给子View
[b]触摸事件的分发与处理[/b]
事件产生的顺序为: down–>move–>move…—>up
事件对象被系统创建后, 首先会调用对应Activity对象的dispatchTouchEvent()进行分发
down在分发给视图对象的过程中要确定消费者(onTouchEvent()返回true),如果都返回false, 那事件的消费者只能是Activity了
后面的move和up事件, 将事件分发给消费者(可能是视图对象,也可能是Activity)处理, 如果视图不消费, 直接交给Activity处理消费
当前事件的消费者只是决定了下一个事件优先交给它处理
每个事件都需要有一个消费者
优秀博客:Android事件分发机制完全解析,带你从源码的角度彻底理解(上) - 郭霖的专栏 - 博客频道 - CSDN.NET
按键操作的理解
[b]操作的基本类型[/b]down : 手指按下
up : 手指从按键上离开
* 按键操作的顺序: down->down->down->…->up
* 对按键的任何一个操作, 系统都会创建一个KeyEvent对象来对应这个操作
* 按键的长按监听: down之后一定时间还没有up时会触发长按监听回调
[b]按键操作的相关API[/b]
KeyEvent
int ACTION_DOWN = 0 : 标识down的常量
int ACTION_UP = 1 : 标识up的常量
int getAction() : 得到事件类型
int getKeyCode() : 得到按键的keycode(唯一标识)
startTracking() : 追踪事件, 用于长按监听 (在keyDown那里设置,event.startTracking()方法,这样onKeyLongPress方法才会有效,但特殊的是back键已经那只了这个方法)
Activity
boolean dispatchKeyEvent(KeyEvent event) : 分发事件
boolean onKeyDown(int keyCode, KeyEvent event) : 按下按键的回调
boolean onKeyUp(int keyCode, KeyEvent event) : 松开按键的回调
boolean onKeyLongPress(int keyCode, KeyEvent event) : 长按按键的回调
自定义控件的基础
先看以前的笔记:尚硅谷15天Android基础(复习笔记) - it菜鸟的飞行梦 - 博客频道 - CSDN.NET面试题:如何区别View与Activity ?
1.View是能显示到手机屏幕中UI组件
2.Activity是四大组件中唯一能与用户进行直接交互的应用组件
3.Activity只是控制和管理View, 真正显示和处理事件的是View本身来完成
View(及其子类)的生命周期
生命周期:创建对象(Activity的onResume()执行之后才会进入后面的流程)、显示(测量onMeasure、布局onLayout、绘制onDraw)、事件处理、死亡创建对象
创建方式(2种)
new MyView(context)
加载布局文件(必须有自定义View的全类名标签)
流程方法
构造方法
Xxx(Context context)
Xxx(Context context, AttributeSet set)
onFinishInflate()-作用是得到子View对象,只有布局的方式才会调用即在xml创建布局这种
onAttachedToWindow()-作用也是得到子View对象,哪种创建对象的方式都会执行这个方法
Activity的onResume()执行之后才会进入后面的流程(onFinishInflate()之后执行, onAttachedToWindow()之前执行)
面试题:为什么在Activity的onCreate()方法里拿不到布局控件的宽高
因为执行完onResume()这个方法之后Activity界面才会执行后面如测量,布局等的方法
测量
作用:计算并确定视图的大小(width/height)
流程方法
measure()
系统在此方法中测量计算出当前视图的宽高
此方法为final类型,不能被重写
onMeasure()
当mearure()中计算出的视图的宽高就会调用此方法, 在此方法默认保存的视图宽高(里面它调用的setMeasuredDimension方法就是保存MeaSure测量出的宽高)
重写它, 做我们自己的工作, 比如得到当前视图测量的宽高, 保存我们指定的宽度
布局
作用:确定视图显示的坐标(left, top, right, bottom)
流程方法
layout(l, t, r, b)
不会重写此方法, 只会调用视图对象的此方法, 指定其新的显示位置(作用在自己的身上)
onLayout()
重写它, 在layout()的过程中, 如果视图的位置/强制重新布局就会调用此方法(作用在儿子身上)
强制重新布局
view.requestLayout()
绘制
作用:画出视图的样子
流程方法
draw()
绘制视图通用的部分
确定绘制的流程
一般不会重写此方法
onDraw()
重写此方法,绘制自己需要的样子
一些具体的View类(TextView/ImageView)都重写了此方法,而布局不会重写这个方法的
强制重绘
invalidate():只能在主线程执行
postInvalidate():可以在主线程或分线程执行
事件处理
流程方法
dispatchTouchEvent()
分发事件
从外向里一层一层分发, 分发到事件发生的最里面的视图对象
boolean onInterceptTouchEvent()
拦截请求, 只有return true才拦截成功
如果事件被拦截,事件不会再向内层分发, 交给当前的视图处理(但不一定是它消费)
boolean onTouchEvent()
处理事件
消费事件, 条件: return true
requestDisallowInterceptTouchEvent(true)
反拦截
view.getParent().requestDisallowInterceptTouchEvent(true)-View没有拦截事件的能力,ViewGruop才有拦截事件的能力
事件机制
分发
将TouchEvent对象从Activity对象开始,
由外向内分发给对应的布局和子View对象
处理
回调OnTouchListener的boolean onTouch()
回调boolean onTouchEvent()
消费
回调方法返回true
拦截
onInterceptTouchEvent()执行返回true
如果返回true, TouchEvent就不会再传入子View对象
反拦截
view.getParent().requestDisallowInterceptTouchEvent(true)
使父View不能再拦截, 事件就会分发到当前View对象
死亡
什么时候会死亡?
视图对象被移除
Activity死亡之前
流程方法
onDetachedFromWindow()
animation动画知识
View和ViewGroup的初步认识
Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.
View对象是Android平台中用户界面体现的基础单位。
View类是它称为“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的UI对象的完整实现。
ViewGroup类同样为其被称为“Layouts(布局)”的子类奠定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。
一般来说,开发Android应用程序的UI界面都不会直接使用View和ViewGroup,而是使用这两大基类的派生类。
View派生出的直接子类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView, TextView,ViewGroup,ViewStub
View派生出的间接子类有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton
ViewGroup派生出的直接子类有AbsoluteLayout,AdapterView,FragmentBreadCrumbs,FrameLayout, LinearLayout,RelativeLayout,SlidingDrawer
ViewGroup派生出的间接子类有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView
这里特别指出,ImageView是布局具有图片效果的UI常用的类,SurfaceView是用来进行游戏开发的与一般View相比较为特殊的非常重要的类,而AbsoluteLayout、 FrameLayout,LinearLayout, RelativeLayout这几个ViewGroup的直接子类是Android UI布局中最基本的布局元素。
动画的分类
View Animation(补间动画):基于View的渐变动画,她只改变了View的绘制效果,而实际属性值未变。比如动画移动一个按钮位置,但按钮点击的实际位置仍未改变。在代码中定义动画,可以参考AnimationSet类和Animation的子类;而如果使用XML,可以在res/anim/文件夹中定义XML文件。
Drawable Animation(帧动画):
加载一系列Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放,就像电影胶片。在代码中定义动画帧,使用AnimationDrawable类;XML文件能更简单的组成动画帧,在res/drawable文件夹,使用采用来定义不同的帧。感觉只能设置的属性是动画间隔时间。
Property Animation(属性动画):
动画的对象除了传统的View对象,还可以是Object对象,动画之后,Object对象的属性值被实实在在的改变了。Property animation能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来试试刷新。
参考博客:
1. Android应用开发之所有动画使用详解 - 工匠若水 - 博客频道 - CSDN.NET
2. Android属性动画完全解析(上),初识属性动画的基本用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
3. Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
4. Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法 - 郭霖的专栏 - 博客频道 - CSDN.NET
5.
自定义控件实战
源码下载:simplebam/custom_view用系统控件重新组合
优酷自定义菜单* 广告条效果
用到的控件:ViewPager
ViewPager详解(一)简单介绍和使用 - 简书
ViewPager详解(二)广告轮播图 - 简书
Android之——史上最简单图片轮播广告效果实现 - 博客频道 - CSDN.NET
自己造轮子–一款实用的Android广告栏实现过程(一) - 简书
最终效果
Android自定义带动画无限自动轮播的Banner控件 - 简书
可以考虑的第三方开源库:
Android-ConvenientBanner: 通用的广告栏控件,让你轻松实现广告头效果。
首页垂直滚动TextView广告效果,使用TextSwicher+animation实现 - 门徒07的博客 - 博客频道 - CSDN.NET
下拉框
更好的实现:
Android之——自定义下拉菜单的实现 - 刘亚壮的专栏 - 博客频道 - CSDN.NET
Android 自定义View修炼-如何打造Android自定义的下拉列表框控件 - Jamy Cai - 博客园
自定义类继承View
一个视图从创建到显示过程中的主要方法1.构造方法实例化类
2.测量-measure(int,int)–>onMeasure();
如果当前View是一个ViewGroup,还有义务测量孩子
孩子有建议权
3.指定位置-layout()–>onLayout();
指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
4.绘制视图–draw()–>onDraw(canvas)
根据上面两个方法参数,进入绘制
自定义开关
参考博客:
Android自定义控件系列二:自定义开关按钮(一) - 苦咖啡的自留地 - 博客频道 - CSDN.NET
Android自定义控件系列三:自定义开关按钮(二) - 苦咖啡的自留地 - 博客频道 - CSDN.NET
水波纹
参考博客:
1. Android5.0水波纹效果ripple实现 - wansho - 博客园
2. Android 自定义view实现水波纹效果 - 享受技术带来的快乐 - 博客频道 - CSDN.NET
3. Android 水波纹点击效果(Ripple Effect) - wingyip - 博客园
4. Android L中水波纹点击效果的实现 - 任玉刚 - 博客频道 - CSDN.NET
自定义属性
引用博客:
Android自定义View(二、深入解析自定义属性) - openXu的专栏 - 博客频道 - CSDN.NET
Android 自定义VIEW属性用法详解(attrs、TypedArray)_Windows Phone_IThao123
Android:自定义控件 — 自定义属性 枚举值(固定属性值) - 博客频道 - CSDN.NET
Android 中 Bitmap 和 Drawable 相互转换的方法 - 哦? - 博客频道 - CSDN.NET
面试题:Android Bitmap 和 BitmapDrawable的区别
Bitmap继承Parcelable,可见是一个可以跨进程传输的对象
BitmapDrawable继承Drawable,可Drawable只是一个抽象类,可见此类是一个存放数据流的载体
使用情况:如果想绑定imageView之类的控件,两者都可以用,而想要将图片数据转换成其它对象,Bitmap功能更强大,而BitmapDrawable只是一个流的载体,所以一般获取src资源文件的时候用得多,而想要把资源图片截入到Bitmap需要转换后才可得到Bitmap对象。两者之间有微妙的联系,又有微妙的区别,请看情况而定
自定义类继承ViewGroup
防ViewPager参考博客:
android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明 - 未来之路 的专栏 - 博客频道 - CSDN.NET
实现3D翻转效果的仿ViewPager - KevinsCSDN的博客 - 博客频道 - CSDN.NET
让你的动画不再生硬 Android插值器Interpolator使用秘籍 - 旋转 跳跃 然后 团灭 - 博客频道 - CSDN.NET
android动画插值器Interpolator使用demo - 下载频道 - CSDN.NET
插补器Interpolator配图详解 - pengkv的专栏 - 博客频道 - CSDN.NET
Android-通过自定义ViewPager来高仿土巴兔选择装修风格效果(中间放大效果) - 泡在网上的日子
Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果 - Jamy Cai - 博客园
Android开发-自定义View-AndroidStudio(十三)仿ViewPager(3) - iwanghang(一个播音与主持艺术专业、干过网游打金工作室,做过海鲜小吃排挡的新手程序员) - 博客频道 - CSDN.NET
关于自定义ViewGroup的问题
1. Android自定义View(三、深入解析控件测量onMeasure) - openXu的专栏 - 博客频道 - CSDN.NET
2.自定义View 1:关于View,ViewGroup的测量和绘制流程 - Android开发社区 | CTOLib码库
3.Activtiy完全解析(三、View的显示过程measure、layout、draw) - openXu的专栏 - 博客频道 - CSDN.NET
联系人列表
参考博客:
Android 联系人列表界面(仿iphone、A~Z字母排列、过滤搜索) - 白雨-博客 - 博客频道 - CSDN.NET
Android自定义View——实现联系人列表字母索引 - 阿钟的博客 - 博客频道 - CSDN.NET
android中getWidth()和getMeasuredWidth()之间的区别 - 豌豆豆 - 博客园
发现一个写法更简洁的实现方式-gjiazhe/WaveSideBar: An Index Side Bar With Wave Effect
更为绚丽的联系人列表-kongnanlive/bubble-scroll: An animating scroll bar
侧滑删除菜单
参考博客:
1. 【android自定义控件】android ListView添加侧滑删除 - ___leng的专栏 - 博客频道 - CSDN.NET
更为优秀的做法:
1. ListView 侧滑菜单的实现 – 大道至简的SwipeMenuLayout - 简书
2. Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 - Hongyang - 博客频道 - CSDN.NET
3. RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载 - 严振杰 - 博客频道 - CSDN.NET
[b]联系人+侧滑菜单高度集成[/b]
[【Android】史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS。 - zxt0601的博客 - 博客频道 - CSDN.NET](http://blog.csdn.net/zxt0601/article/details/53157090)
![联系人+侧滑菜单高度集成](http://ac-mhke0kuv.clouddn.com/104ab70447af9b78832f.gif)
动画的移动
教你10行代码写侧滑菜单-黑马程序员IT技术论坛 - 黑马程序员快速入学必看论坛Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 - Hongyang - 博客频道 - CSDN.NET
移动动画的三种方式:
使用scrollTo/scrollBy用于做View的滑动,它可以比较方便实现滑动的效果,并且不影响内部元素的点击事件;它只能滑动View的内容,并不能滑动View本身。
调用View的scrollTo()和scrollBy()是用于滑动View中的内容,而不是把某个View的位置进行改变。如果想改变莫个View在屏幕中的位置,可以使用如下的方法。
使用动画
View动画是对View的影像做操作,它并不能真正改变View的位置参数,包括宽和高。
Android3.0以上使用属性动画可以解决,可以改变位置参数。
改变布局参数
适用于对View有交互的View.
使用场景:应用第一次进入时引导动画界面的小红点
坐标问题
以当前控件左上方原点坐标,getX()距离X轴上的距离,getY()距离Y轴上的距离MotionEvent.getX();
MotionEvent.getY();
以屏幕左上方原点坐标,getRawX()距离x轴心上的距离,getRawY()距离Y轴上的距离
MotionEvent.getRawX();
MotionEvent.getRawY();
getScrollX(),getScrollY()偏移量的问题
图解MotionEvent中getRawX、getRawY与getX、getY以及View中的getScrollX、getScrollY - 残阳破晓 - 博客园图解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY() - bigconvience的专栏 - 博客频道 - CSDN.NET
Android中View中的scrollTo(),scrollBy(),getScrollX(), getScrollY()详解 - 博客频道 - CSDN.NET
Android getScrollX()详解 - znouy的博客 - 博客频道 - CSDN.NET
个人小理解:
1.getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量
如果是从左到右移动得到的值是负数,负数代表内容距离左边的偏移量;从右到左移动是正值
比如button里面的内容对于button而言的偏移量
<RelativeLayout ...> <LinearLayout ...> <Button ... android:text="Scroll me"/> </LinearLayout> </RelativeLayout>
幽默解析版:比如Button里面的内容text移动了,但对于Button的老爸LinearLayout以及爷爷RelativeLayout(一般都是爷爷管爸爸,爸爸管儿子的,所以这里不谈RelativeLayout),老爸LinearLayout从看到儿子Button位置没有改变,就认为他没事(此时Button的getScrollX()的偏移量是0),但是Button看到自己的内容text位置改变了,他认为text有事(此时text的getScrollX()的偏移量不是0了)
整体局部版:把Button当做一个整体,从Button外部看,Button的位置的确没有改变,至于他内部怎么改变(比如他内容text位置改变了),那是他自己的事情,所以Button的getScrollX是0;但仅仅看Button的时候,它内部的text的确位置改变了,那么text的getScrollX不是0(重点理解这句话:getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量,其实就是一个位移值)
PS:儿子的位置是由父亲作为坐标系确定的
view.scrollTo(x,y)genscrollBy(x,y)区别
图解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY() - bigconvience的专栏 - 博客频道 - CSDN.NETandroid 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明 - 未来之路 的专栏 - 博客频道 - CSDN.NET
view.scrollTo(x,y) 将整个父视图的左上角定为(0,0),再移动这个屏幕的左上角到父视图的点(x,y)处,注意此处的x和y是根据父视图的坐标系来定的。
Scroller
scroller.startScroll(int startX, int startY, int dx, int dy)参数说明四个参数分别表示起点的坐标和滑动的向量,即从(startX,startY)开始滑 动,横向滑动dx的距离,纵向滑动dy的距离(正值向左滑,负值向右滑),而这里的startX,startY又是参照的父视图左上角为原点坐标的坐标系,滑屏时经常使用getScrollX()和getScrollY()来代表屏幕左边缘和上边缘处于父视图坐标系的具体位置
公式:
int dx = 目标- getScrollX()
scroller.computeScrollOffset返回的是boolean值,false代表移动完成了
/** * Call this when you want to know the new location. If it returns true, * the animation is not yet finished. */ public boolean computeScrollOffset() { if (mFinished) { return false; }
相关文章推荐
- iPhone开发学习笔记005——使用XIB自定义一个UIView,然后将这个view添加到controller的view
- APIDemo学习笔记——在XML中使用自定义的View类
- Android开发学习笔记-自定义TextView属性模版
- Android自定义View学习笔记04
- Android自定义view学习笔记01
- IOS学习笔记-04-自定义view和Xib
- 学习鸿洋大神的自定义View(一)的笔记
- Scala中View Bounds代码实战及其在Spark中的应用源码解析之Scala学习笔记-35
- Animation & Animator使用方法(Mooc Android加薪利器--自定义view 代码学习笔记)
- ASP.NET MVC学习笔记-----使用自定义的View Engine
- Android(java)学习笔记204:自定义SmartImageView(继承自ImageView,扩展功能为自动获取网络路径图片)
- 【Android实战】记录自学自定义GifView过程,详解属性那些事!【学习篇】
- Android总结笔记01:自定义View学习(一)
- Android自定义view学习笔记02
- ios学习笔记----实现一个带滑动手势的tabBarViewController,并可自定义tabBar
- Android自定义View学习笔记03
- Android自定义View学习笔记04
- Andriod 学习笔记之八 自定义view实现圆圈标记
- Android自定义view学习笔记