ANDROID自己定义视图——onLayout源代码 流程 思路具体解释
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!
简单介绍:
在自己定义view的时候。事实上非常easy。仅仅须要知道3步骤:
1.測量——onMeasure():决定View的大小
2.布局——onLayout():决定View在ViewGroup中的位置
3.绘制——onDraw():怎样绘制这个View。
而第3步的onDraw系统已经封装的非常好了,基本不用我们来担心,仅仅须要专注到1,2两个步骤就中好了。
第一步的測量,能够參考我之前的文章:(ANDROID自己定义视图——onMeasure流程。MeasureSpec具体解释)
而这篇文章就来谈谈第二步:“布局(Layout)”
知识点回想:
在谈怎样使用onLayout方法前,先简单回顾一下知识点:
View视图结构:
View视图能够是单一的一个如TextView,也能够是一个视图组(ViewGroup)如LinearLayout。
如图:对于多View的视图他的结构是树形结构,最顶层是ViewGroup。ViewGroup下可能有多个ViewGroup或View。
这个树的概念非常重要,由于不管我们是在測量大小或是调整布局的时候都是从树的顶端開始一层一层。一个分支一个分支的进行(树形递归)。
Measure简单回想:
measure的作用就是为整个View树计算实际的大小。而通过刚才对View树的介绍知道,想计算整个View树的大小,就须要递归的去计算每个子视图的大小(Layout同理)。
对每个视图通过onMeasure方法的一系列測量流程后计算出实际的高(mMeasuredHeight)和宽(mMeasureWidth)传入setMeasuredDimension()方法完毕单个View的測量,如果所測的视图是ViewGroup则能够通过measureChild方法递归的计算当中的每个子view。对于每个View的实际宽高都是由父视图和本身视图决定的。
Layout(源代码分析):
Layout的作用就是为整个View树计算实际的位置。而通过刚才对View树的介绍知道,想计算整个View树的位置,就须要递归的去计算每个子视图的位置(Measure同理)。
而确定这个位置非常easy,仅仅须要mLeft,mTop,mRight,mBottom四个值(注意:这4个值是子View相对于父View的值。以下会具体介绍)。
在代码中怎样设置这4个值呢?
首先,不管是系统提供的LinearLayout还是我们自己定义的View视图,他都需要继承自ViewGroup类。之后必需要做的就是重写onLayout方法(由于在onLayout在ViewGroup中被定义为抽象方法)。
ViewGroup-onlayout:
@Override
protected abstract void onLayout(boolean changed, int l, int t, int r, int b);
onLayout被定义为抽象方法,所以在继承ViewGroup时必需要重写该方法(onMeasure不需要)。另外这种方法也被override标注,所以也是重写的方法。他重写的是其父类view中的onLayout方法。
View-onlayout:
/**
* 当这个view和其子view被分配一个大小和位置时,被layout调用。
* @param changed 当前View的大小和位置改变了
* @param left 左部位置(相对于父视图)
* @param top 顶部位置(相对于父视图)
* @param right 右部位置(相对于父视图)
* @param bottom 底部位置(相对于父视图)
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {}
注讲解:当这个view和其子view被分配一个大小和位置时,被layout调用。所以我们去看看layout中做了什么。(注解没有全然依照英文翻译。而且有省略)
View-layout:
/**
* 给View和其全部子View分配大小和位置
*
* 这是布局的第二个阶段(第一个阶段是測量)。在这个阶段中。每个父视图须要去调用layout去为他全部的子视图确定位置
* 派生的子类不应该重写layout方法,应该重写onLayout方法,在onlayout方法中应该去调用每个view的layout
*/
public void layout(int l, int t, int r, int b) {
// 将当前视图的左上右下记录为old值(參数中传入的为新的l,t,r,b值)
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight; // setFrame方法的作用就是将新传入的ltrb属性赋值给View。然后推断当前View大小和位置是否发生了变化并返回
boolean changed = setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
// 调用onLayout回调方法。具体实现由重写了onLayout方法的ViewGroup的子类去实现(后面具体说明)
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; // 调用全部重写了onLayoutChange监听的方法。通知View大小和位置发生了改变
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
}
在这段代码中我们仅仅要知道:假设视图的大小和位置发生变化后。会调用我们前面分析过的onLayout方法。
对于onLayout方法的终于实现所有依靠我们在自己定义ViewGroup类中重写的onLayout去实现。
计算View位置:
在重写的onLayout方法中,唯一的目的就是:
对当前视图和其全部子View设置它们在父视图中详细位置(确定这个位置就依靠mLeft,mTop。mRight。mBottom这四个值)
之前介绍过,mLeft,mTop。mRight,mBottom这四个值表示的是子view相对于父view的位置。
以下我贴出我画的图看一下就明确了。
如图,黄色区域是我们的父view,而中间的深色的区域就是我们的子view。
所以对于这个View来说,我列出它相对于父view的各个值是怎样计算和相关函数:
mLeft,mTop,mRight,mBottom:
view.getLeft()——mLeft:子View左边界到父view左边界的距离
public final int getLeft() {
return mLeft;
}
view.getTop()——mTop:子View上边界到父view上边界的距离
view.getRight()——mRight:子View右边界到父view左边界的距离
view.getBottom()——mBottom:子View下边距到父View上边界的距离
视图宽高:
视图宽度 view.getWidth();子View的右边界 - 子view的左边界。
public final int getWidth() {
return mRight - mLeft;
}
视图高度 view.getHeight() ;子View的下边界 - 子view的上边界。
public final int getHeight() {
return mBottom - mTop;
}
測量宽高:
view.getMeasuredWidth();measure过程中返回的mMeasuredWidth
public final int getMeasuredWidth() {
return mMeasuredWidth & MEASURED_SIZE_MASK;
}
view.getMeasuredHeight();measure过程中返回的mMeasuredHeight
public final int getMeasuredHeight() {
return mMeasuredHeight & MEASURED_SIZE_MASK;
}
最后介绍一下getWidth/Height和getMeasuredWidth/Height的差别:
getWidth,和getLeft等这些函数都是View相对于其父View的位置。而getMeasuredWidth,getMeasuredHeight是測量后该View的实际值(有点绕,以下摘录一段jafsldkfj所写的Blog中的解释).
实际上在当屏幕能够包裹内容的时候,他们的值是相等的。仅仅有当view超出屏幕后,才干看出他们的差别:
getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。
当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的大小
在计算子View在父View中的位置时,主要就是应用上面这几个函数。以下就来看看怎样去重写onLayout。
onLayout:
对于重写onLayout的思路和重写onMeasure同样:
假设仅仅须要測量单个View。则单独測量它自己即可。假设须要測量的View其下还有子View,则须要測量其全部的子View。
并传递到onlayout( l, t, r, b )中;
剩下的任务就仅仅须要知道它的mLeft值。mTop值。加上长、宽值即可了。
长宽值非常easy,使用getWidth/Height和getMeasuredWidth/Height都能够。
因为这个View须要居中显示。剩下的问题就是怎样计算该View的mLeft值和mTop值。我的思路例如以下:
r(父View的mRight) = mLeft + width + mLeft(由于左右间距一样)
b(父View的mBottom) = mTop + height + mTop(由于上下间距一样)
我的代码例如以下:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { // 循环全部子View
for (int i=0; i<getChildCount(); i++) {
View child = getChildAt(i);
// 取出当前子View长宽
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight(); // 计算当前的mLeft和mTop值(r,b为传递进来的父View的mRight和mBottom值)
int mLeft = (r - width) / 2;
int mTop = (b - height) / 2; // 调用layout并传递计算过的參数为子view布局
child.layout(mLeft, mTop, mLeft + width, mTop + height);
}
}
布局文件例如以下:
<com.gxy.text.CostomViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#eee999" > <Button
android:text="ChildView"
android:layout_width="200dip"
android:layout_height="200dip"
android:background="#333444"
android:id="@+id/textView2" />
</com.gxy.text.CostomViewGroup>
效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="400" height="600" alt="">
总结:
onMeasure和onLayout的大致总结完了,在自己定义View的时候最关键的是onLayout,由于不管你怎样Measure这个View的大小,最后的决定权永远在onLayout手中,onLayout会决定详细View的大小和位置。当然onMeasure也非常重要,有的情况控件的宽高不确定或者须要自己定义,这时候须要我们人工Measure它。
而在复杂的自己定义View时。非常多计算也须要在onMeasure中完毕。而且些值会记录下来在onLayout中又一次使用(个人理解,欢迎指正)。
写onMeasure和onLayout的时候仅仅是想自己总结一下。整理一下思路。由于网上有太多写的好了。这里推荐一下qinjuning这位大神的blog。关于View的内容他总结的相当全面和深入。
尽管有非常好的了。但我还会坚持自己总结一遍,接下来的计划是写一个略微复杂点的小样例。将onMeasure和onLayout结合起来(已经写完了,链接例如以下:ANDROID自己定义视图——仿瀑布布局)。
之后深入的研究一下View和ViewGroup的源代码,总结一下LayoutParams,LayoutInflater等简单经常使用的知识点。了解一下View的绘制刷新流程等等等。
。。
太多不会的了,慢慢来吧。
ANDROID自己定义视图——onLayout源代码 流程 思路具体解释的更多相关文章
- Android自己定义视图(一):带下划线的TextView
package com.francis.underlinetextviewtest; import android.content.Context; import android.content.re ...
- ANDROID定义自己的看法——onMeasure,MeasureSpec源代码 过程 思考具体解释
一个简短的引论: 在他们的定义view什么时候,其实很easy,只需要知道3: 1.測量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGrou ...
- 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...
- ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...
- android自己定义控件系列教程----视图
理解android视图 对于android设备我们所示区域事实上和它在底层的绘制有着非常大的关系,非常多时候我们都仅仅关心我们所示,那么在底层一点它究竟是怎么样的一个东西呢?让我们先来看看这个图. w ...
- android 自己定义ViewGroup实现可记载并呈现选择的ListView
转载请注明出处:王亟亟的大牛之路 之前也做过一些用TextView之类的记录ListView选项的东西.可是总认为好难看.发现个不错的实现就贴给大家. 项目文件夹 执行效果: 自己定义视图: @Tar ...
- Android自己定义控件:进度条的四种实现方式
前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://down ...
- Android自己定义控件系列五:自己定义绚丽水波纹效果
尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...
- Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象.与Google原生AOSP有些许差异.请读者知悉. ...
随机推荐
- HTTP协议中的1xx,2xx,3xx,4xx,5xx状态码分别表示什么,列举常见错误码及含义
转自:http://m.blog.csdn.net/blog/u013857407/21741847 HTTP协议状态码,是指在HTTP协议运作中由客户端发出请求连接,服务端建立连接,客户端发出HTT ...
- Linux内核中的list用法和实现分析
这些天在思考知识体系的完整性,发现总是对消息队列的实现不满意,索性看看内核里面的链表实现形式,这篇文章就当做是学习的i笔记吧.. 内核代码中有很多的地方使用了list,而这个list的用法又跟我们平时 ...
- ORACLE 两个表或两个结果集的数据对比常用的函数
假设有两个表A,B,都只有一个字段PHONE 1,MINUS SELECT PHONE FROM A MINUS SELECT PHONE FROM B; 相当于用结果集A减去结果B得出的结果 ...
- AndroidAutoLayout 屏幕适配
https://github.com/hongyangAndroid/AndroidAutoLayout
- 继承ViewGroup研究(汇总) 一、二、三
转载过来:为一.二.三版本. 仅供参考: 继承ViewGroup研究(1) --简介和一个小Demo 又翻开一个新篇章了,哈哈,上一回学习的是继承View,关于继承View个人感觉不是那么完美,做技术 ...
- JAVA代码静态检测之PMD
今天再次想启动Java代码静态检测工具的利用问题,主要再次尝试用了PMD,发现不少代码编码规范问题和好的代码建议,并学到不少自己之前没有注意到的Java方便的基础知识,感觉很不错,把相关明白的好的规则 ...
- oracle解锁表
select b.owner,b.object_name,a.session_id,a.locked_mode,c.serial#,c.sid||','||c.serial# from v$locke ...
- Netfilter-packet-flow.svg
调试网络的方法:(Debugging the kernel using Ftrace) $ watch -n1 -d sudo cat /proc/net/snmp$ watch -n1 -d su ...
- dataGuard client 自动切换
使用dataguard作为HA方案,要解决的一个问题在于:后台数据库发生了切换,client连接如何做到自动切到新的primary数据库上? 如果做通用的方案,需要客户端自己提供自动重连的能力,这点大 ...
- 桂林电子科技大学出校流量控制器Android版1.0.0
每次玩游戏的时候,总是要开着电脑挂着出校控制器,真是浪费国家资源啊,,, 突然想起学校有个开放流量的网页,无奈UC等浏览器真是尝试优化js脚本啊,挂在后台,不到几分钟就掉线了,悲剧啊~~~ 还好And ...