在发展中,有时会遇到一些要求。布局和控制系统不仅提供使用,以满足我们的发展,所以这一次就行,通常是你自己的自定义布局(ViewGroup)并控制(View)该。我在这里,我们将用一个简单的例子,当他们解释他们的定义ViewGroup基本流程,我希望能帮助朋友不理解这个过程。

首先,我们想要实现的布局图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V6aGlwZW5nMTk5MQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

就这样看起来十分简单,用系统提供的布局就能够实现了这个效果,根本不须要自己定义ViewGroup来实现嘛!!

。只是,假设你自己去尝试一下用系统的布局来做。你就会发现一些问题了。问题1是:要实现各个view错开的效果,就必须为他们设置不同的固定外边距參数。这样可能带来的问题就是:不同手机。显示效果可能会不一样。也就是适配问题!问题2是:假设想要增加的View多了,还须要自己计算每一个View的外边距參数。非常坑爹,再说,这里主要是解说自己定义ViewGroup的基本流程,所以,样例越简单,也就越好理解了!

首先,我们能够自己定义自己ViewGroup想要的属性;这里我为ViewGroup定义了两个属性,horizontal_spacing(布局中的view的水平间距)和vertical_spacing(布局中的View的垂直间距);另外,还定义了一个布局參数的属性,layout_vertical_spacing。这个属性能够供我们自己定义的ViewGroup中的View使用。

attrs.xml 的内容:

<?xml version="1.0" encoding="utf-8"?

>
<resources> <declare-styleable name="MyCustomLayout">
<attr name="horizontal_spacing" format="dimension" />
<attr name="vertical_spacing" format="dimension" />
</declare-styleable> <declare-styleable name="MyCustomLayout_LayoutParams">
<attr name="layout_vertical_spacing" format="dimension" />
</declare-styleable> </resources>

在dimens.xml中定义两个属性的默认值。

dimens.xml 的内容:

<?

xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="horizontal_spacing">10dp</dimen>
<dimen name="vertical_spacing">10dp</dimen>
</resources>

接着,最基本的步骤来了。先看看我们自己定义的ViewGroup。

以下是源代码:

package com.customlayout.mycustomlayout;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup; public class MyCustomLayout extends ViewGroup { private int mHorizontalSpacing;
private int mVerticalSpacing; public MyCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout);
mHorizontalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_horizontal_spacing,
getResources().getDimensionPixelSize(R.dimen.horizontal_spacing));
mVerticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_vertical_spacing,
getResources().getDimensionPixelSize(R.dimen.vertical_spacing));
ta.recycle();
} @Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
// TODO Auto-generated method stub
return p != null;
} @Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
// TODO Auto-generated method stub
return (LayoutParams) p;
} @Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
} @Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
int height = getPaddingTop();
int verticalSpacing;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
verticalSpacing = mVerticalSpacing;
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.verticalSpacing > 0) {
verticalSpacing += lp.verticalSpacing;
}
width = getPaddingLeft() + mHorizontalSpacing * i;
lp.x = width;
lp.y = height;
width += child.getMeasuredWidth();
height += verticalSpacing;
}
width += getPaddingRight();
height += getChildAt(getChildCount() - 1).getMeasuredHeight() + getPaddingBottom(); setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
} public static class LayoutParams extends ViewGroup.LayoutParams {
public int x;
public int y;
public int verticalSpacing; public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout_LayoutParams);
verticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_LayoutParams_layout_vertical_spacing, -1);
ta.recycle();
} public LayoutParams(int w, int h) {
super(w, h);
}
}
}

首先,我们从MyCustomLayout.java 的构造方法说起。

public MyCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout);
mHorizontalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_horizontal_spacing,
getResources().getDimensionPixelSize(R.dimen.horizontal_spacing));
mVerticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_vertical_spacing,
getResources().getDimensionPixelSize(R.dimen.vertical_spacing));
ta.recycle();
}

这个构造方法有两个參数,当中attrs是我们布局的属性集合,有了这个參数。我们就能够获取到在布局文件xml中设置的相关属性了。

