目前对于view还处于学习阶段,本来打算学习结束之后再写一篇进行总结,但是发现自己自制力太差,学习效率太低,所以在此,边学边写博客,不仅督促自己完成对view的学习,而且还可以看看大家对于view有什么想知道的,顺便来看看自己需要研究些什么。
请尊重技术原创,转载请注明出处 ,本文出自
fang_fang_story
接下来就是对view的学习。对于view我的学习思路是先要对view相关的知识进行一个整体的系统的了解,然后在对view中各个知识模块进行详细的研究,如果有正在研究view并且遇到问题的可以留言,大家一起讨论讨论。想要对view先有个整体的了解,我建议大家参考view.java中的类的注释,注释中交代了view所涉及到的所有知识。
Chapter One ,View概念介绍
View是基本的用户界面组件,一个view拥有屏幕上的一块儿矩形区域,可以进行绘制以及事件events的处理。View类是各种控件widget类的基类,控件widget是那些用户交互UI组件,比如,button,textview,imageview等等。View的子类ViewGroup是界面布局layout的基类,layout是指linearlayout,relativelayout等等,这些layout是一些不可见但占有space的invisible的布局容器,可以包括layout或者widget,并且可以声明他们自己的layout属性。(笔者注:invisible是说控件存在屏幕上已经布局了该view但是不可见此时控件可以有事件处理逻辑,gone是指控件不存在屏幕上现在不存在该view);
Chapter Two,Using View(view如何使用)
一个Window窗口中所有的view都在同一个tree即树形结构中。往一个树形结构中添加view有两种方法
1,可以通过代码添加(笔者注:调用viewgroup的addview方法 ,如下代码),
RelativeLayout mRl = (RelativeLayout) findViewById(R.id.rl);
TextView tv = new TextView(this);
tv.setText("这是在代码中加载的view");
tv.setTextColor(Color.RED);
mRl.addView(tv);
2,也可以在view树的layout文件中添加。
Chapter Three,View的生命周期--LifeCycle
要想自定义view,你可以覆写一些framework层使用view时调用的一些标准方法,不需要覆写所有的,事实上,可以覆写onDraw,如下表所示
Category | Methods | Description |
Creation | Constructors(构造器方法) | 当view在代码中被创建时会调用该方法,填充xml文件时也会调用该方法 |
onFinishInflate() | 当view以及他所有的子view都被填充时会调用该方法 | |
Layout | onMeasure(int ,int ) | 决定view与子view所要求的大小时调用 |
onLayout(boolean,int,int,int,int) | 当view给子view分配size和position,大小和位置的时候会调用 | |
onSizeChanged(int,int,int,int) | 当view的size发生改变时会调用 | |
Drawing | onDraw | 当view需要提供content内容时调用 |
Event Processing(事件处理) | onKeyDown(int,KeyEvent) | 当有物理按键被按下时会调用 |
onKeyUp(int,KeyEvent) | 当物理按键抬起时会调用 | |
onTrackBallEvent(MotionEvent) | ???Called when a trackball motion event occurs(笔者注:何时触发,view轨迹移动) | |
onTouchEvent(MotionEvent) | 当有触摸事件发生时会触发 | |
Focus | onFocusChanged(boolean,int,android.graphics.Rect) | 当view的焦点发生改变时(失去或者获取焦点)会调用该方法 |
onWindowFocusChanged(boolean) | 当包含这个view的window获取或者失去焦点时(activity的生命周期有关) | |
Attaching | onAttachedToWindow() | 当与window绑定时会调用该方法 |
onDetachedFromWindow() | 当与window解除绑定时会调用该方法 | |
onWindowVisibilityChanged(int) | 当所绑定的window的可见性发生改变时会调用 |
- Context context:上下文对象,用于获取theme,resource资源等等。(获取当前activity的theme用this,获取整个应用可以用getApplicationContext)
- AttributSet attrs:属性集合,有了这个参数,才可以解析在xml中添加的view的各种属性。(width,height...etc)
- int defStyleAttr:主题属性(item)比如buttonstyle等等,R.attrs....,是在context所获取的theme中寻找view所对应的一个item属性,用来规定view的样式资源style
- int defStyleRes:样式资源style的id,可以使用自己自定义的style来给view,自定义的style可以通过context获取到resource资源获取,但是这个只有在主题中没有定义样式资源这个属性或者样式资源这个属性为0时才会起作用
- 可以在代码中动态添加方法(在运行时期添加),借助viewgroup特有的addView(View)方法添加view,添加view可借助只含有Context构造参数的构造方法
- 可以在xml中静态添加(在编译期添加),在xml中添加view要注意两个问题,一个是一定要覆写带有AttributSet参数的构造方法,二是这个参数一定不能为null,因为这个参数会传给framework层让其去解析xml文件中对应的属性
在笔者刚开始自定义view时问题很多,比如在xml文件中使用时会报出填充异常等等,很多都是因为对view的构造方法不熟悉导致的。只有了解了基础,才能进行举一反三,毕竟关于view的这些都是依靠这些基础而来的,不论再多变,不变的是基础!!!
对于onMeasure,onLayout,onDraw以及事件的处理,需要仔细分析。对于这些方法的分析先留着以后进行,接下来继续对view的介绍
Chapter Four ,IDS
对于view的id应该没什么好说的了,经常使用。view需要一个整形的id与其对应,在你所查找的view树范围(一个window窗口)内,ID具有唯一性。所以在view树中可以通过ID来寻找view
Chapter Five, Position
view的几何形状是个矩形(笔者注:自定义selector改变形状除外),left和top的值决定了view的location(位置),宽和高的大小决定了view的size(尺寸大小),不论是尺寸还是位置单位都是像素。笔者注:所以可以知道通过getLeft(view的X坐标)和getTop(view的Y坐标)就可以获取到view的位置(但是所获取到的getLeft和getTop都是相对于它的父view来说的)
Chapter Six,SizePaddingMargins
Size:View的大小通过宽和高两个值来体现,事实上一个view拥有两对宽和高的值
- the first第一对,measured width/height,测量宽高(getMeasuredHeight/width):这组宽高定义了view在它的父view中所想要的宽高
- the Sec第二对,width/height有时也叫drawingwidth/drawingHeight,绘制的宽高(getWidth/height):定义了在layout结束后在draw绘制时view在屏幕上所显示的真是的宽高,这组值有可能与第一组值不同。
Padding : 为了测量view的尺寸,需要将Padding考虑在内,View的padding包括left、top、right、bottom。padding用来表示view的内容的偏移量,(这个不再多说,目前还没看到需要有什么注意的地方,如果以后有遇到再说)
Margins:margin说的是view与view之间的距离,所以对于单个view来说没有margin的概念,margin是针对viewgroup来说的。
Chapter Seven,EventHandlingThreading(事件处理线程)
Chapter Eight,FocusHandling(焦点处理)
- isFocusable()/setFocusable(boolean) :View是否想要获取焦点
- isFocusableInTouchMode/setFocusableInTouchMode:在触摸模式下,view是否想要获取焦点
- requestFocus():让view获取焦点
Chapter Nine Touch Mode (触摸模式)
Chapter Ten Tags(标签)
首先你需要在string.xml文件中定义一个标签,格式如下
<resources>
。。。。。
<item name="R.tag.view" type="id"/>
</resources>
然后你可以在Java中传递view的信息
可以看到有两种方式,第一是setTag(要保存的信息),第二种是setTag(key,value);如果你只需要保存一个view相关的信息,完全可以使用setTag(value)的方式,但如果要保存的view的信息有多个,那就要使用setTag(key,value)来保存,然后通过对应的tag的key来获取所保存的信息。
其他与measure,layout,draw以及触摸或者按键事件的处理过程需要详细研究
【S】【actor added 】【2016-12-29】
Chapter Eleven,Layout
Layout包含两个过程:measure测量过程和layout定位布局的过程。
通过measure(int,int)来实现测量过程,测量是对view树从上到下进行递归测量的一个过程。在递归测量的过程中每一个view把自己的测量数据交给view树。在测量过程结束后每一个view存储了自己的测量值。
layout定位布局的过程发生在layout(int,int,int,int),也是沿着view树从上到下的过程,在layout过程中每一个父view有责任根据measure过程中所计算的子view的大小去定位子view的位置。
当一个view的measure的方法返回时,该view的measuredWIdth和measuredHeight必须被设置,也就是说,如果调用了measure方法对view进行了测量,那就必须调用setMeasuredDimensionRaw方法将view包括该view的子view的measuredHeight和measuredWidth保存起来。view的measuredHeight/measuredWidth大小必须遵循父view对子view的限制。只有这样才能保证在测量过程结束后父view能够接受子view的尺寸,进行更好的布局。父view可能对子view多次调用measure方法。例如,父view去测量未指明大小的view所想要的size,又或者所有view的大小加起来过大或者过小时就会重新进行measure。
measure的过程涉及到两个类。一个是MeasureSpec(测量规范)用来让子view告诉父view他们想要怎样被测量。还有一个LayoutParams类用来描述一个view想要多大,对于view的尺寸可能是以下三种的一个值
- an exact number:一个确定的值
- match_parent:和父类一样大
- wrap_parent:包裹内容.
不同的viewgroup有不同 的layoutparams的子类,例如,Absolutelayout的layoutparams的子类可以添加X和Y的值。
测量规范是父view对子view的一个测量规范,一个测量规范有三种模式
- UNSPECIFIED:未指明的,父view不对子view的测量做任何要求,子view想要多大就多大
- EXACTLY:准确的值,父view给子view一个确定值,不论子view想要多大,只能使用父view给子view规定的值
- AT_MOST:至多,父view会规定一个最大值,子view的大小不能超过这个值
通过调用requestlayout()方法可以初始化layout,当一个view察觉到当前的边界已经不再适合时会调用。
Chapter Twelve,Drawing
Drawing用来遍历整个view树并且渲染无效区域的view,因为drawing是沿着view进行遍历的,这也就意味着父view优先于子view的绘制,同一级的view是按照他们view树中出现的顺序进行绘制,如果你给一个view设置了背景图片,那么在回调onDraw方法之前会优先绘制背景图片。
framework不会绘制不处于无效区域(无效区域是指还未被使用的一片区域)的view。
通过调用invaliate()方法来强制进行drawing。
Chapter Thirteen,Animation
可以调用setAnimation(animation)或者startAnimation(animation)来给view绑定一个动画。动画可以是view进行伸缩,旋转,平移和透明度渐变的动画。如果一个有子view的view添加了动画,那么这个动画会影响以该view为一个根节点沿着view树向下的所有view。当开始动画后,framework会按照动画要求对view进行重新绘制,直到动画结束。
Chapter Fourteen,嵌套类
- BaseSavedState:基类,通过继承该类并借助onSaveInstanceState保存自己状态
- MeasureSpec:封装了父view对子view的测量要求
- onClickListener:当view被点击时调用
- onCreateContextMenuListener:当view创建了上下文菜单时触发
- onFocusChangedListener:当view的焦点发生改变时触发
- onKeyListener:当有按键事件会触发
- onLongClickListener:长按时触发
- onTouchListener:触摸时触发