透彻理解自定义View

本文提供:

1.原理解析(不是源码解析,为了不使读者困惑)

2.实战演练


measure spec

简单讲一下,就是32位的int值,前2位用来存储Mode(UNSPECIFIED,EXACTLY,AT_MOST),后30位用来存储Size。

我们measure的核心就是:父view group的measure spec+子view的layout params=子view的measure spec


measure(分为两种1.view group 2.view)

view:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

可以看到,MeasureSpec参数是view group给你的,而这个MeasureSpec参数,view group中会替你去计算,先不用关注这一点。

你需要关注的点是:

当你给一个view设置wrap_content的时候,效果等同于match_parent!可是TextView,ImageView为什么在指定wrap_content的时候,没有出现这个现象?原因在于他们自身已经处理好了。所以我们来进行实战演练

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
    int width = widthSpecSize;
    int height = heightSpecSize;
    if (widthSpecMode == MeasureSpec.AT_MOST) {
        width = 100;
    }
    if (heightSpecMode == MeasureSpec.AT_MOST) {
        height = 100;
    }
    setMeasuredDimension(width,height);
}

代码很简单,意思就是如果是wrap_content,直接设置100sp!我们直接定死了100!

所以这里我们可以再思考下TextView的测绘!没有什么好说的了!他肯定是计算文字的宽高啊!可是文字的宽高又咋计算?

这里给你剧透一下

  1. if (heightMode == MeasureSpec.EXACTLY)  
  2.     {  
  3.         height = heightSize;  
  4.     } else  
  5.     {  
  6.         mPaint.setTextSize(mTitleTextSize);  
  7.         mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
  8.         float textHeight = mBounds.height();  
  9.         int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());  
  10.         height = desired;  
  11.     }  

(else代表wrap_content情况)

这样一个api,你只需要调用getTextBounds就能把画出这一段字所需要的面积放到mBounds中(即我们预定义的矩形中)

这样你就可以根据矩形去获取文字的高了!宽也是同理!


view group:

他是这样的:

递归所有孩子,对每个孩子进行计算MeasureSpec的操作,传给孩子,孩子进行测量

测量自身

所以,我们只需要重点关注一下这个“计算”工作即可。

先给你一下伪代码

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) [

    for(View child :所有子view) {

        measureChild(child,int widthMeasureSpec, int heightMeasureSpec);

    }

}

protected void measureChild(View child,int parentWidthMeasureSpec, int parentHeightMeasureSpec) {

    child.getLayoutParams

    计算(parentMeasure,childLayoutParams)

    child.measure(计算的结果)

}

这个计算,前面有说,就是

父view group的measure spec+子view的layout params=子view的measure spec

UNSPECIFIED,EXACTLY,AT_MOST的含义忘说了,其实是这样的:

UNSPECIFIED用于系统内部测量,可不用关注;

EXACTLY顾名思义,代表你的宽高已经确定了,对应match_parent和设置固定值比如100dp这样的情况。

AT_MOST,对应wrap_content,别忘了正常情况下wrap_content等同于match_parent即可。

我们根据父view group的measure spec和子view的layout params,可以得出如下结论

如果你的子view是固定值,那么毫无疑问,你的measure spec的mode为EXACTLY,size为child size,毋庸置疑。

如果你的子view是match_parent,那么也自然可以知道,你的大小肯定也是parent的大小,而你的mode肯定也得跟parent的一样!比如parent是EXACTLY,你也就是EXACTLY;parent是AT_MOST(即wrap_content),那你也是AT_MOST。

如果你的子view是wrap_content的,那么也自然可以得出,他是parentSize,不管什么情况下都是AT_MOST模式。

(这里再讲解下AT_MOST,其实你可以认为是包住的意思,如果你不指定,就是最大,如果你指定了,包住你指定的即可。默认 情况下系统是没有指定的,所以AT_MOST可以认为是尽可能的大。而且AT_MOST和EXACTLY最明显的区别就是,前者的大小是未确定的,后者是已确定的。理解了这句话你回过头去看,可能会很轻松的就理解了上面得出的结论)

好了,计算讲完了。讲父view group的自己的测量。

我们拿LinearLayout实战演练下,简单讲下思路:

其实也是按你的经验来!

肯定是先measure所有孩子

但是你懂的,他是排在一个方向的!

比如竖直

你需要计算竖直方向上的总长度吧?

总长度包含啥?自高,padding,margin

不就好了?

至于水平?你还用算?


至此,measure讲完!


layout

其实和measure一个套路啊!

你只需要重点关注两个方法,onLayout和layout。onLayout是确定所有子元素的位置,layout是确定子元素自身的位置。所以你有没有印象了,或许在你曾经自定义view的时候,layout(...)一下你就成功的放置好了你的位置。

再拿LinearLayout举例子。它是怎么放的?

线性放的,这其中会有一系列的规则,比如margin等。

我们先放放看!

比如加一个孩子进去。

首先measure吧!然后你在layout中就可以获取测量的宽高了!用getMeasuredWidth这个api就可以!那么你岂不是已经知道了!直接0,0 然后是0+width,0+height两个坐标!那么就定位好了。直接调用layout(0,0,0+width,0+height)即可!

如果有个top margin比如10又是怎样的情况?

直接layout(0,10,0+width,10+height)就可以了!就是这么简单!

所以如果你想自定义view group的话,指定自己的规则,根据宽高,自己去layout即可!


draw

最简单了!源码也简单,使用也简单!

源码:

1.绘制背景

2.绘制自己

3.绘制孩子

4.绘制装饰

使用:

这个api太多了,什么drawCircle,drawArc,draw。。。只是一个api的积累罢了!


好了,趁着手还热着,赶紧去看看鸿洋或者启舰的自定义view实战系列吧!!!从此自定义view在你眼里再也没有任何秘密!~

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值