Add API demo for a custom layout.

This serves as a complete, formal layout, with attributes
and all that good stuff.  Intended for use as sample code
in the java docs.

Change-Id: Ic45b9387d724bf574e2bfb8970b26c7b47fc0a2b
This commit is contained in:
Dianne Hackborn
2013-03-05 17:54:42 -08:00
parent 3de0bf970a
commit 654f51aa29
10 changed files with 417 additions and 15 deletions

View File

@@ -1390,76 +1390,93 @@
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout1" android:label="Views/Layouts/LinearLayout/1. Vertical">
<activity android:name=".view.LinearLayout1"
android:label="Views/Layouts/LinearLayout/01. Vertical">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout2" android:label="Views/Layouts/LinearLayout/2. Vertical (Fill Screen)">
<activity android:name=".view.LinearLayout2"
android:label="Views/Layouts/LinearLayout/02. Vertical (Fill Screen)">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout3" android:label="Views/Layouts/LinearLayout/3. Vertical (Padded)">
<activity android:name=".view.LinearLayout3"
android:label="Views/Layouts/LinearLayout/03. Vertical (Padded)">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout4" android:label="Views/Layouts/LinearLayout/4. Horizontal">
<activity android:name=".view.LinearLayout4"
android:label="Views/Layouts/LinearLayout/04. Horizontal">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout5" android:label="Views/Layouts/LinearLayout/5. Simple Form">
<activity android:name=".view.LinearLayout5"
android:label="Views/Layouts/LinearLayout/05. Simple Form">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout6" android:label="Views/Layouts/LinearLayout/6. Uniform Size">
<activity android:name=".view.LinearLayout6"
android:label="Views/Layouts/LinearLayout/06. Uniform Size">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout7" android:label="Views/Layouts/LinearLayout/7. Fill Parent">
<activity android:name=".view.LinearLayout7"
android:label="Views/Layouts/LinearLayout/07. Fill Parent">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout8" android:label="Views/Layouts/LinearLayout/8. Gravity">
<activity android:name=".view.LinearLayout8"
android:label="Views/Layouts/LinearLayout/08. Gravity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout9" android:label="Views/Layouts/LinearLayout/9. Layout Weight">
<activity android:name=".view.LinearLayout9"
android:label="Views/Layouts/LinearLayout/09. Layout Weight">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.LinearLayout10" android:label="Views/Layouts/LinearLayout/10. Background Image">
<activity android:name=".view.LinearLayout10"
android:label="Views/Layouts/LinearLayout/10. Background Image">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.CustomLayoutActivity"
android:label="Views/Layouts/CustomLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".view.RadioGroup1" android:label="Views/Radio Group">
<intent-filter>

View File

@@ -18,7 +18,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#00000000"/>
<stroke android:width="1dp" color="#ff000000"/>
<stroke android:width="1dp" android:color="#ff000000"/>
<padding android:left="1dp" android:top="1dp"
android:right="1dp" android:bottom="1dp" />
</shape>

View File

@@ -17,5 +17,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dp" color="#ffffffff"/>
<stroke android:width="1dp" android:color="#ffffffff"/>
</shape>

View File

@@ -18,7 +18,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f0600000"/>
<stroke android:width="3dp" color="#ffff8080"/>
<stroke android:width="3dp" android:color="#ffff8080"/>
<corners android:radius="3dp" />
<padding android:left="10dp" android:top="10dp"
android:right="10dp" android:bottom="10dp" />

View File

@@ -16,7 +16,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffdddd00"/>
<stroke android:width="3dp" color="#ff000000"/>
<stroke android:width="3dp" android:color="#ff000000"/>
<corners android:radius="3dp" />
<padding android:left="10dp" android:top="10dp"
android:right="10dp" android:bottom="10dp" />

View File

@@ -16,7 +16,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f0600000"/>
<stroke android:width="3dp" color="#ffff8080"/>
<stroke android:width="3dp" android:color="#ffff8080"/>
<corners android:radius="3dp" />
<padding android:left="10dp" android:top="10dp"
android:right="10dp" android:bottom="10dp" />

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Demonstrates use of CustomLayout -->
<!-- BEGIN_INCLUDE(Complete) -->
<com.example.android.apis.view.CustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.android.apis"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- put first view to left. -->
<TextView
android:background="@drawable/filled_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_position="left"
android:layout_gravity="fill_vertical|center_horizontal"
android:text="l1"/>
<!-- stack second view to left. -->
<TextView
android:background="@drawable/filled_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_position="left"
android:layout_gravity="fill_vertical|center_horizontal"
android:text="l2"/>
<!-- also put a view on the right. -->
<TextView
android:background="@drawable/filled_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_position="right"
android:layout_gravity="fill_vertical|center_horizontal"
android:text="r1"/>
<!-- by default views go in the middle; use fill vertical gravity -->
<TextView
android:background="@drawable/green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical|center_horizontal"
android:text="fill-vert"/>
<!-- by default views go in the middle; use fill horizontal gravity -->
<TextView
android:background="@drawable/green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|fill_horizontal"
android:text="fill-horiz"/>
<!-- by default views go in the middle; use top-left gravity -->
<TextView
android:background="@drawable/blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|left"
android:text="top-left"/>
<!-- by default views go in the middle; use center gravity -->
<TextView
android:background="@drawable/blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="center"/>
<!-- by default views go in the middle; use bottom-right -->
<TextView
android:background="@drawable/blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:text="bottom-right"/>
</com.example.android.apis.view.CustomLayout>
<!-- END_INCLUDE(Complete) -->

