Fix for bug 6110465.

Add layout bound metadata to 9-patch files and make layouts take them into account.

This CL contains a proposed API for dealing with layout bounds.

This solution exposes:

1. Class: Insets - for storing layout Insets (and later possibly padding).
2. Methods: View:(get/set)LayoutInsets() - for storing layoutBounds.
3. Methods: ViewGroup:(get/set)LayoutMode() - for controlling layoutMode.

It also iuncudes the changes to GridLayout to support layout bounds.

Change-Id: I60c836b6530b61c5abf37f93ee9c44aad73573f1
This commit is contained in:
Philip Milne
2012-04-04 23:41:34 -07:00
parent c58a6d2da4
commit 1557fd7809
17 changed files with 436 additions and 42 deletions

View File

@@ -24079,6 +24079,7 @@ package android.view {
method public android.view.View getFocusedChild();
method public android.view.animation.LayoutAnimationController getLayoutAnimation();
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
method public int getLayoutMode();
method public android.animation.LayoutTransition getLayoutTransition();
method public int getPersistentDrawingCache();
method public int indexOfChild(android.view.View);
@@ -24126,6 +24127,7 @@ package android.view {
method public void setDescendantFocusability(int);
method public void setLayoutAnimation(android.view.animation.LayoutAnimationController);
method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener);
method public void setLayoutMode(int);
method public void setLayoutTransition(android.animation.LayoutTransition);
method public void setMotionEventSplittingEnabled(boolean);
method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
@@ -24138,9 +24140,11 @@ package android.view {
method public void startViewTransition(android.view.View);
method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
field public static final int COMPONENT_BOUNDS = 0; // 0x0
field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
field public static final int LAYOUT_BOUNDS = 1; // 0x1
field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
field public static final int PERSISTENT_NO_CACHE = 0; // 0x0

View File

@@ -24,6 +24,7 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
@@ -2597,6 +2598,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
@ViewDebug.ExportedProperty(category = "padding")
protected int mPaddingBottom;
/**
* The layout insets in pixels, that is the distance in pixels between the
* visible edges of this view its bounds.
*/
private Insets mLayoutInsets;
/**
* Briefly describes the view and is primarily used for accessibility support.
*/
@@ -13272,6 +13279,29 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
return mUserPaddingRelative;
}
/**
* @hide
*/
public Insets getLayoutInsets() {
if (mLayoutInsets == null) {
if (mBackground == null) {
mLayoutInsets = Insets.NONE;
} else {
Rect insetRect = new Rect();
boolean hasInsets = mBackground.getLayoutInsets(insetRect);
mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE;
}
}
return mLayoutInsets;
}
/**
* @hide
*/
public void setLayoutInsets(Insets layoutInsets) {
mLayoutInsets = layoutInsets;
}
/**
* Changes the selection state of this view. A view can be selected or not.
* Note that selection is not the same as focus. Views are typically

View File

@@ -169,6 +169,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
protected int mGroupFlags;
/*
* THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or
* {@link #LAYOUT_BOUNDS}
*/
private int mLayoutMode = UNDEFINED_LAYOUT_MODE;
/**
* NOTE: If you change the flags below make sure to reflect the changes
* the DisplayList class
@@ -334,6 +340,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
public static final int PERSISTENT_ALL_CACHES = 0x3;
// Layout Modes
private static final int UNDEFINED_LAYOUT_MODE = -1;
/**
* This constant is a {@link #setLayoutMode(int) layoutMode}.
* Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
* {@link #getRight() right} and {@link #getBottom() bottom}.
*/
public static final int COMPONENT_BOUNDS = 0;
/**
* This constant is a {@link #setLayoutMode(int) layoutMode}.
* Layout bounds are derived by offsetting the component bounds using
* {@link View#getLayoutInsets()}.
*/
public static final int LAYOUT_BOUNDS = 1;
/**
* We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
* are set at the same time.
@@ -4367,6 +4391,52 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
}
/**
* Returns the basis of alignment during the layout of this view group:
* either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
*
* @return whether or not this view group should use the component or layout bounds during
* layout operations
*
* @see #setLayoutMode(int)
*/
public int getLayoutMode() {
if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
ViewParent parent = getParent();
if (parent instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) parent;
return viewGroup.getLayoutMode();
} else {
int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
}
}
return mLayoutMode;
}
/**
* Sets the basis of alignment during alignment of this view group.
* Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
* <p>
* The default is to query the property of the parent if this view group has a parent.
* If this ViewGroup is the root of the view hierarchy the default
* value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
* {@link #LAYOUT_BOUNDS} otherwise.
*
* @return whether or not this view group should use the component or layout bounds during
* layout operations
*
* @see #getLayoutMode()
*/
public void setLayoutMode(int layoutMode) {
if (mLayoutMode != layoutMode) {
mLayoutMode = layoutMode;
requestLayout();
}
}
/**
* Returns a new set of layout parameters based on the supplied attributes set.
*

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
@@ -559,9 +560,9 @@ public class GridLayout extends ViewGroup {
int flags = (gravity & mask) >> shift;
switch (flags) {
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
return LEADING;
return horizontal ? LEFT : TOP;
case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
return TRAILING;
return horizontal ? RIGHT : BOTTOM;
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
return FILL;
case AXIS_SPECIFIED:
@@ -1042,12 +1043,15 @@ public class GridLayout extends ViewGroup {
int rightMargin = getMargin(c, true, false);
int bottomMargin = getMargin(c, false, false);
// Alignment offsets: the location of the view relative to its alignment group.
int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
int sumMarginsX = leftMargin + rightMargin;
int sumMarginsY = topMargin + bottomMargin;
int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
// Alignment offsets: the location of the view relative to its alignment group.
int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
int dx = x1 + gravityOffsetX + alignmentOffsetX;
@@ -1181,7 +1185,7 @@ public class GridLayout extends ViewGroup {
View c = getChildAt(i);
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
}
}
@@ -2138,16 +2142,30 @@ public class GridLayout extends ViewGroup {
return before + after;
}
protected int getOffset(View c, Alignment alignment, int size) {
return before - alignment.getAlignmentValue(c, size);
private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) {
boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS;
if (!useLayoutBounds) {
return a.getAlignmentValue(c, size);
} else {
Insets insets = c.getLayoutInsets();
int leadingInset = horiz ? insets.left : insets.top; // RTL?
int trailingInset = horiz ? insets.right : insets.bottom; // RTL?
int totalInset = leadingInset + trailingInset;
return leadingInset + a.getAlignmentValue(c, size - totalInset);
}
}
protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
return before - getAlignmentValue(gl, c, size, a, horizontal);
}
protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
this.flexibility &= spec.getFlexibility();
int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
boolean horizontal = axis.horizontal;
int size = gl.getMeasurementIncludingMargin(c, horizontal);
Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
// todo test this works correctly when the returned value is UNDEFINED
int before = alignment.getAlignmentValue(c, size);
int before = getAlignmentValue(gl, c, size, alignment, horizontal);
include(before, size - before);
}
@@ -2614,8 +2632,8 @@ public class GridLayout extends ViewGroup {
}
@Override
protected int getOffset(View c, Alignment alignment, int size) {
return max(0, super.getOffset(c, alignment, size));
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
return max(0, super.getOffset(gl, c, a, size, hrz));
}
};
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2006 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 android.graphics;
/**
* An Insets instance holds four integer offsets which describe changes to the four
* edges of a Rectangle. By convention, positive values move edges towards the
* centre of the rectangle.
* <p>
* Insets are immutable so may be treated as values.
*
* @hide
*/
public class Insets {
public static final Insets NONE = new Insets(0, 0, 0, 0);
public final int left;
public final int top;
public final int right;
public final int bottom;
private Insets(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
// Factory methods
/**
* Return an Insets instance with the appropriate values.
*
* @param left the left inset
* @param top the top inset
* @param right the right inset
* @param bottom the bottom inset
*
* @return Insets instance with the appropriate values
*/
public static Insets of(int left, int top, int right, int bottom) {
if (left == 0 && top == 0 && right == 0 && bottom == 0) {
return NONE;
}
return new Insets(left, top, right, bottom);
}
/**
* Return an Insets instance with the appropriate values.
*
* @param r the rectangle from which to take the values
*
* @return an Insets instance with the appropriate values
*/
public static Insets of(Rect r) {
return of(r.left, r.top, r.right, r.bottom);
}
/**
* Two Insets instances are equal iff they belong to the same class and their fields are
* pairwise equal.
*
* @param o the object to compare this instance with.
*
* @return true iff this object is equal {@code o}
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Insets insets = (Insets) o;
if (bottom != insets.bottom) return false;
if (left != insets.left) return false;
if (right != insets.right) return false;
if (top != insets.top) return false;
return true;
}
@Override
public int hashCode() {
int result = left;
result = 31 * result + top;
result = 31 * result + right;
result = 31 * result + bottom;
return result;
}
@Override
public String toString() {
return "Insets{" +
"left=" + left +
", top=" + top +
", right=" + right +
", bottom=" + bottom +
'}';
}
}

View File

@@ -704,6 +704,20 @@ public abstract class Drawable {
return false;
}
/**
* Return in insets the layout insets suggested by this Drawable for use with alignment
* operations during layout. Positive values move toward the
* center of the Drawable. Returns true if this drawable
* actually has a layout insets, else false. When false is returned, the padding
* is always set to 0.
*
* @hide
*/
public boolean getLayoutInsets(Rect insets) {
insets.set(0, 0, 0, 0);
return false;
}
/**
* Make this drawable mutable. This operation cannot be reversed. A mutable
* drawable is guaranteed to not share its state with any other drawable.
@@ -965,9 +979,7 @@ public abstract class Drawable {
Rect pad, Rect layoutBounds, String srcName) {
if (np != null) {
NinePatchDrawable npd = new NinePatchDrawable(res, bm, np, pad, srcName);
npd.setLayoutBounds(layoutBounds);
return npd;
return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
}
return new BitmapDrawable(res, bm);

View File

@@ -90,6 +90,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
}
/**
* @hide
*/
@Override
public boolean getLayoutInsets(Rect insets) {
if (mCurrDrawable != null) {
return mCurrDrawable.getLayoutInsets(insets);
} else {
return super.getLayoutInsets(insets);
}
}
@Override
public void setAlpha(int alpha) {
if (mAlpha != alpha) {

View File

@@ -16,9 +16,17 @@
package android.graphics.drawable;
import android.graphics.*;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -29,7 +37,7 @@ import java.io.IOException;
import java.io.InputStream;
/**
*
*
* A resizeable bitmap, with stretchable areas that you define. This type of image
* is defined in a .png file with a special format.
*
@@ -47,7 +55,6 @@ public class NinePatchDrawable extends Drawable {
private NinePatchState mNinePatchState;
private NinePatch mNinePatch;
private Rect mPadding;
private Rect mLayoutBounds;
private Paint mPaint;
private boolean mMutated;
@@ -56,7 +63,7 @@ public class NinePatchDrawable extends Drawable {
// These are scaled to match the target density.
private int mBitmapWidth;
private int mBitmapHeight;
NinePatchDrawable() {
}
@@ -69,7 +76,7 @@ public class NinePatchDrawable extends Drawable {
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
}
/**
* Create drawable from raw nine-patch data, setting initial target density
* based on the display metrics of the resources.
@@ -79,7 +86,19 @@ public class NinePatchDrawable extends Drawable {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Create drawable from raw nine-patch data, setting initial target density
* based on the display metrics of the resources.
*
* @hide
*/
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, Rect layoutInsets, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Create drawable from existing nine-patch, not dealing with density.
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
@@ -99,13 +118,6 @@ public class NinePatchDrawable extends Drawable {
mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* @hide
*/
void setLayoutBounds(Rect layoutBounds) {
mLayoutBounds = layoutBounds;
}
private void setNinePatchState(NinePatchState state, Resources res) {
mNinePatchState = state;
mNinePatch = state.mNinePatch;
@@ -201,13 +213,26 @@ public class NinePatchDrawable extends Drawable {
public int getChangingConfigurations() {
return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
}
@Override
public boolean getPadding(Rect padding) {
padding.set(mPadding);
return true;
}
/**
* @hide
*/
@Override
public boolean getLayoutInsets(Rect insets) {
Rect layoutInsets = mNinePatchState.mLayoutInsets;
if (layoutInsets == null) {
return super.getLayoutInsets(insets);
}
insets.set(layoutInsets);
return true;
}
@Override
public void setAlpha(int alpha) {
if (mPaint == null && alpha == 0xFF) {
@@ -217,7 +242,7 @@ public class NinePatchDrawable extends Drawable {
getPaint().setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
if (mPaint == null && cf == null) {
@@ -267,6 +292,7 @@ public class NinePatchDrawable extends Drawable {
options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
final Rect padding = new Rect();
final Rect layoutInsets = new Rect();
Bitmap bitmap = null;
try {
@@ -290,7 +316,7 @@ public class NinePatchDrawable extends Drawable {
setNinePatchState(new NinePatchState(
new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
padding, dither), r);
padding, layoutInsets, dither), r);
mNinePatchState.mTargetDensity = mTargetDensity;
a.recycle();
@@ -344,7 +370,7 @@ public class NinePatchDrawable extends Drawable {
public Region getTransparentRegion() {
return mNinePatch.getTransparentRegion(getBounds());
}
@Override
public ConstantState getConstantState() {
mNinePatchState.mChangingConfigurations = getChangingConfigurations();
@@ -361,27 +387,36 @@ public class NinePatchDrawable extends Drawable {
return this;
}
final static class NinePatchState extends ConstantState {
private final static class NinePatchState extends ConstantState {
final NinePatch mNinePatch;
final Rect mPadding;
final Rect mLayoutInsets;
final boolean mDither;
int mChangingConfigurations;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
NinePatchState(NinePatch ninePatch, Rect padding) {
this(ninePatch, padding, DEFAULT_DITHER);
this(ninePatch, padding, new Rect(), DEFAULT_DITHER);
}
NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) {
this(ninePatch, padding, layoutInsets, DEFAULT_DITHER);
}
NinePatchState(NinePatch ninePatch, Rect rect, Rect layoutInsets, boolean dither) {
mNinePatch = ninePatch;
mPadding = rect;
mLayoutInsets = layoutInsets;
mDither = dither;
}
// Copy constructor
NinePatchState(NinePatchState state) {
mNinePatch = new NinePatch(state.mNinePatch);
// Note we don't copy the padding because it is immutable.
mPadding = state.mPadding;
mLayoutInsets = state.mLayoutInsets;
mDither = state.mDither;
mChangingConfigurations = state.mChangingConfigurations;
mTargetDensity = state.mTargetDensity;
@@ -391,12 +426,12 @@ public class NinePatchDrawable extends Drawable {
public Drawable newDrawable() {
return new NinePatchDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
return new NinePatchDrawable(this, res);
}
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;

View File

@@ -83,6 +83,13 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="LayoutInsetsTest" android:label="LayoutInsetsTest">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="@drawable/my_btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="@drawable/my_btn_default_normal" />
<item android:state_pressed="true"
android:drawable="@drawable/my_btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/my_btn_default_selected" />
<item android:state_enabled="true"
android:drawable="@drawable/my_btn_default_normal" />
<item android:state_focused="true"
android:drawable="@drawable/my_btn_default_normal_disable_focused" />
<item
android:drawable="@drawable/my_btn_default_normal_disable" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -17,7 +17,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:columnCount="2"
<Space
android:layout_row="0"
android:layout_column="0"

View File

@@ -0,0 +1,59 @@
package com.android.test.layout;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.Space;
import android.widget.TextView;
import static android.text.InputType.TYPE_CLASS_TEXT;
import static android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
import static android.widget.GridLayout.*;
import static android.widget.GridLayout.FILL;
import static android.widget.GridLayout.spec;
public class LayoutInsetsTest extends Activity {
public static View create(Context context) {
GridLayout p = new GridLayout(context);
p.setUseDefaultMargins(true);
p.setAlignmentMode(ALIGN_BOUNDS);
p.setOrientation(VERTICAL);
{
TextView c = new TextView(context);
c.setTextSize(32);
c.setText("Email setup");
p.addView(c);
}
{
Button c = new Button(context);
c.setBackgroundResource(R.drawable.btn_default);
c.setText("Manual setup");
p.addView(c);
c.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Button b = (Button) v;
b.setEnabled(false);
}
});
}
return p;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH;
getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN;
setContentView(create(this));
}
}