Improve GLView
This commit is contained in:
1 parent
ad081dd962
commit
8bfffcda1f
2 files changed
+534
-22
No files matched your search
@@ -279,6 +279,8 @@ public class GLRootView extends GLSurfaceView
|
||||
}
|
||||
Log.i(TAG, "layout content pane " + w + "x" + h + " (compensation " + mCompensation + ")");
|
||||
if (mContentView != null && w != 0 && h != 0) {
|
||||
mContentView.measure(GLView.MeasureSpec.makeMeasureSpec(w, GLView.MeasureSpec.EXACTLY),
|
||||
GLView.MeasureSpec.makeMeasureSpec(h, GLView.MeasureSpec.EXACTLY));
|
||||
mContentView.layout(0, 0, w, h);
|
||||
}
|
||||
// Uncomment this to dump the view hierarchy.
|
||||
@@ -631,6 +633,11 @@ public class GLRootView extends GLSurfaceView
|
||||
protected void onDetachedFromWindow() {
|
||||
unfreeze();
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
// TODO Is it right ?
|
||||
if (mContentView != null) {
|
||||
mContentView.detachFromRoot();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.hippo.ehviewer.gallery.ui;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
@@ -24,6 +25,7 @@ import android.view.MotionEvent;
|
||||
import com.hippo.ehviewer.gallery.anim.CanvasAnimation;
|
||||
import com.hippo.ehviewer.gallery.anim.StateTransitionAnimation;
|
||||
import com.hippo.ehviewer.gallery.glrenderer.GLCanvas;
|
||||
import com.hippo.ehviewer.gallery.glrenderer.GLPaint;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,6 +48,8 @@ import java.util.ArrayList;
|
||||
public class GLView {
|
||||
private static final String TAG = "GLView";
|
||||
|
||||
private static final boolean DEBUG_DRAW_BOUNDS = false;
|
||||
|
||||
public static final int VISIBLE = 0;
|
||||
public static final int INVISIBLE = 1;
|
||||
|
||||
@@ -57,7 +61,16 @@ public class GLView {
|
||||
void onClick(GLView v);
|
||||
}
|
||||
|
||||
protected final static GLPaint mDrawBoundsPaint;
|
||||
|
||||
static {
|
||||
mDrawBoundsPaint = new GLPaint();
|
||||
mDrawBoundsPaint.setColor(Color.RED);
|
||||
mDrawBoundsPaint.setLineWidth(2);
|
||||
}
|
||||
|
||||
protected final Rect mBounds = new Rect();
|
||||
private final Rect mRenderCheckBounds = new Rect();
|
||||
protected final Rect mPaddings = new Rect();
|
||||
|
||||
private GLRoot mRoot;
|
||||
@@ -80,6 +93,20 @@ public class GLView {
|
||||
protected int mScrollHeight = 0;
|
||||
protected int mScrollWidth = 0;
|
||||
|
||||
/**
|
||||
* The minimum height of the view. We'll try our best to have the height
|
||||
* of this view to at least this amount.
|
||||
*/
|
||||
private int mMinHeight;
|
||||
|
||||
/**
|
||||
* The minimum width of the view. We'll try our best to have the width
|
||||
* of this view to at least this amount.
|
||||
*/
|
||||
private int mMinWidth;
|
||||
|
||||
private LayoutParams mLayoutParams;
|
||||
|
||||
private float [] mBackgroundColor;
|
||||
private StateTransitionAnimation mTransition;
|
||||
|
||||
@@ -118,6 +145,7 @@ public class GLView {
|
||||
onAttachToRoot(root);
|
||||
}
|
||||
|
||||
// TODO It is not called when the
|
||||
// This should only be called on the content pane (the topmost GLView).
|
||||
public void detachFromRoot() {
|
||||
AssertUtils.assertTrue(mParent == null && mRoot != null);
|
||||
@@ -139,15 +167,46 @@ public class GLView {
|
||||
|
||||
// Adds a child to this GLView.
|
||||
public void addComponent(GLView component) {
|
||||
addComponent(component, -1, null);
|
||||
}
|
||||
|
||||
public void addComponent(GLView component, int index) {
|
||||
addComponent(component, index, null);
|
||||
}
|
||||
|
||||
public void addComponent(GLView component, LayoutParams params) {
|
||||
addComponent(component, -1, params);
|
||||
}
|
||||
|
||||
public void addComponent(GLView component, int index, LayoutParams params) {
|
||||
// Make component is not null
|
||||
if (component == null) {
|
||||
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
|
||||
}
|
||||
// Make sure the component doesn't have a parent currently.
|
||||
if (component.mParent != null) throw new IllegalStateException();
|
||||
if (component.mParent != null) {
|
||||
throw new IllegalStateException(
|
||||
"Component " + this + " being added, but it already has a parent");
|
||||
}
|
||||
|
||||
// Ensure index is valid
|
||||
if (index < 0) {
|
||||
index = getComponentCount();
|
||||
}
|
||||
|
||||
// Ensure params is valid
|
||||
if (!checkLayoutParams(params)) {
|
||||
params = generateLayoutParams(params);
|
||||
}
|
||||
|
||||
// Build parent-child links
|
||||
if (mComponents == null) {
|
||||
mComponents = new ArrayList<GLView>();
|
||||
mComponents = new ArrayList<>();
|
||||
}
|
||||
mComponents.add(component);
|
||||
|
||||
mComponents.add(index, component);
|
||||
component.mParent = this;
|
||||
component.setLayoutParams(params);
|
||||
|
||||
// If this is added after we have a root, tell the component.
|
||||
if (mRoot != null) {
|
||||
@@ -165,6 +224,19 @@ public class GLView {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeComponentAt(int index) {
|
||||
if (mComponents == null) {
|
||||
return false;
|
||||
}
|
||||
if (index >= 0 && index < getComponentCount()) {
|
||||
GLView component = mComponents.remove(index);
|
||||
removeOneComponent(component);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Removes all children of this GLView.
|
||||
public void removeAllComponents() {
|
||||
for (int i = 0, n = mComponents.size(); i < n; ++i) {
|
||||
@@ -197,6 +269,30 @@ public class GLView {
|
||||
return mBounds.bottom - mBounds.top;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset this GLView's vertical location by the specified number of pixels.
|
||||
*
|
||||
* @param offset the number of pixels to offset the view by
|
||||
*/
|
||||
public void offsetTopAndBottom(int offset) {
|
||||
if (offset != 0){
|
||||
mBounds.offset(0, offset);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset this GLView's horizontal location by the specified amount of pixels.
|
||||
*
|
||||
* @param offset the number of pixels to offset the view by
|
||||
*/
|
||||
public void offsetLeftAndRight(int offset) {
|
||||
if (offset != 0){
|
||||
mBounds.offset(offset, 0);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public GLRoot getGLRoot() {
|
||||
return mRoot;
|
||||
}
|
||||
@@ -211,8 +307,8 @@ public class GLView {
|
||||
// Request re-layout of the view hierarchy.
|
||||
public void requestLayout() {
|
||||
mViewFlags |= FLAG_LAYOUT_REQUESTED;
|
||||
mLastHeightSpec = -1;
|
||||
mLastWidthSpec = -1;
|
||||
mLastHeightSpec = -1;
|
||||
if (mParent != null) {
|
||||
mParent.requestLayout();
|
||||
} else {
|
||||
@@ -229,19 +325,31 @@ public class GLView {
|
||||
transitionActive = mTransition.isActive();
|
||||
}
|
||||
renderBackground(canvas);
|
||||
onRender(canvas);
|
||||
canvas.save();
|
||||
if (transitionActive) {
|
||||
mTransition.applyContentTransform(this, canvas);
|
||||
}
|
||||
for (int i = 0, n = getComponentCount(); i < n; ++i) {
|
||||
renderChild(canvas, getComponent(i));
|
||||
GLView component = getComponent(i);
|
||||
if (Rect.intersects(mRenderCheckBounds, component.mBounds)) {
|
||||
renderChild(canvas, getComponent(i));
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
if (DEBUG_DRAW_BOUNDS) {
|
||||
canvas.drawRect(0, 0, getWidth(), getHeight(), mDrawBoundsPaint);
|
||||
}
|
||||
|
||||
if (transitionActive) {
|
||||
mTransition.applyOverlay(this, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onRender(GLCanvas canvas) {
|
||||
}
|
||||
|
||||
public void setIntroAnimation(StateTransitionAnimation intro) {
|
||||
mTransition = intro;
|
||||
if (mTransition != null) mTransition.start();
|
||||
@@ -347,39 +455,97 @@ public class GLView {
|
||||
|
||||
public void layout(int left, int top, int right, int bottom) {
|
||||
boolean sizeChanged = setBounds(left, top, right, bottom);
|
||||
final boolean forceLayout = (mViewFlags & FLAG_LAYOUT_REQUESTED) == FLAG_LAYOUT_REQUESTED;
|
||||
if (sizeChanged || forceLayout) {
|
||||
onLayout(sizeChanged, left, top, right, bottom);
|
||||
}
|
||||
mViewFlags &= ~FLAG_LAYOUT_REQUESTED;
|
||||
// We call onLayout no matter sizeChanged is true or not because the
|
||||
// orientation may change without changing the size of the View (for
|
||||
// example, rotate the device by 180 degrees), and we want to handle
|
||||
// orientation change in onLayout.
|
||||
onLayout(sizeChanged, left, top, right, bottom);
|
||||
}
|
||||
|
||||
private boolean setBounds(int left, int top, int right, int bottom) {
|
||||
boolean sizeChanged = (right - left) != (mBounds.right - mBounds.left)
|
||||
|| (bottom - top) != (mBounds.bottom - mBounds.top);
|
||||
mBounds.set(left, top, right, bottom);
|
||||
mRenderCheckBounds.set(0, 0, right - left, bottom - top);
|
||||
return sizeChanged;
|
||||
}
|
||||
|
||||
public void measure(int widthSpec, int heightSpec) {
|
||||
if (widthSpec == mLastWidthSpec && heightSpec == mLastHeightSpec
|
||||
&& (mViewFlags & FLAG_LAYOUT_REQUESTED) == 0) {
|
||||
return;
|
||||
}
|
||||
final boolean forceLayout = (mViewFlags & FLAG_LAYOUT_REQUESTED) == FLAG_LAYOUT_REQUESTED;
|
||||
final boolean isExactly = MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY &&
|
||||
MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY;
|
||||
final boolean matchingSize = isExactly &&
|
||||
getMeasuredWidth() == MeasureSpec.getSize(widthSpec) &&
|
||||
getMeasuredHeight() == MeasureSpec.getSize(heightSpec);
|
||||
if (forceLayout || !matchingSize &&
|
||||
(widthSpec != mLastWidthSpec ||
|
||||
heightSpec != mLastHeightSpec)) {
|
||||
mLastWidthSpec = widthSpec;
|
||||
mLastHeightSpec = heightSpec;
|
||||
|
||||
mLastWidthSpec = widthSpec;
|
||||
mLastHeightSpec = heightSpec;
|
||||
|
||||
mViewFlags &= ~FLAG_SET_MEASURED_SIZE;
|
||||
onMeasure(widthSpec, heightSpec);
|
||||
if ((mViewFlags & FLAG_SET_MEASURED_SIZE) == 0) {
|
||||
throw new IllegalStateException(getClass().getName()
|
||||
+ " should call setMeasuredSize() in onMeasure()");
|
||||
mViewFlags &= ~FLAG_SET_MEASURED_SIZE;
|
||||
onMeasure(widthSpec, heightSpec);
|
||||
if ((mViewFlags & FLAG_SET_MEASURED_SIZE) == 0) {
|
||||
throw new IllegalStateException(getClass().getName()
|
||||
+ " should call setMeasuredSize() in onMeasure()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onMeasure(int widthSpec, int heightSpec) {
|
||||
setMeasuredSize(getDefaultSize(getMinimumWidth(), widthSpec),
|
||||
getDefaultSize(getMinimumHeight(), heightSpec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum height of the view.
|
||||
*
|
||||
* @return the minimum height the view will try to be.
|
||||
*
|
||||
* @see #setMinimumHeight(int)
|
||||
*/
|
||||
public int getMinimumHeight() {
|
||||
return mMinHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum height of the view. It is not guaranteed the view will
|
||||
* be able to achieve this minimum height (for example, if its parent layout
|
||||
* constrains it with less available height).
|
||||
*
|
||||
* @param minHeight The minimum height the view will try to be.
|
||||
*
|
||||
* @see #getMinimumHeight()
|
||||
*/
|
||||
public void setMinimumHeight(int minHeight) {
|
||||
mMinHeight = minHeight;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum width of the view.
|
||||
*
|
||||
* @return the minimum width the view will try to be.
|
||||
*
|
||||
* @see #setMinimumWidth(int)
|
||||
*/
|
||||
public int getMinimumWidth() {
|
||||
return mMinWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum width of the view. It is not guaranteed the view will
|
||||
* be able to achieve this minimum width (for example, if its parent layout
|
||||
* constrains it with less available width).
|
||||
*
|
||||
* @param minWidth The minimum width the view will try to be.
|
||||
*
|
||||
* @see #getMinimumWidth()
|
||||
*/
|
||||
public void setMinimumWidth(int minWidth) {
|
||||
mMinWidth = minWidth;
|
||||
requestLayout();
|
||||
|
||||
}
|
||||
|
||||
protected void setMeasuredSize(int width, int height) {
|
||||
@@ -400,6 +566,143 @@ public class GLView {
|
||||
boolean changeSize, int left, int top, int right, int bottom) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to return a default size. Uses the supplied size if the
|
||||
* MeasureSpec imposed no constraints. Will get larger if allowed
|
||||
* by the MeasureSpec.
|
||||
*
|
||||
* @param size Default size for this view
|
||||
* @param measureSpec Constraints imposed by the parent
|
||||
* @return The size this view should be.
|
||||
*/
|
||||
public static int getDefaultSize(int size, int measureSpec) {
|
||||
int result = size;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
switch (specMode) {
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = size;
|
||||
break;
|
||||
case MeasureSpec.EXACTLY:
|
||||
result = specSize;
|
||||
break;
|
||||
case MeasureSpec.AT_MOST:
|
||||
return size == 0 ? specSize : Math.min(size, specSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int getComponentSpec(int spec, int childSize) {
|
||||
int specMode = MeasureSpec.getMode(spec);
|
||||
int specSize = MeasureSpec.getSize(spec);
|
||||
|
||||
int size = Math.max(0, specSize);
|
||||
|
||||
int resultSize = 0;
|
||||
int resultMode = 0;
|
||||
|
||||
switch (specMode) {
|
||||
// Parent has imposed an exact size on us
|
||||
case MeasureSpec.EXACTLY:
|
||||
if (childSize >= 0) {
|
||||
resultSize = childSize;
|
||||
resultMode = MeasureSpec.EXACTLY;
|
||||
} else if (childSize == LayoutParams.MATCH_PARENT) {
|
||||
// Child wants to be our size. So be it.
|
||||
resultSize = size;
|
||||
resultMode = MeasureSpec.EXACTLY;
|
||||
} else if (childSize == LayoutParams.WRAP_CONTENT) {
|
||||
// Child wants to determine its own size. It can't be
|
||||
// bigger than us.
|
||||
resultSize = size;
|
||||
resultMode = MeasureSpec.AT_MOST;
|
||||
}
|
||||
break;
|
||||
|
||||
// Parent has imposed a maximum size on us
|
||||
case MeasureSpec.AT_MOST:
|
||||
if (childSize >= 0) {
|
||||
// Child wants a specific size... so be it
|
||||
resultSize = childSize;
|
||||
resultMode = MeasureSpec.EXACTLY;
|
||||
} else if (childSize == LayoutParams.MATCH_PARENT) {
|
||||
// Child wants to be our size, but our size is not fixed.
|
||||
// Constrain child to not be bigger than us.
|
||||
resultSize = size;
|
||||
resultMode = MeasureSpec.AT_MOST;
|
||||
} else if (childSize == LayoutParams.WRAP_CONTENT) {
|
||||
// Child wants to determine its own size. It can't be
|
||||
// bigger than us.
|
||||
resultSize = size;
|
||||
resultMode = MeasureSpec.AT_MOST;
|
||||
}
|
||||
break;
|
||||
|
||||
// Parent asked to see how big we want to be
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
if (childSize >= 0) {
|
||||
// Child wants a specific size... let him have it
|
||||
resultSize = childSize;
|
||||
resultMode = MeasureSpec.EXACTLY;
|
||||
} else if (childSize == LayoutParams.MATCH_PARENT) {
|
||||
// Child wants to be our size... find out how big it should
|
||||
// be
|
||||
resultSize = 0;
|
||||
resultMode = MeasureSpec.UNSPECIFIED;
|
||||
} else if (childSize == LayoutParams.WRAP_CONTENT) {
|
||||
// Child wants to determine its own size.... find out how
|
||||
// big it should be
|
||||
resultSize = 0;
|
||||
resultMode = MeasureSpec.UNSPECIFIED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
|
||||
}
|
||||
|
||||
public static void measureComponent(GLView component, int widthSpec, int heightSpec) {
|
||||
final LayoutParams lp = component.getLayoutParams();
|
||||
final int componentWidthSpec = getComponentSpec(widthSpec, lp.width);
|
||||
final int componentHeightSpec = getComponentSpec(heightSpec, lp.height);
|
||||
component.measure(componentWidthSpec, componentHeightSpec);
|
||||
}
|
||||
|
||||
public static void measureAllComponents(GLView parent, int widthSpec, int heightSpec) {
|
||||
for (int i = 0, n = parent.getComponentCount(); i < n; i++) {
|
||||
GLView component = parent.getComponent(i);
|
||||
measureComponent(component, widthSpec, heightSpec);
|
||||
}
|
||||
}
|
||||
|
||||
public LayoutParams getLayoutParams() {
|
||||
return mLayoutParams;
|
||||
}
|
||||
|
||||
public void setLayoutParams(LayoutParams params) {
|
||||
if (params == null) {
|
||||
if (mParent == null) {
|
||||
throw new NullPointerException("Layout parameters cannot be null");
|
||||
} else {
|
||||
params = mParent.generateDefaultLayoutParams();
|
||||
}
|
||||
}
|
||||
mLayoutParams = params;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
protected boolean checkLayoutParams(LayoutParams p) {
|
||||
return p != null;
|
||||
}
|
||||
|
||||
protected LayoutParams generateDefaultLayoutParams() {
|
||||
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
protected LayoutParams generateLayoutParams(LayoutParams p) {
|
||||
return new LayoutParams(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounds of the given descendant that relative to this view.
|
||||
*/
|
||||
@@ -462,4 +765,206 @@ public class GLView {
|
||||
getComponent(i).dumpTree(prefix + "....");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
|
||||
* Each MeasureSpec represents a requirement for either the width or the height.
|
||||
* A MeasureSpec is comprised of a size and a mode. There are three possible
|
||||
* modes:
|
||||
* <dl>
|
||||
* <dt>UNSPECIFIED</dt>
|
||||
* <dd>
|
||||
* The parent has not imposed any constraint on the child. It can be whatever size
|
||||
* it wants.
|
||||
* </dd>
|
||||
*
|
||||
* <dt>EXACTLY</dt>
|
||||
* <dd>
|
||||
* The parent has determined an exact size for the child. The child is going to be
|
||||
* given those bounds regardless of how big it wants to be.
|
||||
* </dd>
|
||||
*
|
||||
* <dt>AT_MOST</dt>
|
||||
* <dd>
|
||||
* The child can be as large as it wants up to the specified size.
|
||||
* </dd>
|
||||
* </dl>
|
||||
*
|
||||
* MeasureSpecs are implemented as ints to reduce object allocation. This class
|
||||
* is provided to pack and unpack the <size, mode> tuple into the int.
|
||||
*/
|
||||
public static class MeasureSpec {
|
||||
private static final int MODE_SHIFT = 30;
|
||||
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
|
||||
|
||||
/**
|
||||
* Measure specification mode: The parent has not imposed any constraint
|
||||
* on the child. It can be whatever size it wants.
|
||||
*/
|
||||
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
|
||||
|
||||
/**
|
||||
* Measure specification mode: The parent has determined an exact size
|
||||
* for the child. The child is going to be given those bounds regardless
|
||||
* of how big it wants to be.
|
||||
*/
|
||||
public static final int EXACTLY = 1 << MODE_SHIFT;
|
||||
|
||||
/**
|
||||
* Measure specification mode: The child can be as large as it wants up
|
||||
* to the specified size.
|
||||
*/
|
||||
public static final int AT_MOST = 2 << MODE_SHIFT;
|
||||
|
||||
/**
|
||||
* The max size allowed
|
||||
*/
|
||||
public static final int MAX_SIZE = ~MODE_MASK;
|
||||
|
||||
/**
|
||||
* Creates a measure specification based on the supplied size and mode.
|
||||
*
|
||||
* The mode must always be one of the following:
|
||||
* <ul>
|
||||
* <li>{@link #UNSPECIFIED}</li>
|
||||
* <li>{@link #EXACTLY}</li>
|
||||
* <li>{@link #AT_MOST}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
|
||||
* implementation was such that the order of arguments did not matter
|
||||
* and overflow in either value could impact the resulting MeasureSpec.
|
||||
* {@link android.widget.RelativeLayout} was affected by this bug.
|
||||
* Apps targeting API levels greater than 17 will get the fixed, more strict
|
||||
* behavior.</p>
|
||||
*
|
||||
* @param size the size of the measure specification
|
||||
* @param mode the mode of the measure specification
|
||||
* @return the measure specification based on size and mode
|
||||
*/
|
||||
public static int makeMeasureSpec(int size, int mode) {
|
||||
return (size & ~MODE_MASK) | (mode & MODE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the mode from the supplied measure specification.
|
||||
*
|
||||
* @param measureSpec the measure specification to extract the mode from
|
||||
* @return {@link #UNSPECIFIED},
|
||||
* {@link #AT_MOST} or
|
||||
* {@link #EXACTLY}
|
||||
*/
|
||||
public static int getMode(int measureSpec) {
|
||||
return (measureSpec & MODE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the size from the supplied measure specification.
|
||||
*
|
||||
* @param measureSpec the measure specification to extract the size from
|
||||
* @return the size in pixels defined in the supplied measure specification
|
||||
*/
|
||||
public static int getSize(int measureSpec) {
|
||||
return (measureSpec & ~MODE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of the specified measure
|
||||
* specification.
|
||||
*
|
||||
* @param measureSpec the measure specification to convert to a String
|
||||
* @return a String with the following format: "MeasureSpec: MODE SIZE"
|
||||
*/
|
||||
public static String toString(int measureSpec) {
|
||||
int mode = getMode(measureSpec);
|
||||
int size = getSize(measureSpec);
|
||||
|
||||
StringBuilder sb = new StringBuilder("MeasureSpec: ");
|
||||
|
||||
if (mode == UNSPECIFIED)
|
||||
sb.append("UNSPECIFIED ");
|
||||
else if (mode == EXACTLY)
|
||||
sb.append("EXACTLY ");
|
||||
else if (mode == AT_MOST)
|
||||
sb.append("AT_MOST ");
|
||||
else
|
||||
sb.append(mode).append(" ");
|
||||
|
||||
sb.append(size);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The LayoutParams look like {@link android.view.ViewGroup.LayoutParams},
|
||||
* and work like it.
|
||||
*/
|
||||
public static class LayoutParams {
|
||||
|
||||
/**
|
||||
* Special value for the height or width requested by a View.
|
||||
* MATCH_PARENT means that the view wants to be as big as its parent,
|
||||
* minus the parent's padding, if any. Introduced in API Level 8.
|
||||
*/
|
||||
public static final int MATCH_PARENT = -1;
|
||||
|
||||
/**
|
||||
* Special value for the height or width requested by a View.
|
||||
* WRAP_CONTENT means that the view wants to be just large enough to fit
|
||||
* its own internal content, taking its own padding into account.
|
||||
*/
|
||||
public static final int WRAP_CONTENT = -2;
|
||||
|
||||
/**
|
||||
* Information about how wide the view wants to be. Can be one of the
|
||||
* constants {@link #MATCH_PARENT} or {@link #WRAP_CONTENT} or an exact size.
|
||||
*/
|
||||
public int width;
|
||||
|
||||
/**
|
||||
* Information about how tall the view wants to be. Can be one of the
|
||||
* constants {@link #MATCH_PARENT} or {@link #WRAP_CONTENT} or an exact size.
|
||||
*/
|
||||
public int height;
|
||||
|
||||
/**
|
||||
* Creates a new set of layout parameters with the specified width
|
||||
* and height.
|
||||
*
|
||||
* @param width the width, either {@link #WRAP_CONTENT},
|
||||
* {@link #MATCH_PARENT}, or a fixed size in pixels
|
||||
* @param height the height, either {@link #WRAP_CONTENT},
|
||||
* {@link #MATCH_PARENT}, or a fixed size in pixels
|
||||
*/
|
||||
public LayoutParams(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. Clones the width and height values of the source.
|
||||
*
|
||||
* @param source The layout params to copy from.
|
||||
*/
|
||||
public LayoutParams(LayoutParams source) {
|
||||
this.width = source.width;
|
||||
this.height = source.height;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LayoutParams with gravity inside
|
||||
*/
|
||||
public static class GravityLayoutParams extends LayoutParams {
|
||||
|
||||
public int gravity = Gravity.NO_GRAVITY;
|
||||
|
||||
public GravityLayoutParams(GLView.LayoutParams source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public GravityLayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user