android自定义控件系列教程----视图的测量和布局

前面说点什么

当我们的一个视图界面绘制在android屏幕上面的时候其实都必须经过这几步measure、 layout、draw这几个阶段,我们可以在view类里面看到这几个函数,然后里面有几个函数是onmeasure、onlayout、ondraw这几个函数是我们重写控件需要注意的这几个函数,下面我们就来讲讲这几个函数的功能和作用。

onMeasure

正如这个函数的名子一样就是测量,所有的图示其实系统在绘制之前都不知道它到底有多大的,所以在很多时候我们在初始化界面oncreate的时候直接去调用一个View的getwitfh或者getheight都获取不到,因为在oncreate的时候系统还没有统一的发出排版请求,说到了这里我们就仔细来分析一下这个onmeasuer函数到底要注意些什么,他回调给我们的参数是MeasureSpec,保存的是父亲的属性。MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小,specMode记录的是规格。specMode一共有三种类型,如下所示:

1. EXACTLY

表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。

2. AT_MOST

表示子视图最多只能是specSize中指定的大小,开发人员应该尽可能小得去设置这个视图,并且保证不会超过specSize。系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。

3. UNSPECIFIED

表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。

关于测量的问题可以看看LinearLayout、RelativeLayout这些是怎么实现的,加深理解。

onLayout

通过前面的onMeasure我们计算出了这个控件所占的宽高,那么我就就需要在这个onlayout函数里面去告诉系统它应该摆放在屏幕的哪个位置,由于我们基本上所有的控件都回去继承ViewGroup我们仔细的来研究一下它的onLayout方法吧。

   @Override
    protected abstract void onLayout(boolean changed,
            int l, int t, int r, int b);

可以看它是一个抽象的方法,所以我们所有的实现类都需要来实现这个方法,自己来告诉系统我们需要怎么去排版我们的界面,像LinearLayout、RelativeLayout等布局,都是重写了这个方法,然后在内部按照各自的规则对子视图进行布局的。由于LinearLayout和RelativeLayout的布局规则都比较复杂,就不单独拿出来进行分析了。

实例讲解

这里我们结合一个例子来讲解上面提到的东西,我们将简单的实现一个垂直的布局。先看看效果吧。

我们要实现的就是一个类似于LinearLayout的垂直布局的容器,好了现在我们直接看代码吧,我把代码都注释在里面。我们还是按规矩来继承一个ViewGroup

public class SimpleVertical extends ViewGroup {

	public SimpleVertical(Context context) {
		super(context);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int totalheight = 0;
		int childcount = getChildCount();
		for (int i = 0; i < childcount; i++) {
			View childView = getChildAt(i);
			if (childView.getVisibility() != GONE) {
				childView.layout(0, totalheight, childView.getMeasuredWidth(), totalheight+childView.getMeasuredHeight()); //设置自己放置的位置
				totalheight+=childView.getMeasuredHeight();//计算高度的开始
			}
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int childCount = getChildCount();
		for (int i = 0; i < childCount; i++) {
			View childView = getChildAt(i);
			if (childView.getVisibility() != GONE) {
				LayoutParams childLp = childView.getLayoutParams(); // 获取layout参数
				int childWidthMeasureSpec = getChildMeasureSpec(
						widthMeasureSpec, getPaddingLeft() + getPaddingRight(),
						childLp.width); // 调用VIewGroup的封装的方法
				int childHeightMeasureSpec = getChildMeasureSpec(
						widthMeasureSpec, getPaddingTop() + getPaddingBottom(),
						childLp.height);
				childView
						.measure(childWidthMeasureSpec, childHeightMeasureSpec); // 最重要的就是告诉自己测量
			}
		}
		// measureChildren(widthMeasureSpec, heightMeasureSpec);
		// 也可以调用ViewGroup这个方法
		super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 记住调用这个方法不然会报错,其实它也是调用的setMeasuredDimension这个方法
	}
}

所有的注释我都写在上面了然后我们来写一个测试的Activity,我直接贴出oncreate里面的代码了。也很简单

<span style="font-size:14px;">SimpleVertical simpleVertical = new SimpleVertical(this);
		for (int i = 0; i < 12; i++) {
			TextView textView = getTextView("android自定义控件系列教程----视图的测量和布局");
			textView.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					Toast.makeText(MainActivity.this, "</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:12px;">android自定义控件系列教程----视图的测量和布局</span></span><span style="font-size:14px;">", 0).show();
				}
			});
			simpleVertical.addView(textView);
		}

		setContentView(simpleVertical);</span>

可以看到我们不但把我们自己写得控件写上了,还给它添加了一个点击事件,点击上去也是没有问题的,这样我们就简单的实现了Linearlayotu的垂直布局了,想要跟深入的理解这里的写法,我的建议是去看Linearlayotu,RelaytiveLayout这一类容器控件的写法。

时间: 2024-10-09 05:54:47

android自定义控件系列教程----视图的测量和布局的相关文章

android自定义控件系列教程----视图

