Create custom layout
Description
The following code shows how to create custom layout.
Example
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2012 Manning
See the file license.txt for copying permission.
-->
<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:vertical_spacing="20dp" >
<View
android:layout_width="100dp"
android:layout_height="150dp"
cascade:layout_vertical_spacing="90dp"
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>
res/layout/framelayout_with_margins.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2012 Manning
See the file license.txt for copying permission.
-->
<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>
Main Activity java
/*******************************************************************************
* Copyright (c) 2012 Manning/* w ww .j a v a2s. com*/
* See the file license.txt for copying permission.
******************************************************************************/
package com.manning.androidhacks.hack003;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Custom layout Java file
/*******************************************************************************
* Copyright (c) 2012 Manning//www. j a v a2 s. c om
* See the file license.txt for copying permission.
******************************************************************************/
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);
}
}
}
res/values/dimen.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2012 Manning
See the file license.txt for copying permission.
-->
<resources>
<dimen name="cascade_horizontal_spacing">10dp</dimen>
<dimen name="cascade_vertical_spacing">10dp</dimen>
</resources>
res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2012 Manning
See the file license.txt for copying permission.
-->
<resources>
<declare-styleable name="CascadeLayout">
<attr name="horizontal_spacing" format="dimension" />
<attr name="vertical_spacing" format="dimension" />
</declare-styleable>
<declare-styleable name="CascadeLayout_LayoutParams">
<attr name="layout_vertical_spacing" format="dimension" />
</declare-styleable>
</resources>