50个Android开发技巧(03 自己定义ViewGroup)
图1
(原文地址:http://blog.csdn.net/vector_yi/article/details/24415537)
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width= "fill_parent"
android:layout_height= "fill_parent" > <View
android:layout_width ="100dp"
android:layout_height ="150dp"
android:background ="#FF0000" /> <View
android:layout_width ="100dp"
android:layout_height ="150dp"
android:layout_marginLeft ="30dp"
android:layout_marginTop ="20dp"
android:background ="#00FF00" /> <View
android:layout_width ="100dp"
android:layout_height ="150dp"
android:layout_marginLeft ="60dp"
android:layout_marginTop ="40dp"
android:background ="#0000FF" /> </RelativeLayout>
效果如图2:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmVjdG9yX3lp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
图2
- 当你将这个布局应用到不同Activity中时更加easy维护
- 能够利用自己定义属性来自己定义ViewGroup中的每一个子View
- 更加简洁可读的XML文件内容
- 假设须要改变margin的时候。不须要手动的去计算每一个子View的margin
<FrameLayout
<!--自己定义命名空间,以便在下文中使用自己定义的属性-->
xmlns:cascade ="http://schemas.android.com/apk/res/com.manning.androidhacks.hack003"
xmlns:android= "http://schemas.android.com/apk/res/android"
android:layout_width= "fill_parent"
android:layout_height= "fill_parent" > <com.manning.androidhacks.hack003.view.CascadeLayout
android:layout_width ="fill_parent"
android:layout_height ="fill_parent"
cascade:horizontal_spacing ="30dp"<!--由于前面加入了cascade命名空间,所以此处能够使用自己定义属性-->
cascade:vertical_spacing ="20dp" > <View
android:layout_width ="100dp"
android:layout_height ="150dp"
cascade:layout_vertical_spacing ="90dp"<!--为子View加入的自己定义属性,将在本文第三部分用到-->
android:background ="#FF0000" /> <View
android:layout_width ="100dp"
android:layout_height ="150dp"
android:background ="#00FF00" /> <View
android:layout_width ="100dp"
android:layout_height ="150dp"
android:background ="#0000FF" />
</com.manning.androidhacks.hack003.view.CascadeLayout> </FrameLayout>
<? xml version ="1.0" encoding= "utf-8" ?>
<resources>
<declare-styleable name= "CascadeLayout" >
<attr name= "horizontal_spacing" format = "dimension" />
<attr name= "vertical_spacing" format = "dimension" />
</declare-styleable>
</resources>
<? xml version ="1.0" encoding= "utf-8" ? >
<resources>
<dimen name= "cascade_horizontal_spacing" >10dp</dimen>
<dimen name= "cascade_vertical_spacing" >10dp</dimen>
</resources>
public CascadeLayout (Context context, AttributeSet attrs) {
super( context, attrs);
TypedArray a = context .obtainStyledAttributes (attrs ,
R. styleable. CascadeLayout );
try {
mHorizontalSpacing = a. getDimensionPixelSize(
R. styleable. CascadeLayout_horizontal_spacing ,
getResources ().getDimensionPixelSize (
R. dimen. cascade_horizontal_spacing ));
mVerticalSpacing = a. getDimensionPixelSize(
R. styleable. CascadeLayout_vertical_spacing , getResources ()
.getDimensionPixelSize (R .dimen .cascade_vertical_spacing ));
} finally {
a .recycle ();
}
public static class LayoutParams extends ViewGroup .LayoutParams {
int x;
int y;
public LayoutParams( Context context , AttributeSet attrs) {
super (context , attrs );
}
public LayoutParams( int w , int h ) {
super (w , h );
}
}
@Override
protected void onMeasure (int widthMeasureSpec , int heightMeasureSpec ) {
int width = 0;
int height = getPaddingTop (); final int count = getChildCount ();
for ( int i = 0; i < count; i++) {
View child = getChildAt (i );
measureChild (child , widthMeasureSpec , heightMeasureSpec );
LayoutParams lp = (LayoutParams ) child .getLayoutParams ();
width = getPaddingLeft () + mHorizontalSpacing * i; lp .x = width;
lp .y = height; width += child .getMeasuredWidth ();
height += mVerticalSpacing ;
} 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 ());
}
}
<declare-styleable name="CascadeLayout_LayoutParams">
<attr name="layout_vertical_spacing" format="dimension" />
</declare-styleable>
public LayoutParams (Context context, AttributeSet attrs) {
super (context , attrs );
TypedArray a = context .obtainStyledAttributes (attrs ,
R. styleable. CascadeLayout_LayoutParams );
try {
verticalSpacing = a
.getDimensionPixelSize (
R .styleable .CascadeLayout_LayoutParams_layout_vertical_spacing ,
-1 );
} finally {
a .recycle ();
}
}
@Override
protected void onMeasure (int widthMeasureSpec , int heightMeasureSpec ) {
int width = getPaddingLeft ();
int height = getPaddingTop ();
int verticalSpacing ; final int count = getChildCount ();
for ( int i = 0; i < count; i++) {
verticalSpacing = mVerticalSpacing ; View child = getChildAt (i );
measureChild (child , widthMeasureSpec , heightMeasureSpec ); LayoutParams lp = ( LayoutParams ) child .getLayoutParams ();
width = getPaddingLeft () + mHorizontalSpacing * i; lp .x = width;
lp .y = height; if (lp .verticalSpacing >= 0 ) {
verticalSpacing = lp .verticalSpacing ;
} width += child .getMeasuredWidth ();
height += verticalSpacing ;
} width += getPaddingRight ();
height += getChildAt (getChildCount () - 1). getMeasuredHeight ()
+ getPaddingBottom (); setMeasuredDimension ( resolveSize( width, widthMeasureSpec ),
resolveSize( height, heightMeasureSpec ));
}
package com.manning.androidhacks.hack003.view; import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup; import com.manning.androidhacks.hack003.R; public class CascadeLayout extends ViewGroup { private int mHorizontalSpacing;
private int mVerticalSpacing; public CascadeLayout(Context context, AttributeSet attrs) {
super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CascadeLayout); try {
mHorizontalSpacing = a.getDimensionPixelSize(
R.styleable.CascadeLayout_horizontal_spacing,
getResources().getDimensionPixelSize(
R.dimen.cascade_horizontal_spacing)); mVerticalSpacing = a.getDimensionPixelSize(
R.styleable.CascadeLayout_vertical_spacing, getResources()
.getDimensionPixelSize(R.dimen.cascade_vertical_spacing));
} finally {
a.recycle();
} } @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getPaddingLeft();
int height = getPaddingTop();
int verticalSpacing; final int count = getChildCount();
for (int i = 0; i < count; i++) {
verticalSpacing = mVerticalSpacing; View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec); LayoutParams lp = (LayoutParams) child.getLayoutParams();
width = getPaddingLeft() + mHorizontalSpacing * i; lp.x = width;
lp.y = height; if (lp.verticalSpacing >= 0) {
verticalSpacing = lp.verticalSpacing;
} 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());
}
} @Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
} @Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
} @Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
} @Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p.width, p.height);
} public static class LayoutParams extends ViewGroup.LayoutParams {
int x;
int y;
public int verticalSpacing; public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CascadeLayout_LayoutParams);
try {
verticalSpacing = a
.getDimensionPixelSize(
R.styleable.CascadeLayout_LayoutParams_layout_vertical_spacing,
-1);
} finally {
a.recycle();
}
} public LayoutParams(int w, int h) {
super(w, h);
} }
}
project文件夹结构:
(原文地址:http://blog.csdn.net/vector_yi/article/details/24415537)
50个Android开发技巧(03 自己定义ViewGroup)的更多相关文章
- 50个android开发技巧
50个android开发技巧 http://blog.csdn.net/column/details/androidhacks.html
- 50一个Android开发技巧(01 利用好layout_weight属性)
问题:如何将一个Button放置在布局的中间,并设置其宽度parent的50%? 分析:问题想要达到的效果应该是这样: (原文地址:http://blog.csdn.net/vector_yi/art ...
- 50个Android开发技巧(02 延迟载入和避免反复渲染视图)
当你在Application中创建复杂的布局时.页面的渲染过程也变得更加缓慢. 此时,我们须要利用 <include />标签(避免反复渲染)和 ViewStub类(延迟载入)来优化我们的 ...
- 50个Android开发技巧(24 处理ListView数据为空的情况)
在移动平台上为用户展示数据的一个经常用法是将数据填充进一个List内,而此时须要注意的一点就是: 原文地址:(http://blog.csdn.net/vector_yi/article/d ...
- 50个Android开发技巧(11 为文字加入特效)
问题:怎样构建一个模拟LED数字时钟的页面?效果例如以下图所看到的: (原文地址:http://blog.csdn.net/vector_yi/article/details/24460227) 分析 ...
- 50个Android开发技巧(10 为TextView加入样式)
首先来看一个控件的例子: (原文地址:http://blog.csdn.net/vector_yi/article/details/24428085) 手机上类似这种场景你一定已经见过非常多次了,但有 ...
- 50个Android开发技巧(12 为控件加入圆角边框)
控件的圆角边框能够使你的App看起来更美观,事实上实现起来也非常easy. (原文地址:http://blog.csdn.net/vector_yi/article/details/24463025) ...
- 50个Android开发技巧(09 避免用EditText对日期进行验证)
我们都知道,在表单中对数据进行验证不但无聊并且easy出错. (原文地址:http://blog.csdn.net/vector_yi/article/details/24424713) 想象一下,一 ...
- Android开发技巧——大图裁剪
本篇内容是接上篇<Android开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使 ...
随机推荐
- 简单的图形学(三)——光源
参考自:用JavaScript玩转计算机图形学(二)基本光源 - Milo Yip - 博客园,主要讲述三种最基本的光源--平行光.点光源.聚光灯,其实就是三种数学模型. 代码的调整 先前的代码中,颜 ...
- 【转】二叉树、B树、B-树、B+树、B*树
二叉树 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: 二叉树的搜索,从 ...
- Python中写一个乒乓球类的游戏
最近开始学Python,感觉挺好玩的,既有脚本语言的灵活性,又有丰富的类库与面向对象的特点,开发起来很方便. 游戏的规则和乒乓球一样,如果妙蛙种子掉地上了就算输,你可以用蓝色的跷跷板弹它,使他不落到地 ...
- Maven项目下HttpServletRequest 或 HttpServletResponse需引用的依赖包
转载: http://xyly624.blog.51cto.com/842520/865630/ Maven项目下HttpServletRequest 或 HttpServletResponse需引用 ...
- lighttpd + php 移植配置
buildroot 内添加 lighttpd 和php 等相关选项 // make menuconfig Target packages ---> Interpreter languages a ...
- ubuntu 14.04 安装中文输入法
记录Ubuntu 14.04 里面安装中文输入法的过程 先安装如下包 sudo apt-get install ibus sudo apt-get install ibus ibus-clutter ...
- kafkaStream执行过程中出现TimeoutException异常退出
日志中出现以下异常信息,程序中断退出. 目前参考别人的修改下面的配置,原来使用的hostname,改成IP,再观察观察. advertised.listeners=PLAINTEXT://192.1 ...
- spingboot集成jpa(二)
一.使用单元测试 单元测试在每个项目环境中必不可少,springboot中如何使用单元测试 在src/test/java中新建测试类DemoApplicationTest.java 项目结构: De ...
- 【SpringMVC笔记】第五课 改进Handler处理器和视图解析器
第四课 已经对注解的映射器和适配器进行了改进. 接下来需要对Handler处理器和视图解析器进行改进. <!-- 配置handler处理器 --> <bean class=" ...
- http抓包工具
fiddler 可以用该工具抓包并修改对应的参数数据