这个系列是老外写的,干货!翻译出来一起学习。如有不妥,不吝赐教!

  1. Android自定义视图一:扩展现有的视图,添加新的XML属性
  2. Android自定义视图二:如何绘制内容
  3. Android自定义视图三:给自定义视图添加“流畅”的动画
  4. Android自定义视图四:定制onMeasure强制显示为方形



上一篇开发之后的效果如上图。不过看着这张图,需要注意的不是我们自定义视图展示了什么,而是这个视图的大小和位置。你会看到这个折线图有一个特定的大小(size)。这个size是怎么定的呢?现在的代码是使用了一个竖直方向的LinearLayout,折线图和他下面的TextView使用layout_weight属性平分了他们所在的LinearLayout的高度。那么如果我们删掉了TextView和全部的layout_weight,并把折线图的高度设定为wrap_content会发生什么呢?



是的,以上修改之后整个的图就变成了这样。虽然使用了wrap_content的高度,但是效果是填满了整个LinearLayout。这就是View的默认布局行为,但是,如果我们要改变一下呢?

View的Layout

自定义视图显示在屏幕上一共分三步:measure(测量),layout(布局),draw(绘制)。基本上一个自定义视图在测量这一步计算大小,之后可以通过getMeasureWidthgetMeasureHeight得到View的宽度和高度。在布局计算这个自定义视图的左上和右下坐标以及实际的宽度和高度,最后根据以上layout步骤获得的数据调用onDraw方法把View绘制在屏幕上。

所以要修改size,也就是自定义视图中修改默认的行为,就需要override onMeasure()方法。一般的通用做法是:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) var widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)
var widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)
var heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)
var heightSpecSize = MeasureSpec.getSize(heightMeasureSpec) if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
// set default width and height values you defined
setMeasuredDimension(mDefaultWidth, mDefaultHeight)
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
// set default width value and calculated `heightSpecSize` as height
setMeasuredDimension(mDefaultWidth, heightSpecSize)
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
// set calculated `widthSpecSize` as width and default height
setMeasuredDimension(widthSpecSize, mDefaultHeight)
}
}

简单理解MeasureSpec.AT_MOST就是你给折线图的layout_width或者layout_height设置了wrap_content,系统不知道精确的宽度、高度是多少的时候的一个标记。如果有具体的50dp, 100dp的时候,这个标记的值为MeasureSpec.EXACTLY。一般,一个view的宽度、高度只有这两种标记。

View的宽、高度测量分别处理三种情况:

  1. 如果宽、高度都是AT_MOST的时候,宽度和高度设置为默认值。
  2. 宽度为AT_MOST高度不是的时候,宽度设置为默认值,高度设置为测量的值heightSpecSize
  3. 宽度为精确值,高度为AT_MOST的时候,宽度设置为widthSpecSize ,高度设置为默认值。

而我们这里则是意外的简单。因为要设置为正方形,所以使用宽度和高度中相对较小的那个值来作为宽、高度共同的值就可以了:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) var size = 0 var width = getMeasuredWidth()
var height = getMeasuredHeight() if (width > height) {
size = height
} else {
size = width
} setMeasuredDimension(size, size)
}

如前文所说,我们要把折线图这个自定义视图设置为正方形。所以,不管测量的Mode是如何的,只要用宽、高中的最小值就可以了。

而上面说到的layout部分,对于有子view的`View`比较有用,
也就是说对于继承自`ViewGroup`的`View`来说比较有用。
我们的折线图知识一个单纯的不能更单纯的`View`。

我们前面在onDraw方法使用的getWidth()getHeight()onMeasure()方法中都是不可用的。因为这个时候正在计算宽、高度。在这个方法里只能取到getMeasuredWidth()getMeasuredHeight()

override onMeasure方法就一定要在最后调用setMeasuredDimension 方法。调用setMeasuredDimension 方法是告诉父view当前view的测量高度是多少。如果不调用这个方法的话会抛异常。

修改之后的布局,宽度match_parent,高度wrap_content不必要的属性都略掉了

<RelativeLayout>

    <LinearLayout>
<Button android:text="walking" />
<Button android:text="Running" />
<Button android:text="Cycling" />
</LinearLayout> <demo.customview.customviewdemo.Views.SquareLineChartView
android:layout_width="match_parent"
android:layout_height="wrap_content" /> </RelativeLayout>

