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

  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 definedsetMeasuredDimension(mDefaultWidth, mDefaultHeight)} else if (widthSpecMode == MeasureSpec.AT_MOST) {// set default width value and calculated `heightSpecSize` as heightsetMeasuredDimension(mDefaultWidth, heightSpecSize)} else if (heightSpecMode == MeasureSpec.AT_MOST) {// set calculated `widthSpecSize` as width and default heightsetMeasuredDimension(widthSpecSize, mDefaultHeight)}
}

简单理解MeasureSpec.AT_MOST就是你给折线图的layout_width或者layout_height设置了wrap_content,系统不知道精确的宽度、高度是多少的时候的一个标记。如果有具体的50dp100dp的时候,这个标记的值为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 = 0var 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 - paddingRightvar heightWithoutPadding = height - paddingTop - paddingBottomvar 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):

本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/5470984.html,如需转载请自行联系原作者

Android自定义视图四:定制onMeasure强制显示为方形相关推荐

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

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

  2. android 自定义绘画,【整理】Android 自定义视图之画图

    Android 自定义视图之画图 首先简单的一个画矩形的例子 public class DrawView extends View { public DrawView(Context context) ...

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

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

  4. android自定义视图添加布局文件,android – 添加自定义视图作为XML布局的视图

    方案如下: 我有一个活动RunTrainingWorkoutsView,它使用XML布局_run_workout.xml_,其中一些标签由CountDownTimer更新.工作正常- 现在,除了每秒通 ...

  5. android 设置画布大小设置,Android自定义视图:设置画布大小以包装位图

    我有一个自定义视图,其中包含Canvas.我正在使用此画布在其上显示位图,然后我可以在触摸时绘制位图.当我加载位图时,它比视图大小大得多,我看不到整个位图(它是用相机拍摄的照片).我尝试创建缩放的位图 ...

  6. Android自定义View——自由定制优惠券背景

    1.功能介绍 现在购物类的APP真的是数不甚数啊,经常可以在这些APP中看到优惠券的影子,今天我们就来实现一下优惠券的背景效果.实际开发中,如果我们想偷懒,直接用一张背景图作为优惠劵背景就OK了,今天 ...

  7. android自定义游戏闯关图,Android自定义View(四) -- Canvas

    本文计划根据HenCoder系列文章进行学习,所以代码风格及博文素材可能会摘自其中. 1 范围裁切 范围裁切有两个方法: clipRect() 和 clipPath().裁切方法之后的绘制代码,都会被 ...

  8. android 使用自定义组件,Android自定义组件开发之onMeasure使用

    一.自定义组件造成其他组件的隐藏 我们在开发过程中往往现有的组件无法满足我们的需求,所有我们需要去自定义组件来实现我们的需求,在实现的过程中总会有各种问题,这里我们讨论一下onMeasure的使用,首 ...

  9. Android自定义View(四)——仿Android5.0波纹效果

    项目源码比较简单,直接看帖的代码就可以了. 说实话,我是真没有去看RippleView的源码,只是从表面看到它的效果,所以产生了一点思路,所以功能很有局限性,而且用起来也比较复杂,大家且看且喷就好^_ ...

最新文章

  1. Git Submodule管理项目子模块
  2. 如何使用jquery_好程序员web前端学习路线分享jQuery学习技巧
  3. 网站QQ全屏PHP代码,QQ技术导航升级版 超级导航美化版带后台版 PHP源码
  4. python构建知识库_使用Mediawiki构建个人知识库
  5. 日志进程redo thread
  6. w7 mysql不启动_Win7安装mysql5.7服务无法启动没有任何报错信息处理:
  7. 第一序列任小粟的能力_末世废土文—《第一序列》:“这世间,已经不需要齐天大圣了。”...
  8. python 立体匹配_手写双目立体匹配 SGM 算法(下)
  9. java rtmp录制视频_red5-rtmp-push
  10. 让程序员崩溃的一句话。。。
  11. 一个小小的签到功能,到底用MySQL还是Redis?
  12. Excel 单元格 自定义格式详解
  13. 【生物信息学】外显子测序的原理及优缺点
  14. 用Django2.1开发易班联合登录
  15. 解决阿里云不能使用yum问题
  16. CLH(Craig, Landin, and Hagersten locks)机制
  17. 程序员专用表情包,拿走不谢!
  18. python笔试编程题_Python自动化测试笔试面试时常见的编程题
  19. sqoop export hive数据同步到oracle的用法
  20. win10更新失败 无法安装 Windows,因为这台电脑的磁盘布局不受UEFI固件支持

热门文章

  1. Oracle RAC环境下如何更新patch(Rolling Patch)
  2. Nginx配置中文域名
  3. html5模拟keyup事件
  4. 离开页面前显示确认提示对话框(兼容IE,firefox) = how to Catch Win...
  5. HTML5 localStorage本地儲存
  6. Base62x比Base64的编码速度更快吗?
  7. Python3-面向对象编程
  8. laravel 是怎么做到运行 composer dump-autoload 不清空 classmap 映射关系的呢?
  9. 雅虎可能被Verizon收购 阿里巴巴也可能成为接盘者
  10. Storm【配置项】 - 详细解释