下面列出了android.view.Gravity#HORIZONTAL_GRAVITY_MASK 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private float calculateTranslationX(
@NonNull View dependency, @NonNull View child, @NonNull Positioning positioning) {
RectF dependencyBounds = tmpRectF1;
RectF childBounds = tmpRectF2;
calculateDependencyWindowBounds(dependency, dependencyBounds);
calculateWindowBounds(child, childBounds);
float translationX = 0f;
switch (positioning.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
translationX = childBounds.left - dependencyBounds.left;
break;
case Gravity.CENTER_HORIZONTAL:
translationX = childBounds.centerX() - dependencyBounds.centerX();
break;
case Gravity.RIGHT:
translationX = childBounds.right - dependencyBounds.right;
break;
default:
break;
}
translationX += positioning.xAdjustment;
return translationX;
}
/**
* Describes how the selected item view is positioned. Currently only the horizontal component
* is used. The default is determined by the current theme.
*
* @param gravity See {@link android.view.Gravity}
*
* @attr ref android.R.styleable#Spinner_gravity
*/
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.LEFT;
}
mGravity = gravity;
requestLayout();
}
}
private int getGravity(LayoutParams lp) {
int parentGravity = this.config.getGravity();
int childGravity;
// get childGravity of child view (if exists)
if (lp != null && lp.gravitySpecified()) {
childGravity = lp.getGravity();
} else {
childGravity = parentGravity;
}
childGravity = getGravityFromRelative(childGravity);
parentGravity = getGravityFromRelative(parentGravity);
// add parent gravity to child gravity if child gravity is not specified
if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
childGravity |= parentGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
}
if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
childGravity |= parentGravity & Gravity.VERTICAL_GRAVITY_MASK;
}
// if childGravity is still not specified - set default top - left gravity
if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
childGravity |= Gravity.LEFT;
}
if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
childGravity |= Gravity.TOP;
}
return childGravity;
}
public static void setWidthPercent(android.view.View view, float value) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params == null) {
params = new CommonLayoutParams();
}
if (params instanceof CommonLayoutParams) {
CommonLayoutParams lp = (CommonLayoutParams) params;
lp.widthPercent = value;
lp.width = (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT;
view.setLayoutParams(params);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void layoutChild(View child, int parentLeft, int parentTop, int parentRight, int parentBottom) {
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
final int childTop = parentTop + lp.topMargin;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = Gravity.TOP | Gravity.START;
}
final int layoutDirection;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutDirection = LAYOUT_DIRECTION_LTR;
} else {
layoutDirection = getLayoutDirection();
}
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 + lp.leftMargin - lp.rightMargin;
break;
case Gravity.END:
childLeft = parentRight - width - lp.rightMargin;
break;
case Gravity.START:
default:
childLeft = parentLeft + lp.leftMargin;
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
/**
* Position the children during a layout pass if the orientation of this
* LinearLayout is set to {@link #VERTICAL}.
*
* @see #getOrientation()
* @see #setOrientation(int)
* @see #onLayout(boolean, int, int, int, int)
* @param left
* @param top
* @param right
* @param bottom
*/
void layoutVertical(int left, int top, int right, int bottom) {
final int paddingLeft = mPaddingLeft;
int childTop;
int childLeft;
// Where right end of child should go
final int width = right - left;
int childRight = width - mPaddingRight;
// Space available for child
int childSpace = width - paddingLeft - mPaddingRight;
final int count = getVirtualChildCount();
final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
switch (majorGravity) {
case Gravity.BOTTOM:
// mTotalLength contains the padding already
childTop = mPaddingTop + bottom - top - mTotalLength;
break;
// mTotalLength contains the padding already
case Gravity.CENTER_VERTICAL:
childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
break;
case Gravity.TOP:
default:
childTop = mPaddingTop;
break;
}
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child == null) {
childTop += measureNullChild(i);
} else if (child.getVisibility() != GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
final LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) child.getLayoutParams();
int gravity = lp.gravity;
if (gravity < 0) {
gravity = minorGravity;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+ lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = childRight - childWidth - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = paddingLeft + lp.leftMargin;
break;
}
if (hasDividerBeforeChildAt(i)) {
childTop += mDividerHeight;
}
childTop += lp.topMargin;
setChildFrame(child, childLeft, childTop + getLocationOffset(child),
childWidth, childHeight);
childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
i += getChildrenSkipCount(child, i);
}
}
}
public void handleShow(IBinder windowToken) {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
// If a cancel/hide is pending - no need to show - at this point
// the window token is already invalid and no need to do any work.
if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {
return;
}
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
mView = mNextView;
Context context = mView.getContext().getApplicationContext();
String packageName = mView.getContext().getOpPackageName();
if (context == null) {
context = mView.getContext();
}
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
final Configuration config = mView.getContext().getResources().getConfiguration();
final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
mParams.packageName = packageName;
mParams.hideTimeoutMilliseconds = mDuration ==
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
mParams.token = windowToken;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
// Since the notification manager service cancels the token right
// after it notifies us to cancel the toast there is an inherent
// race and we may attempt to add a window after the token has been
// invalidated. Let us hedge against that.
try {
mWM.addView(mView, mParams);
trySendAccessibilityEvent();
} catch (WindowManager.BadTokenException e) {
/* ignore */
}
}
}
@Override
protected void onDraw(Canvas canvas) {
// If there's text of any sort resort to CompoundButton#onDraw
if (getText() != null && getText().length() > 0 ||
getTextOff() != null && getTextOff().length() > 0 ||
getTextOff() != null && getTextOn().length() > 0) {
super.onDraw(canvas);
}
// Otherwise override CompoundButton#onDraw entirely to allow properly aligned image toggles
else {
final Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(this);
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int horizontalGravity = getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth();
final int top;
switch (verticalGravity) {
case Gravity.BOTTOM:
top = getHeight() - drawableHeight;
break;
case Gravity.CENTER_VERTICAL:
top = (getHeight() - drawableHeight) / 2;
break;
default:
top = 0;
}
final int left;
switch (horizontalGravity) {
case Gravity.RIGHT:
case Gravity.END:
left = getWidth() - drawableWidth;
break;
case Gravity.CENTER_HORIZONTAL:
left = (getWidth() - drawableWidth) / 2;
break;
default:
left = 0;
}
final int bottom = top + drawableHeight;
final int right = left + drawableWidth;
buttonDrawable.setBounds(left, top, right, bottom);
final Drawable background = getBackground();
if (Build.VERSION.SDK_INT > 21 && background != null) {
background.setHotspotBounds(left, top, right, bottom);
}
buttonDrawable.draw(canvas);
}
}
}
private boolean isCheckMarkAtStart() {
final int gravity = Gravity.getAbsoluteGravity(mCheckMarkGravity, getLayoutDirection());
final int hgrav = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
return hgrav == Gravity.LEFT;
}
void layoutChildren(int left, int top, int right, int bottom,
boolean forceLeftGravity) {
final int count = getChildCount();
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
int symbolHeight = 0;
// 尽可能先找到Bottom View
for (int i = count - 1; i >= 0; 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();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = Gravity.NO_GRAVITY;
}
final int layoutDirection = ViewCompat.getLayoutDirection(this);
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
case Gravity.END:
if (!forceLeftGravity) {
childLeft = parentRight - width - lp.rightMargin;
break;
}
case Gravity.LEFT:
case Gravity.START:
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
symbolHeight = ((ViewGroup)child).getChildCount() > 0 ? ((ViewGroup)child).getChildAt(0).getMeasuredHeight() : 0;
float offset = mSlideOffset == 0 ? (symbolHeight == 0 ? 0.3f : symbolHeight / (float)height) : mSlideOffset;
childTop = parentBottom - (int) (height * offset);
// childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
/**
* Creates and positions all views for this Spinner.
*
* @param delta Change in the selected position. +1 means selection is moving to the right,
* so views are scrolling to the left. -1 means selection is moving to the left.
*/
@Override
void layout(int delta, boolean animate) {
int childrenLeft = mSpinnerPadding.left;
int childrenWidth = mRight - mLeft - mSpinnerPadding.left - mSpinnerPadding.right;
if (mDataChanged) {
handleDataChanged();
}
// Handle the empty set by removing all views
if (mItemCount == 0) {
resetList();
return;
}
if (mNextSelectedPosition >= 0) {
setSelectedPositionInt(mNextSelectedPosition);
}
recycleAllViews();
// Clear out old views
removeAllViewsInLayout();
// Make selected view and position it
mFirstPosition = mSelectedPosition;
if (mAdapter != null) {
View sel = makeView(mSelectedPosition, true);
int width = sel.getMeasuredWidth();
int selectedOffset = childrenLeft;
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
break;
case Gravity.RIGHT:
selectedOffset = childrenLeft + childrenWidth - width;
break;
}
sel.offsetLeftAndRight(selectedOffset);
}
// Flush any cached views that did not get reused above
mRecycler.clear();
invalidate();
checkSelectionChanged();
mDataChanged = false;
mNeedSync = false;
setNextSelectedPositionInt(mSelectedPosition);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
CommonLayoutParams.adjustChildrenLayoutParams(this, widthMeasureSpec, heightMeasureSpec);
int measureWidth = 0;
int measureHeight = 0;
int width = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int verticalPadding = this.getPaddingTop() + this.getPaddingBottom();
int horizontalPadding = this.getPaddingLeft() + this.getPaddingRight();
boolean infinityWidth = widthMode == MeasureSpec.UNSPECIFIED;
boolean infinityHeight = heightMode == MeasureSpec.UNSPECIFIED;
this.helper.width = Math.max(0, width - horizontalPadding);
this.helper.height = Math.max(0, height - verticalPadding);
int gravity = LayoutBase.getGravity(this);
int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
final int layoutDirection = this.getLayoutDirection();
final int horizontalGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection) & Gravity.HORIZONTAL_GRAVITY_MASK;
this.helper.stretchedHorizontally = widthMode == MeasureSpec.EXACTLY || (horizontalGravity == Gravity.FILL_HORIZONTAL && !infinityWidth);
this.helper.stretchedVertically = heightMode == MeasureSpec.EXACTLY || (verticalGravity == Gravity.FILL_VERTICAL && !infinityHeight);
this.helper.setInfinityWidth(infinityWidth);
this.helper.setInfinityHeight(infinityHeight);
this.helper.clearMeasureSpecs();
this.helper.init();
for (int i = 0, count = this.getChildCount(); i < count; i++) {
View child = this.getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
MeasureSpecs measureSpecs = this.map.get(child);
this.updateMeasureSpecs(child, measureSpecs);
this.helper.addMeasureSpec(measureSpecs);
}
this.helper.measure();
// Add in our padding
measureWidth = this.helper.measuredWidth + horizontalPadding;
measureHeight = this.helper.measuredHeight + verticalPadding;
// Check against our minimum sizes
measureWidth = Math.max(measureWidth, this.getSuggestedMinimumWidth());
measureHeight = Math.max(measureHeight, this.getSuggestedMinimumHeight());
int widthSizeAndState = resolveSizeAndState(measureWidth, widthMeasureSpec, 0);
int heightSizeAndState = resolveSizeAndState(measureHeight, heightMeasureSpec, 0);
this.setMeasuredDimension(widthSizeAndState, heightSizeAndState);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
if (isInEditMode()) {
// Don't crash the layout editor. Consume all of the space if specified
// or pick a magic number from thin air otherwise.
// TODO Better communication with tools of this bogus state.
// It will crash on a real device.
if (widthMode == MeasureSpec.AT_MOST) {
widthMode = MeasureSpec.EXACTLY;
} else if (widthMode == MeasureSpec.UNSPECIFIED) {
widthMode = MeasureSpec.EXACTLY;
widthSize = 300;
}
if (heightMode == MeasureSpec.AT_MOST) {
heightMode = MeasureSpec.EXACTLY;
}
else if (heightMode == MeasureSpec.UNSPECIFIED) {
heightMode = MeasureSpec.EXACTLY;
heightSize = 300;
}
} else {
throw new IllegalArgumentException(
"DrawerLayout must be measured with MeasureSpec.EXACTLY.");
}
}
setMeasuredDimension(widthSize, heightSize);
// Gravity value for each drawer we've seen. Only one of each permitted.
int foundDrawers = 0;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (isContentView(child)) {
// Content views get measured at exactly the layout's size.
final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
child.measure(contentWidthSpec, contentHeightSpec);
} else if (isDrawerView(child)) {
final int childGravity =
getDrawerViewGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
if ((foundDrawers & childGravity) != 0) {
throw new IllegalStateException("Child drawer has absolute gravity " +
gravityToString(childGravity) + " but this " + TAG + " already has a " +
"drawer view along that edge");
}
final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
lp.width);
final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
lp.topMargin + lp.bottomMargin,
lp.height);
child.measure(drawerWidthSpec, drawerHeightSpec);
} else {
throw new IllegalStateException("Child " + child + " at index " + i +
" does not have a valid layout_gravity - must be Gravity.LEFT, " +
"Gravity.RIGHT or Gravity.NO_GRAVITY");
}
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutCount--;
if (containerView != null) {
int t = (bottom - top) - containerView.getMeasuredHeight();
if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
left += lastInsets.getSystemWindowInsetLeft();
right -= lastInsets.getSystemWindowInsetRight();
t -= lastInsets.getSystemWindowInsetBottom() - (drawNavigationBar ? 0 : bottomInset);
if (Build.VERSION.SDK_INT >= 29) {
t -= getAdditionalMandatoryOffsets();
}
}
int l = ((right - left) - containerView.getMeasuredWidth()) / 2;
if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
l += lastInsets.getSystemWindowInsetLeft();
}
containerView.layout(l, t, l + containerView.getMeasuredWidth(), t + containerView.getMeasuredHeight());
}
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE || child == containerView) {
continue;
}
if (!onCustomLayout(child, left, top, right, bottom - (drawNavigationBar ? bottomInset : 0))) {
final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = Gravity.TOP | Gravity.LEFT;
}
final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = (right - left - width) / 2 + lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = right - width - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.CENTER_VERTICAL:
childTop = (bottom - top - height) / 2 + lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = (bottom - top) - height - lp.bottomMargin;
break;
default:
childTop = lp.topMargin;
}
if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
childLeft += lastInsets.getSystemWindowInsetLeft();
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
if (layoutCount == 0 && startAnimationRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(startAnimationRunnable);
startAnimationRunnable.run();
startAnimationRunnable = null;
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
final int parentLeft, parentRight;
if (mLayoutScaleX != 1f) {
final float pivotX = getPivotX();
parentLeft = getPaddingLeft() + (int)(pivotX - pivotX / mLayoutScaleX + 0.5f);
parentRight = (int)(pivotX + (right - left - pivotX) / mLayoutScaleX + 0.5f)
- getPaddingRight();
} else {
parentLeft = getPaddingLeft();
parentRight = right - left - getPaddingRight();
}
final int parentTop, parentBottom;
if (mLayoutScaleY != 1f) {
final float pivotY = getPivotY();
parentTop = getPaddingTop() + (int)(pivotY - pivotY / mLayoutScaleY + 0.5f);
parentBottom = (int)(pivotY + (bottom - top - pivotY) / mLayoutScaleY + 0.5f)
- getPaddingBottom();
} else {
parentTop = getPaddingTop();
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();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = parentRight - width - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
private void recompute(int width) {
if (text != null) {
// work out the top padding and line height to align text to a 4dp grid
final float fourDip = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
getResources().getDisplayMetrics());
// ensure that the first line's baselines sits on 4dp grid by setting the top padding
final Paint.FontMetricsInt fm = paint.getFontMetricsInt();
final int gridAlignedTopPadding = (int) (fourDip * (float)
Math.ceil((unalignedTopPadding + Math.abs(fm.ascent)) / fourDip)
- Math.ceil(Math.abs(fm.ascent)));
super.setPadding(
getPaddingLeft(), gridAlignedTopPadding, getPaddingTop(), getPaddingBottom());
// ensures line height is a multiple of 4dp
final int fontHeight = Math.abs(fm.ascent - fm.descent) + fm.leading;
final int baselineAlignedLineHeight =
(int) (fourDip * (float) Math.ceil(lineHeightHint / fourDip));
// before we can workout indents we need to know how many lines of text there are;
// so we need to create a temporary layout :(
layout = StaticLayout.Builder.obtain(text, 0, text.length(), paint, width)
.setLineSpacing(baselineAlignedLineHeight - fontHeight, 1f)
.setBreakStrategy(breakStrategy)
.build();
final int preIndentedLineCount = layout.getLineCount();
// now we can calculate the indents required for the given fab gravity
final boolean gravityTop = (fabGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP;
final boolean gravityLeft =
(fabGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT;
// we want to iterate forward/backward over the lines depending on whether the fab
// overlap vertical gravity is top/bottom
int currentLine = gravityTop ? 0 : preIndentedLineCount - 1;
int remainingHeightOverlap = fabOverlapHeight -
(gravityTop ? getPaddingTop() : getPaddingBottom());
final int[] leftIndents = new int[preIndentedLineCount];
final int[] rightIndents = new int[preIndentedLineCount];
do {
if (remainingHeightOverlap > 0) {
// still have overlap height to consume, set the appropriate indent
leftIndents[currentLine] = gravityLeft ? fabOverlapWidth : 0;
rightIndents[currentLine] = gravityLeft ? 0 : fabOverlapWidth;
remainingHeightOverlap -= baselineAlignedLineHeight;
} else {
// have consumed the overlap height: no indent
leftIndents[currentLine] = 0;
rightIndents[currentLine] = 0;
}
if (gravityTop) { // iterate forward over the lines
currentLine++;
} else { // iterate backward over the lines
currentLine--;
}
} while (gravityTop ? currentLine < preIndentedLineCount : currentLine >= 0);
// now that we know the indents, create the actual layout
layout = StaticLayout.Builder.obtain(text, 0, text.length(), paint, width)
.setLineSpacing(baselineAlignedLineHeight - fontHeight, 1f)
.setIndents(leftIndents, rightIndents)
.setBreakStrategy(breakStrategy)
.build();
// ensure that the view's height sits on the grid (as we've changed padding etc).
final int height = getPaddingTop() + layout.getHeight() + getPaddingBottom();
final float overhang = height % fourDip;
if (overhang != 0) {
super.setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
unalignedBottomPadding + (int) (fourDip - overhang));
}
}
}
private static int getMeasureSpec(View view, int parentMeasureSpec, boolean horizontal) {
int parentLength = MeasureSpec.getSize(parentMeasureSpec);
int parentSpecMode = MeasureSpec.getMode(parentMeasureSpec);
CommonLayoutParams lp = (CommonLayoutParams) view.getLayoutParams();
final int margins = horizontal ? lp.leftMargin + lp.rightMargin : lp.topMargin + lp.bottomMargin;
int resultSize = 0;
int resultMode = MeasureSpec.UNSPECIFIED;
int measureLength = Math.max(0, parentLength - margins);
int childLength = horizontal ? lp.width : lp.height;
// We want a specific size... let be it.
if (childLength >= 0) {
if (parentSpecMode != MeasureSpec.UNSPECIFIED) {
resultSize = Math.min(parentLength, childLength);
} else {
resultSize = childLength;
}
resultMode = MeasureSpec.EXACTLY;
} else {
switch (parentSpecMode) {
// Parent has imposed an exact size on us
case MeasureSpec.EXACTLY:
resultSize = measureLength;
int gravity = LayoutBase.getGravity(view);
boolean stretched;
if (horizontal) {
final int horizontalGravity = Gravity.getAbsoluteGravity(gravity, view.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
stretched = horizontalGravity == Gravity.FILL_HORIZONTAL;
} else {
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
stretched = verticalGravity == Gravity.FILL_VERTICAL;
}
// if stretched - view wants to be our size. So be it.
// else - view wants to determine its own size. It can't be bigger than us.
resultMode = stretched ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
break;
// Parent has imposed a maximum size on us
case MeasureSpec.AT_MOST:
resultSize = measureLength;
resultMode = MeasureSpec.AT_MOST;
break;
case MeasureSpec.UNSPECIFIED:
resultSize = 0;
resultMode = MeasureSpec.UNSPECIFIED;
break;
}
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
/**
* Creates and positions all views for this Spinner.
*
* @param delta Change in the selected position. +1 moves selection is moving to the right,
* so views are scrolling to the left. -1 means selection is moving to the left.
*/
@Override
void layout(int delta, boolean animate) {
int childrenLeft = mSpinnerPadding.left;
int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;
if (mDataChanged) {
handleDataChanged();
}
// Handle the empty set by removing all views
if (mItemCount == 0) {
resetList();
return;
}
if (mNextSelectedPosition >= 0) {
setSelectedPositionInt(mNextSelectedPosition);
}
recycleAllViews();
// Clear out old views
removeAllViewsInLayout();
// Make selected view and position it
mFirstPosition = mSelectedPosition;
View sel = makeAndAddView(mSelectedPosition);
int width = sel.getMeasuredWidth();
int selectedOffset = childrenLeft;
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
break;
case Gravity.RIGHT:
selectedOffset = childrenLeft + childrenWidth - width;
break;
}
sel.offsetLeftAndRight(selectedOffset);
// Flush any cached views that did not get reused above
mRecycler.clear();
invalidate();
checkSelectionChanged();
mDataChanged = false;
mNeedSync = false;
setNextSelectedPositionInt(mSelectedPosition);
}
@Override
public void onClick(View v) {
final ActionBar bar = getSupportActionBar();
int flags = 0;
switch (v.getId()) {
case R.id.toggle_home_as_up:
flags = ActionBar.DISPLAY_HOME_AS_UP;
break;
case R.id.toggle_show_home:
flags = ActionBar.DISPLAY_SHOW_HOME;
break;
case R.id.toggle_use_logo:
flags = ActionBar.DISPLAY_USE_LOGO;
break;
case R.id.toggle_show_title:
flags = ActionBar.DISPLAY_SHOW_TITLE;
break;
case R.id.toggle_show_custom:
flags = ActionBar.DISPLAY_SHOW_CUSTOM;
break;
case R.id.toggle_navigation:
bar.setNavigationMode(
bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD
? ActionBar.NAVIGATION_MODE_TABS
: ActionBar.NAVIGATION_MODE_STANDARD);
return;
case R.id.cycle_custom_gravity: {
ActionBar.LayoutParams lp = mCustomViewLayoutParams;
int newGravity = 0;
switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
newGravity = Gravity.CENTER_HORIZONTAL;
break;
case Gravity.CENTER_HORIZONTAL:
newGravity = Gravity.RIGHT;
break;
case Gravity.RIGHT:
newGravity = Gravity.LEFT;
break;
}
lp.gravity = lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK | newGravity;
bar.setCustomView(mCustomView, lp);
return;
}
case R.id.toggle_visibility:
if (bar.isShowing()) {
bar.hide();
} else {
bar.show();
}
return;
}
int change = bar.getDisplayOptions() ^ flags;
bar.setDisplayOptions(change, flags);
}
public void onClick(View v) {
final ActionBar bar = getActionBar();
int flags = 0;
switch (v.getId()) {
case R.id.toggle_home_as_up:
flags = ActionBar.DISPLAY_HOME_AS_UP;
break;
case R.id.toggle_show_home:
flags = ActionBar.DISPLAY_SHOW_HOME;
break;
case R.id.toggle_use_logo:
flags = ActionBar.DISPLAY_USE_LOGO;
break;
case R.id.toggle_show_title:
flags = ActionBar.DISPLAY_SHOW_TITLE;
break;
case R.id.toggle_show_custom:
flags = ActionBar.DISPLAY_SHOW_CUSTOM;
break;
case R.id.toggle_navigation:
bar.setNavigationMode(
bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD
? ActionBar.NAVIGATION_MODE_TABS
: ActionBar.NAVIGATION_MODE_STANDARD);
return;
case R.id.cycle_custom_gravity:
ActionBar.LayoutParams lp = (ActionBar.LayoutParams) mCustomView.getLayoutParams();
int newGravity = 0;
switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
newGravity = Gravity.CENTER_HORIZONTAL;
break;
case Gravity.CENTER_HORIZONTAL:
newGravity = Gravity.RIGHT;
break;
case Gravity.RIGHT:
newGravity = Gravity.LEFT;
break;
}
lp.gravity = lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK | newGravity;
bar.setCustomView(mCustomView, lp);
return;
}
int change = bar.getDisplayOptions() ^ flags;
bar.setDisplayOptions(change, flags);
}