理解android视图 对于android设备我们所看到的区域其实和它在底层的绘制有着很大的关系,很多时候我们都只关心我们所看到的,那么在底层一点它到底是怎么样的一个东西呢?让我们先来看看这个图. 对于整个设备的可见区域而言其实就是我们中间的那个屏幕,从上面的拿个图可以清晰的看到,除了我们的可见区域在它的上下左右都应该有内容,那么在android系统中是怎么控制显示它的位置呢?下面我们来解答这个问题. android如何控制视图的显示位置 我们可以打开view类的源码找到这两个函数 /** *

android自定义控件系列教程----继承ViewGroup实现带阻力效果的可回弹的SrollView

前沿分析: 我为什么要想实现一个这样的回弹呢?因为android都没有支持回弹效果,只有个oversroll的回弹效果,其他的时候都是edgeeffect效果,当我们在哪个地方需要这样的回弹效果我们就直接把我们的控件往这个SrollVIew里面一扔就可以了.其他的都不用管. 主要用到的类讲解: Scroller,主要来辅助我们记录动画和滑动的类,VelocityTracker用来计算滑动阀值就是快速滑动的辅助类,用到的辅助类就这两个,其他的就是测量和布局还有事件的编写了. 效果图 里面的按钮是我

android自定义控件系列教程-----touch事件的传递

前沿: 很久没有写过博客了,因为工作的原因很少有时间写东西了,最近想写一个UI系列的博客,因为我发现这一系列的都很少,而且没有那么系统,这里我想以我自己的观点来阐述一下如何自定义android 控件系列. 自定义控件阐述: 在我的理解里面自定义控件,需要了解到touch事件的传递.分发.拦截机制,Scroller类的运用,andorid 视图的理解,ViewGroup的熟悉,因为我们绝大多的控件都是继承自ViewGroup,还有就是要学会布局测量等. Touch事件的传递 首先我们要了解在and

Android自定义控件系列一:如何测量控件尺寸

测量控件尺寸(宽度.高度)是开发自定义控件的第一步,只有确定尺寸后才能开始画(利用canvas在画布上画,我们所使用的控件实际上都是这样画上去的).当然,这个尺寸是需要根据控件的各个部分计算出来的,比如:padding.文字大小,间距等. 非容器控件的onMeasure 下面我们就来看看如何给非容器控件(即直接extends View)这只尺寸的: 1.@Override 2.protected void onMeasure(int widthMeasureSpec, int heightMea

android自定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件

我们先来看看优酷的控件是怎么回事? 只响应最后也就是最顶部的卡片的点击事件,如果点击的不是最顶部的卡片那么就先把它放到最顶部,然后在移动到最前面来,反复如次. 知道了这几条那么我们就很好做了. 里面的技术细节可能就是child的放置到前面来的动画问题把. 先看看我们实现得效果: 然后仔细分析一下我们要实现怎么样的效果: 我也是放置了一个按钮和两个view在控件上面,只有当控件在最前面也就是最里面的时候才会响应事件. 然后我们就动手来实现这个控件. 我们继承一个ViewGroup并且命名为Exch

android自定义控件系列教程----真正的圆角button来了

前沿: 现在网上随便输入一句圆角button就会出现很多博客和文章提示做这样的一个效果,但是那多半都是xml文件来做的,这样做有个很大的弊端,因为每一次都需要重写xml文件(就连简简单单的修改个按钮的颜色也需要修改).~~为什么呢?因为不修改臣妾做不到啊!!!今天就带大家做一个真正的圆角button,我们还是来看效果吧. 正文干货开始: 很明显我们的按钮的背景就是我们要实现的圆角部分,那么我们情不自禁的想到了setBackground这个方法,看看里面的参数,需要的是一个Drawable,而我们

Android自定义控件系列二:如何自定义属性

上一篇Android自定义控件系列一:如何测量控件尺寸 我们讲了如何确定控件的属性,这篇接着也是讲个必要的知识-如何自定义属性.对于一个完整的或者说真正有实用价值的控件,自定义属性是必不可少的. 如何为控件定义属性 在res/values/attrs.xml(attrs.xml如果不存在,可以创建个)中使用<declare-styleable>标签定义属性,比如我想定义个显示头像的圆形的图片控件(AvatarImageView): 01.<?xml version="1.0&q

Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一)

转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45027641 自定义view/viewgroup要重写的几个方法:onMeasure(),onLayout(),onDraw().(不熟悉的话可以查看专栏的前几篇文章:Android自定义控件系列二:自定义开关按钮(一)). 今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpe

Android自定义控件系列八:详解onMeasure()(二)--利用onMeasure测量来实现图片拉伸永不变形,解决屏幕适配问题

上一篇文章详细讲解了一下onMeasure/measure方法在Android自定义控件时的原理和作用,参看博文:Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一),今天就来真正实践一下,让这两个方法大显神威来帮我们搞定图片的屏幕适配问题. 请尊重原创劳动成果,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45038329,非允许请勿用于商业或盈利用途,违者必究. 使用ImageView会遇到