View File

@@ -33,6 +33,19 @@
<attr name="textSize" format="dimension" />
</declare-styleable>
<!-- These are the attributes that we want to retrieve for
view/CustomLayout.java -->
<!-- BEGIN_INCLUDE(CustomLayout) -->
<declare-styleable name="CustomLayoutLP">
<attr name="android:layout_gravity" />
<attr name="layout_position">
<enum name="middle" value="0" />
<enum name="left" value="1" />
<enum name="right" value="2" />
</attr>
</declare-styleable>
<!-- END_INCLUDE(CustomLayout) -->
<!-- These are attributes used with 'DraggableDot' drawables in
view/DragAndDropActivity.java and view/DraggableDot.java -->
<declare-styleable name="DraggableDot">

View File

@@ -0,0 +1,245 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.view;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import android.graphics.Rect;
import com.example.android.apis.R;
//BEGIN_INCLUDE(Complete)
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
/**
* Example of writing a custom layout manager. This is a fairly full-featured
* layout manager that is relatively general, handling all layout cases. You
* can simplify it for more specific cases.
*/
@RemoteViews.RemoteView
public class CustomLayout extends ViewGroup {
/** The amount of space used by children in the left gutter. */
private int mLeftWidth;
/** The amount of space used by children in the right gutter. */
private int mRightWidth;
/** These are used for computing child frames based on their gravity. */
private final Rect mTmpContainerRect = new Rect();
private final Rect mTmpChildRect = new Rect();
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Any layout manager that doesn't scroll will want this.
*/
@Override
public boolean shouldDelayChildPressedState() {
return false;
}
/**
* Ask all children to measure themselves and compute the measurement of this
* layout based on the children.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
// These keep track of the space we are using on the left and right for
// views positioned there; we need member variables so we can also use
// these for layout later.
mLeftWidth = 0;
mRightWidth = 0;
// Measurement will ultimately be computing these values.
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
// Iterate through all children, measuring them and computing our dimensions
// from their size.
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
// Measure the child.
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
// Update our size information based on the layout params. Children
// that asked to be positioned on the left or right go in those gutters.
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.position == LayoutParams.POSITION_LEFT) {
mLeftWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else if (lp.position == LayoutParams.POSITION_RIGHT) {
mRightWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else {
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
}
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
}
// Total width is the maximum width of all inner children plus the gutters.
maxWidth += mLeftWidth + mRightWidth;
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
// Report our final dimensions.
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
}
/**
* Position all children within this layout.
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
// These are the far left and right edges in which we are performing layout.
int leftPos = getPaddingLeft();
int rightPos = right - left - getPaddingRight();
// This is the middle region inside of the gutter.
final int middleLeft = leftPos + mLeftWidth;
final int middleRight = rightPos - mRightWidth;
// These are the top and bottom edges in which we are performing layout.
final int parentTop = getPaddingTop();
final int parentBottom = bottom - top - getPaddingBottom();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
// Compute the frame in which we are placing this child.
if (lp.position == LayoutParams.POSITION_LEFT) {
mTmpContainerRect.left = leftPos + lp.leftMargin;
mTmpContainerRect.right = leftPos + width + lp.rightMargin;
leftPos = mTmpContainerRect.right;
} else if (lp.position == LayoutParams.POSITION_RIGHT) {
mTmpContainerRect.right = rightPos - lp.rightMargin;
mTmpContainerRect.left = rightPos - width - lp.leftMargin;
rightPos = mTmpContainerRect.left;
} else {
mTmpContainerRect.left = middleLeft + lp.leftMargin;
mTmpContainerRect.right = middleRight - lp.rightMargin;
}
mTmpContainerRect.top = parentTop + lp.topMargin;
mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;
// Use the child's gravity and size to determine its final
// frame within its container.
Gravity.apply(lp.gravity, width, height, mTmpContainerRect, mTmpChildRect);
// Place the child.
child.layout(mTmpChildRect.left, mTmpChildRect.top,
mTmpChildRect.right, mTmpChildRect.bottom);
}
}
}
// ----------------------------------------------------------------------
// The rest of the implementation is for custom per-child layout parameters.
// If you do not need these (for example you are writing a layout manager
// that does fixed positioning of its children), you can drop all of this.
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CustomLayout.LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
/**
* Custom per-child layout information.
*/
public static class LayoutParams extends MarginLayoutParams {
/**
* The gravity to apply with the View to which these layout parameters
* are associated.
*/
public int gravity = Gravity.TOP | Gravity.START;
public static int POSITION_MIDDLE = 0;
public static int POSITION_LEFT = 1;
public static int POSITION_RIGHT = 2;
public int position = POSITION_MIDDLE;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
// Pull the layout param values from the layout XML during
// inflation. This is not needed if you don't care about
// changing the layout behavior in XML.
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CustomLayoutLP);
gravity = a.getInt(R.styleable.CustomLayoutLP_android_layout_gravity, gravity);
position = a.getInt(R.styleable.CustomLayoutLP_layout_position, position);
a.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
//END_INCLUDE(Complete)

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.view;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
public class CustomLayoutActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_layout);
}
}