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开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使 ...
随机推荐
- ny495 少年 DXH
少年 DXH 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 大家都知道,DXH 幼时性格怪癖,小朋友都不喜欢和他玩,这种情况一直到 DXH 的少年时期也没有改变.少 ...
- 【图文教程】WebStorm下使用Github下载以及上传代码
1.从一个git路径下,下载代码到本地,选择VCS->Checkout from Version Control ->GitHub. 2.可能会弹出需要设置上传代码的密码,这 ...
- eclipse新建tomcat server但是总是报404的解决方法
今天在eclipse中新建了tomcat server,但是由于一些配置出了问题,导致总是出现404报错,具体情况如下 症状: tomcat在eclipse里面能正常启动,而在浏览器中访问http:/ ...
- C#中一道关于多线程的基础练习题——模拟仓库存销过程
题目:模拟生产.入库.销售(50分) 假设某企业自产.自存.自销,需要将工厂生产的各类产品不定时的运到仓库,与此同时,需要将仓库中的货物运往超市和商场中进行销售,请编写一个程序模拟此过程(主要是存取这 ...
- js中Math.round、parseInt、Math.floor和Math.ceil小数取整小结【转】
[摘要:之前常常正在代码中看到Math.round.parseInt.Math.floor战Math.ceil那四个函数,固然晓得效果皆能够返回一个整数,然则对他们四者的差别照样没有太清晰,本日便做一 ...
- python基础系列教程——Python中的编码问题,中文乱码问题
python基础系列教程——Python中的编码问题,中文乱码问题 如果不声明编码,则中文会报错,即使是注释也会报错. # -*- coding: UTF-8 -*- 或者 #coding=utf-8 ...
- json关键总结
先引用 Newtonsoft.Json.Net20.dll //序列化对象的方法也非常的简单: string json = JsonConvert.SerializeObject(product); ...
- nginx 405 not allowed问题的解决
转载自: http://www.linuxidc.com/Linux/2012-07/66761.htm Apache.IIS.Nginx等绝大多数web服务器,都不允许静态文件响应POST请求,否 ...
- ubuntu下man帮助文档不全怎么办?如何解决?
真心后悔用ubuntu学习linux 发现很多东西不全,kate没有,vi版本低,帮助文档不全一系列的问题.ubuntu下man帮助文档不全怎么办?如何解决?不用担心,下边小编就为大家带来最详细的解决 ...
- signal(SIGPIPE, SIG_IGN) (转)
signal(SIGPIPE, SIG_IGN) 当服务器close一个连接时,若client端接着发数据. 根据TCP 协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会 ...