接着,讲onMeasure方法。顾名思义。这种方法是一个測量方法。它的作用是:遍历布局中的每个View。对每个View进行測量(调用measureChild方法),接着再为View设置LayoutParams。设置View的位置,即在屏幕上的x。y坐标。以便供onLayout方法中使用。这里的LayoutParams是我们重写的,当中int x和int y保存了布局中View的坐标位置。注意:重写LayoutParams类时。必需要对ViewGroup中的checkLayoutParams(ViewGroup.LayoutParams
p)、generateLayoutParams(ViewGroup.LayoutParams p)、generateLayoutParams(AttributeSet attrs)、generateDefaultLayoutParams()进行重写,否则将会出现异常。。。

接下来。讲onLayout方法;这种方法是对布局中的所有View进行位置部署。从方法体中能够看到,它通过一个遍历,对布局中的每个View调用layout方法进行位置部署。

好了,在这里略微总结下:自己定义ViewGroup流程中。 最主要是对onMeasure和onLayout两个方法进行重写。onMeasure通过遍历布局中的View。为每个View測量了大小、计算布局參数等。onLayout则是通过遍历布局中的View,为每个View进行位置布置。

在activity_main.xml 中使用我们自己定义的ViewGroup:

<com.customlayout.mycustomlayout.MyCustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customLayout="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"
customLayout:horizontal_spacing="65dp"
customLayout:vertical_spacing="85dp"> <View
android:layout_width="100dp"
android:layout_height="150dp"
android:background="#00ff00" /> <View
android:layout_width="100dp"
android:layout_height="150dp"
android:background="#0000ff" /> <View
android:layout_width="100dp"
android:layout_height="150dp"
android:background="#ff0000" /> <View
android:layout_width="100dp"
android:layout_height="150dp"
android:background="#0ff000" /> <View
android:layout_width="100dp"
android:layout_height="150dp"
android:background="#00f0f0" /> </com.customlayout.mycustomlayout.MyCustomLayout>

MainActivity.java 的源代码:

package com.customlayout.mycustomlayout;

import android.app.Activity;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.BounceInterpolator;
import android.view.animation.LayoutAnimationController;
import android.view.animation.TranslateAnimation; public class MainActivity extends Activity { MyCustomLayout layout;
LayoutAnimationController layoutAnimationController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); layout = (MyCustomLayout) findViewById(R.id.layout); AnimationSet set = new AnimationSet(true); AlphaAnimation a = new AlphaAnimation(0f, 1f);
a.setDuration(500);
TranslateAnimation t = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1f,
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);
t.setDuration(500); set.addAnimation(t);
set.addAnimation(a);
layoutAnimationController = new LayoutAnimationController(set);
layout.setLayoutAnimation(layoutAnimationController); }
}

最后。讲一下布局动画。在ViewGroup类中,有一个属性是LayoutAnimation,也就是所谓的布局动画。仅仅要我们指定一个动画给这个属性,那么ViewGroup中的每个在布局时都可以带有动画效果。在上面的onCreate()方法中。我指定了一个动画集合并设置给了我自己定义好的MyCustomLayout。

执行一下程序,在网上看到。MyCustomLayout每View将在顺序和我的电影了,现在被指定MyCustomLayout在,其效果是非常酷!

结合这个简单的例子,给你自己定义的简单介绍ViewGroup方法;我们使用其他复杂的布局,所有使用我上面描述将实施的方法。他们的计算将仅比许多上述例子更复杂,但基本原理仍然是。