效果:

支持任意宽高比例

一个正方形的View已经非常实用了。比如继承ImageView之后像上面一样overrideonMeasure()方法就可以得到一个一直都是正方形显示的View。那么,既然我们已经支持了宽、高1:1了,为什么不支持任意的宽高比呢。

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) var width = getMeasuredWidth()
var height = getMeasuredHeight()
var widthWithoutPadding = width - paddingLeft - paddingRight
var heightWithoutPadding = height - paddingTop - paddingBottom var maxWidth = (heightWithoutPadding * RATIO).toInt()
var maxHeight = (widthWithoutPadding / RATIO).toInt() if (widthWithoutPadding > maxWidth) {
width = maxWidth + paddingLeft + paddingRight
} else {
height = maxHeight + paddingTop + paddingBottom
} setMeasuredDimension(width, height)
}

上面的代码就可以支持任意的宽高比了。看看效果(比例7:3):

Android自定义视图四:定制onMeasure强制显示为方形的更多相关文章

  1. Android自定义视图三:给自定义视图添加“流畅”的动画

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  2. Android自定义视图二:如何绘制内容

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  3. Android自定义视图一:扩展现有的视图,添加新的XML属性

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  4. 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解

    原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...

  5. ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解

    简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...

  6. 【转】ANDROID自定义视图——onLayout源码 流程 思路详解

    转载(http://blog.csdn.net/a396901990) 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局 ...

  7. Android自定义视图教程

    Android自定义视图教程 Android的UI元素都是基于View(屏幕中单个元素)和ViewGroup(元素的集合),Android有许多自带的组件和布局,比如Button.TextView.R ...

  8. 自定义View(四),onMeasure

    转自:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--on ...

  9. ANDROID自定义视图——onMeasure流程,MeasureSpec详解

    简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局——onLayout():决定View在ViewGroup中的位置 3. ...

随机推荐

  1. jquery关于attr和prop的差异

    转自:http://www.jb51.net/article/88068.htm 处理像checkbox,radio和select这样的元素时,经常会发现明明使用了attr设置了selected或ch ...

  2. mybatis进阶--输入映射和输出映射

    我们知道,mapper.xml是我们配置操作数据库的sql语句的地方.其中每个sql语句对应着一个方法,每个方法都有自己的输入输出参数类型.那么这些类型都是怎么配置的呢?今天我们来一起学习下. 输入映 ...

  3. 778A String Game

    A. String Game time limit per test 2 seconds memory limit per test 512 megabytes input standard inpu ...

  4. iOS.FBTweak

    FBTweak的源码分析 1. FBTweak提供了以下功能 A): 可以动态的修改某个变量的值,这些变量的类型包括: ... B): 可以以plist的形式将Tweak以key-value的形式进行 ...

  5. RNA测序相对基因表达芯片有什么优势?

    RNA测序相对基因表达芯片有什么优势? RNA-Seq和基因表达芯片相比,哪种方法更有优势?关键看适用不适用.那么RNA-Seq适用哪些研究方向?是否您的研究?来跟随本文了解一下RNA测序相对基因表达 ...

  6. Luogu 3421 [POI2005]SKO-Knights - Exgcd

    Description 给出一个骑士的 $N$种 中行走的方式 $(a_i, b_i)$, 可以使骑士的坐标$(-a,-b)$或$(+a,+b)$. 我们需要找出 第二个骑士的 两种行走方式 $(c_ ...

  7. NOIP需要掌握的内容(大致

    1.排序算法(快排.选择.冒泡.堆排序.二叉排序树.桶排序)2.DFS/BFS 剪枝 哈希表3.树   ①遍历   ②二叉树   ③二叉排序树(查找.生成.删除)   ④堆(二叉堆.左偏树.堆排序)  ...

  8. [Robot Framework] 调用ExcelLibrary

    安装ExcelLibrary for Robot Framework 参考 : http://navinet.github.io/robotframework-excellibrary/ 打开wind ...

  9. [Robot Framework] 如何在Setup中用Run Keywords执行多个带参数的关键字

    参考文档:http://www.howtobuildsoftware.com/index.php/how-do/bZ7q/robotframework-setup-teardown-robot-fra ...

  10. MySQL中varchar与char区别

    MySQL中varchar与char区别(转) MySQL中varchar最大长度是多少? 一. varchar存储规则: 4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字 ...