600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Android中自定义view的onMeasure()方法详谈

Android中自定义view的onMeasure()方法详谈

时间:2024-02-03 06:12:22

相关推荐

Android中自定义view的onMeasure()方法详谈

背景理解MeasureSpecMeasureSpec情况分析结合图例分析总结A little bit of progress every day!Come on!

背景

首先关于自定义view的实现过程我这里就不去实现了,因为这部分总体来说是不难的,自己写个类去继承View,然后实现构造方法,重写onMeasure()方法、onLayout()方法(继承ViewGroup的时候需要重写)和onDraw()方法来实现自定义view。

进入正题:很多时候我们需要自己来确定自定义view的大小,比如某种情况下你需要改变自定义view的大小,这时候你就需要重新测量自定义view的宽/高了,而这就与重写的onMeasure()方法有关系了,所以很关键就是onMeasure()方法里的实现方式了。那么今天给大家写一个该方法的通用写法,可以让自定义view根据设置的宽/高类型(wrap_content或者match_parent),来控制显示的大小。下面跟我来一起实现。

理解MeasureSpec

通过源码可以发现,MeasureSpec参与了View的measure过程。MeasureSpec是干什么的呢?确切来说,MeasureSpec在很大程度上决定了一个View的尺寸规格,之所以说是很大程度上是因为这个过程还受父容器的影响,因为父容器影响View的MeasureSpec的创建过程。在测量过程中,系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,然后再根据这个measureSpec来测量出View的宽/高。

MeasureSpec

MeasureSpec代表一个32位int值,高两位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小。

SpecMode有三类,每一类都表示特殊的含义,如下表所示

情况分析

实际情况中,你在布局文件中引用这个自定义View的时候设置宽和高的时候也就三种情况:

宽/高都设置为了match_parent或者是固定大小宽/高其中一个设置为了wrap_content,另外一个为match_parent或者是固定大小宽/高都设置为了wrap_content

结合图例分析

首先不在onMeasure()方法里写任何代码,就用系统默认的测量来试试看当给自定义view设置不同的宽/高类型后,在布局中是怎么显示的。

代码如下(onMeasure()方法里不写代码):

package com.example.demo.myapplication;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;/*** Created by Administrator on /3/16.*/public class CustomView extends View{Paint paint = null;public CustomView(Context context) {super(context);init();}public CustomView(Context context, AttributeSet attrs) {super(context, attrs);init();}public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/*** 控件初始化,一些初始化设置*/private void init() {paint = new Paint();paint.setStyle(Paint.Style.FILL_AND_STROKE);paint.setColor(Color.BLUE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);// int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);//// int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);// int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);//// if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){// setMeasuredDimension(400, 400);// }else if (widthSpecMode == MeasureSpec.AT_MOST){// setMeasuredDimension(400, heightSpecSize);// }else if (heightSpecMode == MeasureSpec.AT_MOST){// setMeasuredDimension(widthSpecSize, 400);// }}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.RED);// 给自定义View的背景设置成红色,直观的显示view的在不同模式下的大小变化情况}}

这里大家可以看到,我把相关代码注释了。这时候View的大小就是系统自己控制的, 我们不做任何的操作了。

在分析各种情况的时候,我这里发现了一个小技巧,不用运行项目就可以直接的将布局中自定义部分的可视界面根据代码变化也相应的动态变化。通俗点说就是代码变化后,不需要运行项目在移动设备上查看界面,只需要在布局中就能看到变化后的界面效果,这个如何做到的呢?如下:

简单来说,当你的自定义view中onMeasure方法的代码变化后,在布局中可以看到有提示说你的布局构建过时了,这时候就需要重新构建build,点击build就会根据代码的变动做出相对应的修改。而不需要再运行项目重新查看新的界面了,这样的话就方便多了。

当宽/高都是wrap_content的时候,显示如下:

这时候自定义View充满了父布局所在空间。

当宽/高都是match_parent的时候,显示如下:

这时候自定义View充满了父布局所在的空间。

当宽/高都是固定大小的时候,显示如下:

这时候自定义View的大小就是固定的大小了。

很显然上面采用系统默认的测量方式不是我所期望的,我希望的是当自定义View的宽/高为wrap_content的时候可以自己动态的控制view的大小,但是上面的情况下,这时候view是充满父布局的空间的,这显然做不到动态的控制view的显示大小。现在来看第二种情况。

在onMeasure()方法中根据不同的宽/高设置类型来执行对应的操作达到控制view的大小。代码如下:

package com.example.demo.myapplication;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;/*** Created by Administrator on /3/16.*/public class CustomView extends View{Paint paint = null;public CustomView(Context context) {super(context);init();}public CustomView(Context context, AttributeSet attrs) {super(context, attrs);init();}public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/*** 控件初始化,一些初始化设置*/private void init() {paint = new Paint();paint.setStyle(Paint.Style.FILL_AND_STROKE);paint.setColor(Color.BLUE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 获取view宽的SpecSize和SpecModeint widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);// 获取view高的SpecSize和SpecModeint heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){// 当view的宽和高都设置为wrap_content时,调用setMeasuredDimension(measuredWidth,measureHeight)方法设置view的宽/高为400pxsetMeasuredDimension(400, 400);}else if (widthSpecMode == MeasureSpec.AT_MOST){// 当view的宽设置为wrap_content时,设置View的宽为你想要设置的大小(这里我设置400px),高就采用系统获取的heightSpecSizesetMeasuredDimension(400, heightSpecSize);}else if (heightSpecMode == MeasureSpec.AT_MOST){// 当view的高设置为wrap_content时,设置View的高为你想要设置的大小(这里我设置400px),宽就采用系统获取的widthSpecSizesetMeasuredDimension(widthSpecSize, 400);}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.RED);// 给自定义View的背景设置成红色,直观的显示view的在不同模式下的大小变化情况}}

当宽/高都是wrap_content的时候,显示如下:

看这里就是我们自己在代码中设置的400px大小了。

当宽/高都是match_parent的时候,显示如下:

这时候也是充满父布局的空间的。

当宽/高都是固定大小的时候,显示如下:

这时候就是固定的大小显示,也没问题。

当宽/高有一个是wrap_content的时候,显示如下:

可以看到设置的wrap_content是根据代码中设置的大小来进行显示,符合我们的要求。

总结

这里大家应该就差不多清楚了不同模式下的view的显示大小是怎么变化的了。onMeasure()方法中的通用写法如下:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 获取view宽的SpecSize和SpecModeint widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);// 获取view高的SpecSize和SpecModeint heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){// 当view的宽和高都设置为wrap_content时,调用setMeasuredDimension(measuredWidth,measureHeight)方法设置view的宽/高为400pxsetMeasuredDimension(400, 400);}else if (widthSpecMode == MeasureSpec.AT_MOST){// 当view的宽设置为wrap_content时,设置View的宽为你想要设置的大小(这里我设置400px),高就采用系统获取的heightSpecSizesetMeasuredDimension(400, heightSpecSize);}else if (heightSpecMode == MeasureSpec.AT_MOST){// 当view的高设置为wrap_content时,设置View的高为你想要设置的大小(这里我设置400px),宽就采用系统获取的widthSpecSizesetMeasuredDimension(widthSpecSize, 400);}}

这里大家想要设置多大的宽和高,自己可以动态的设置,但是需要设置其类型为wrap_content哦

===========================================================================

A little bit of progress every day!Come on!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。