如何定义自己的ViewGroup的更多相关文章

  1. 定义你自己ViewGroup

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/40264433 好久都没有写文章了,如今利用周末的时间对一些知识进行总结.便于加深理解,今天我 ...

  2. Android自己定义组件系列【1】——自己定义View及ViewGroup

    View类是ViewGroup的父类,ViewGroup具有View的全部特性.ViewGroup主要用来充当View的容器.将当中的View作为自己孩子,并对其进行管理.当然孩子也能够是ViewGr ...

  3. Android自己定义组件系列【2】——Scroller类

    在上一篇中介绍了View类的scrollTo和scrollBy两个方法,对这两个方法不太了解的朋友能够先看<自己定义View及ViewGroup> scrollTo和scrollBy尽管实 ...

  4. 转战WebApp: 最适合Android开发者的WebApp框架

    随着移动端设备越来越多, 微信应用号即将发布, 越来越多的页面需要被移动浏览器承载, HTML5开发大热, 我们需要掌握Web开发的技能来适应时代变化. 合适的WebApp框架 AndroidUI4W ...

  5. Android Touch系统简介(二):实例详解onInterceptTouchEvent与onTouchEvent的调用过程

    上一篇文章主要讲述了Android的TouchEvent的分发过程,其中有两个重要的函数:onInterceptTouchEvent和onTouchEvent,这两个函数可被重装以完成特定的逻辑.on ...

  6. Android Touch系统简介(二):实例详解onInterceptTouchEvent与onTouchEvent的调用过程

    上一篇文章主要讲述了Android的TouchEvent的分发过程,其中有两个重要的函数:onInterceptTouchEvent和onTouchEvent,这两个函数可被重装以完成特定的逻辑.on ...

  7. View事件传递之父View和子View之间的那点事

    Android事件传递流程在网上可以找到很多资料,FrameWork层输入事件和消费事件,可以参考: Touch事件派发过程详解 这篇blog阐述了底层是如何处理屏幕输,并往上传递的.Touch事件传 ...

  8. 手势滑动结束 Activity(一)基本功能的实现

    喜欢听音乐的朋友可能都看过天天动听这款 app, 这款 app 有一个亮点就是在切换页面(Fragment)的时候能够通过手势滑动来结束当前页面.这里先说一下,我为什么会这么关心这个功能呢,由于前两天 ...

  9. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

随机推荐

  1. Python验证码识别处理实例(转)

    一.准备工作与代码实例 1.PIL.pytesser.tesseract (1)安装PIL:下载地址:http://www.pythonware.com/products/pil/(CSDN下载) 下 ...

  2. 解析DBR操作系统引导记录数据

    理解文件系统.你必须要熟悉DBR,下面我们就来看看文件系统解析DBR数据. Dos Boot Record(DBR)操作系统引导记录是由操作系统的格式化程序建立的.在文件系统驱动操作不论什么一个磁盘卷 ...

  3. HDU 4313 Matrix

    水题:在一个双连通的树上有一些点很有破坏性,我们要把这些带破环性的点隔开,就是破坏一些边使这些点之间不连通,破坏一条边需要一点时间,问最少需要多少时间(同一时间只能破坏一个地方,且忽略位置转移的时间) ...

  4. 认识Backbone (二)

    Backbone.Model(模型) Models(模型)是任何Javascript应用的核心,包括数据交互及与其相关的大量逻辑: 转换.验证.计算属性和访问控制.Model在Backbone中为数据 ...

  5. WPF技术触屏上的应用系列(一): 3D 图片(照片)墙、柱面墙(凹面墙或者叫远景墙、凸面墙或者叫近景墙)实现

    原文:WPF技术触屏上的应用系列(一): 3D 图片(照片)墙.柱面墙(凹面墙或者叫远景墙.凸面墙或者叫近景墙)实现 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7 ...

  6. 微信电脑版(Mac和Windows)安装

    内容简介 1.微信Windows版 2.微信Mac版 3.总结优势 微信电脑版 众所周知,腾讯公司(马化腾先生执掌的巨头公司)开发的超成功App:微信.一经推出便引发业界轰动,使用人数更是直逼QQ. ...

  7. C++ Primer 学习笔记_33_STL实践与分析(7) --容器适配器

    STL实践与分析 --容器适配器 引: 除了顺序容器.标准库还提供了三种顺序容器适配器:queue,priority_queue和stack.适配器是标准库中的概念.包含容器适配器,迭代器适配器和函数 ...

  8. ArcSDE SDK For Java二次开发介绍、演示样例

    在一个工作中,遇到了须要java后台来查询ArcGIS 中用到的Oracle数据库空间数据,因为对ArcGIS空间数据首次接触,仅仅知道Oracle能够使用ST_GEOMETRY字段存储,例如以下图 ...

  9. Android - 和其他APP交互 - 把用户带到其他app

    Android的重要功能之一就是app可以根据要执行的操作让用户启动另外一个app.例如,app有一个商业地址然后想要在地图上显示,并不需要在app中加一个显示地图的activity,可以直接用Int ...

  10. 信息二战炸弹:中国到美国咨询公司Say no

    疯抢/文 在禁止Windows8操作系统參与政府採购,以及在中国销售的全部外国IT产品和服务都须通过新的安全审查之后,英国<金融时报>今天报料中国已禁止国企使用美国咨询公司服务. 这则消息 ...