Android 自定义 view(四)—— onMeasure 方法理解
前言:
前面我们已经学过《Android 自定义 view(三)—— onDraw 方法理解》,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法
推荐文章:
http://blog.csdn.net/a396901990/article/details/36475213?utm_source=tuicool&utm_medium=referral
onMeasure 作用
(1)一般情况重写onMeasure()方法作用是为了自定义View尺寸的规则,如果你的自定义View的尺寸是根据父控件行为一致,就不需要重写onMeasure()方法
(2)如果不重写onMeasure方法,那么自定义view的尺寸默认就和父控件一样大小,当然也可以在布局文件里面写死宽高,而重写该方法可以根据自己的需求设置自定义view大小
认识 onMeasure
(0)onMeasure (int widthMeasureSpec, int heightMeasureSpec)是view自己的方法
(1)onMeasure 方法简单的理解就是是用于测量视图的大小,主要是用来测量自己和内容的来确定宽度和高度
(2)onMeasure有两个参数 ( int widthMeasureSpec, int heightMeasureSpec),该参数表示控件可获得的空间以及关于这个空间描述的元数据.
(3)widthMeasureSpec和heightMeasureSpec这两个值通常情况下都是由父视图经过计算后传递给子视图的,说明父视图会在一定程度上决定子视图的大小。
认识 MeasureSpec
在测量自定义view的大小之前,我们需要认识一个类MeasureSpec,它封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求 MeasureSpec由size和mode组成。
specMode一共有三种类型,如下所示:
1. EXACTLY
表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,简单的说(当设置width或height为match_parent时,模式为EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)
2. AT_MOST
表示子视图最多只能是specSize中指定的大小。(当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)
3. UNSPECIFIED
表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。
onMeasure 之我见示意图
onMeasure 实践练习
要去自定义控件上面写一段文字,根据宽度
/**
* Created by yishujun on 16/6/5.
*/
public class YView extends View {
private Context mContext;
//定义一个paint
private Paint mPaint;
private String mText = "测试文字,自定义view";
//绘制时控制文本绘制的范围
private Rect mBound;
public YView(Context context) {
this(context, null);
}
public YView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public YView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
mBound = new Rect();
mPaint = new Paint();
mPaint.setTextSize(60);
mPaint.getTextBounds(mText, 0, mText.length(), mBound);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
mPaint.setColor(Color.RED);
canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
/**
* 比onDraw先执行
* <p>
* 一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
* 一个MeasureSpec由大小和模式组成
* 它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;
* EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;
* AT_MOST(至多),子元素至多达到指定大小的值。
* <p>
* 它常用的三个函数:
* 1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
* 2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
* 3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
Log.e("YView", "---minimumWidth = " + minimumWidth + "");
Log.e("YView", "---minimumHeight = " + minimumHeight + "");
int width = measureWidth(minimumWidth, widthMeasureSpec);
int height = measureHeight(minimumHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int defaultWidth, int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
Log.e("YViewWidth", "---speSize = " + specSize + "");
switch (specMode) {
case MeasureSpec.AT_MOST:
defaultWidth = (int) mPaint.measureText(mText) + getPaddingLeft() + getPaddingRight();
Log.e("YViewWidth", "---speMode = AT_MOST");
break;
case MeasureSpec.EXACTLY:
Log.e("YViewWidth", "---speMode = EXACTLY");
defaultWidth = specSize;
break;
case MeasureSpec.UNSPECIFIED:
Log.e("YViewWidth", "---speMode = UNSPECIFIED");
defaultWidth = Math.max(defaultWidth, specSize);
}
return defaultWidth;
}
private int measureHeight(int defaultHeight, int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
Log.e("YViewHeight", "---speSize = " + specSize + "");
switch (specMode) {
case MeasureSpec.AT_MOST:
defaultHeight = (int) (-mPaint.ascent() + mPaint.descent()) + getPaddingTop() + getPaddingBottom();
Log.e("YViewHeight", "---speMode = AT_MOST");
break;
case MeasureSpec.EXACTLY:
defaultHeight = specSize;
Log.e("YViewHeight", "---speSize = EXACTLY");
break;
case MeasureSpec.UNSPECIFIED:
defaultHeight = Math.max(defaultHeight, specSize);
Log.e("YViewHeight", "---speSize = UNSPECIFIED");
// 1.基准点是baseline
// 2.ascent:是baseline之上至字符最高处的距离
// 3.descent:是baseline之下至字符最低处的距离
// 4.leading:是上一行字符的descent到下一行的ascent之间的距离,也就是相邻行间的空白距离
// 5.top:是指的是最高字符到baseline的值,即ascent的最大值
// 6.bottom:是指最低字符到baseline的值,即descent的最大值
break;
}
return defaultHeight;
}
}
第一组:
第二组:
Android 自定义 view(四)—— onMeasure 方法理解的更多相关文章
- Android自定义View的实现方法,带你一步步深入了解View(四)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回 ...
- 【转】Android自定义View的实现方法,带你一步步深入了解View(四)
原文网址: 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到 ...
- Android 自定义View 四个构造函数详解
https://blog.csdn.net/zhao123h/article/details/52210732 在开发android开发过程中,很多人都会遇到自定义view,一般都需要继承自View类 ...
- Android 自定义View (四) 视频音量调控
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24529807 今天没事逛eoe,看见有人求助要做一个下面的效果,我看下面一哥们说 ...
- android 自定义view 前的基础知识
本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
- Android自定义View(三、深入解析控件测量onMeasure)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51490283 本文出自:[openXu的博客] 目录: onMeasure什么时候会被调用 ...
- Android自定义视图四:定制onMeasure强制显示为方形
这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...
- 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...
随机推荐
- 转载:Android自动化测试- 自动获取短信验证码
前言:android应用的自动化测试必然会涉及到注册登录功能,而许多的注册登录或修改密码功能常常需要输入短信验证码,因此有必要能够自动获得下发的短信验证码. 主要就是实时获取短信信息. android ...
- Tornado学习笔记12 tornado.httpserver-.非阻塞的Http服务器
是一个非阻塞的,单线程的Http 服务器. 一般地,应用程序很少与HttpServer类直接交互,除非在进程开始时启动服务时(甚至在使用tornado.web.Applicaiton.listen时也 ...
- ZeroMQ接口函数之 :zmq_disconnect - 断开一个socket的连接
ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_disconnect zmq_disconnect(3) ØMQ Manual - ØMQ/3.2.5 Name ...
- 【python+mysql】在python中调用mysql出问题 ImportError: No module named MySQLdb.constants
遇到如下异常: File "C:\Users\Neil\PycharmProjects\ScrapyDouban\book\book\database.py", line 4, i ...
- CSS实现元素水平/垂直居中的方法
首先,我们来了解水平居中,它有很多种方法,我们暂时先来了解其中的几种: 1. 在实现方案中,我们最熟悉的莫过于给元素定义一个宽度,然后使用margin: 1 2 3 4 body{ wi ...
- jQuery触发a标签点击事件-为什么不跳转
今天开发发现 使用jQuery触发a标签的点击事件,当前的样式发生了变化,可是没有跳转,为什么? 百度后找到的解决方案: <a onclick="hanle()" href= ...
- baiduMap
1.把百度地图定位API(下载地址:http://lbsyun.baidu.com/sdk/download?selected=location),里面的lib福祉到自己的项目中 2,进行相关配置(官 ...
- 视频直播点播nginx-rtmp开发手册中文版
2016年8月18日12:42:35 参照官方文档https://github.com/arut/nginx-rtmp-module/wiki/Directives 请注意这个是粗翻译版,仅供参考,不 ...
- 获取打开指定Action的所有应用包名
获取打开指定功能的所有应用:发消息,分享等等. 如打开网页,下面代码即可查看所有的浏览器 //查找所有浏览器 private void queryPackage() { PackageManager ...
- iOS相关笔记
#协议[1] [2] @property (nonatomic, assign) id<EveryFrameDelegate> delegate; 表明,这个delegate是一个需要实现 ...