Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4472)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java

Issue 177863008: Update the AppBannerView appearance again (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressing comments hopefully Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java
index 32c2070944b3f71bdfb4e714c0c5a7de76db0fe6..3a302520a668e9696fb1e467158bd5eaa828f82b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java
@@ -8,10 +8,10 @@ import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -25,9 +25,29 @@ import org.chromium.ui.base.LocalizationUtils;
/**
* Lays out a banner for showing info about an app on the Play Store.
- * Rather than utilizing the Android RatingBar, which would require some nasty styling, a custom
- * View is used to paint a Drawable showing all the stars. Showing different ratings is done by
- * adjusting the clipping rectangle width.
+ * The banner mimics the appearance of a Google Now card using a background Drawable with a shadow.
+ *
+ * PADDING CALCULATIONS
+ * The banner has three different types of padding that need to be accounted for:
+ * 1) The background Drawable of the banner looks like card with a drop shadow. The Drawable
+ * defines a padding around the card that solely encompasses the space occupied by the drop
+ * shadow.
+ * 2) The card itself needs to have padding so that the widgets don't abut the borders of the card.
+ * This is defined as mPaddingCard, and is equally applied to all four sides.
+ * 3) Controls other than the icon are further constrained by mPaddingControls, which applies only
+ * to the bottom and end margins.
+ * See {@link #AppBannerView.onMeasure(int, int)} for details.
+ *
+ * MARGIN CALCULATIONS
+ * Margin calculations for the banner are complicated by the background Drawable's drop shadows,
+ * since the drop shadows are meant to be counted as being part of the margin. To deal with this,
+ * the margins are calculated by deducting the background Drawable's padding from the margins
+ * defined by the XML files.
+ *
+ * EVEN MORE LAYOUT QUIRKS
+ * The layout of the banner, which includes its widget sizes, may change when the screen is rotated
+ * to account for less screen real estate. This means that all of the View's widgets and cached
+ * dimensions must be rebuilt from scratch.
*/
public class AppBannerView extends SwipableOverlayView implements View.OnClickListener {
/**
@@ -53,9 +73,15 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
public void onBannerClicked(AppBannerView banner);
}
+ // Number of milliseconds to wait before showing the card highlight.
+ private static final long MS_HIGHLIGHT_APPEARANCE = 150;
+
// XML layout for the BannerView.
private static final int BANNER_LAYOUT = R.layout.app_banner_view;
+ // Maximum distance the finger can travel before dismissing the highlight.
+ private static final float HIGHLIGHT_DISTANCE = 20;
+
// True if the layout is in left-to-right layout mode (regular mode).
private final boolean mIsLayoutLTR;
@@ -67,23 +93,24 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
private TextView mTitleView;
private Button mButtonView;
private RatingView mRatingView;
- private ImageView mLogoView;
+ private View mLogoView;
+ private View mBannerHighlightView;
// Information about the package.
private AppData mAppData;
- // Variables used during layout calculations and saved to avoid reallocations.
- private final Point mSpaceMain;
- private final Point mSpaceForLogo;
- private final Point mSpaceForRating;
- private final Point mSpaceForTitle;
-
// Dimension values.
private int mDefinedMaxWidth;
- private int mPaddingContent;
- private int mMarginSide;
+ private int mPaddingCard;
+ private int mPaddingControls;
+ private int mMarginLeft;
+ private int mMarginRight;
private int mMarginBottom;
+ // Highlight variables.
+ private boolean mIsBannerPressed;
+ private float mInitialXForHighlight;
+
// Initial padding values.
private final Rect mBackgroundDrawablePadding;
@@ -109,10 +136,6 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
public AppBannerView(Context context, AttributeSet attrs) {
super(context, attrs);
mIsLayoutLTR = !LocalizationUtils.isSystemLayoutDirectionRtl();
- mSpaceMain = new Point();
- mSpaceForLogo = new Point();
- mSpaceForRating = new Point();
- mSpaceForTitle = new Point();
// Store the background Drawable's padding. The background used for banners is a 9-patch,
// which means that it already defines padding. We need to take it into account when adding
@@ -137,41 +160,38 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
private void initializeControls() {
// Cache the banner dimensions, adjusting margins for drop shadows defined in the background
- // Drawable. The Drawable is defined to have the same margin on both the left and right.
+ // Drawable.
Resources res = getResources();
mDefinedMaxWidth = res.getDimensionPixelSize(R.dimen.app_banner_max_width);
- mPaddingContent = res.getDimensionPixelSize(R.dimen.app_banner_padding_content);
- mMarginSide = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides)
+ mPaddingCard = res.getDimensionPixelSize(R.dimen.app_banner_padding);
+ mPaddingControls = res.getDimensionPixelSize(R.dimen.app_banner_padding_controls);
+ mMarginLeft = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides)
- mBackgroundDrawablePadding.left;
+ mMarginRight = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides)
+ - mBackgroundDrawablePadding.right;
mMarginBottom = res.getDimensionPixelSize(R.dimen.app_banner_margin_bottom)
- mBackgroundDrawablePadding.bottom;
if (getLayoutParams() != null) {
MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
- params.leftMargin = mMarginSide;
- params.rightMargin = mMarginSide;
+ params.leftMargin = mMarginLeft;
+ params.rightMargin = mMarginRight;
params.bottomMargin = mMarginBottom;
}
- // Add onto the padding defined by the Drawable's drop shadow.
- int padding = res.getDimensionPixelSize(R.dimen.app_banner_padding);
- int paddingStart = mBackgroundDrawablePadding.left + padding;
- int paddingTop = mBackgroundDrawablePadding.top + padding;
- int paddingEnd = mBackgroundDrawablePadding.right + padding;
- int paddingBottom = mBackgroundDrawablePadding.bottom + padding;
- ApiCompatibilityUtils.setPaddingRelative(
- this, paddingStart, paddingTop, paddingEnd, paddingBottom);
-
// Pull out all of the controls we are expecting.
mIconView = (ImageView) findViewById(R.id.app_icon);
mTitleView = (TextView) findViewById(R.id.app_title);
mButtonView = (Button) findViewById(R.id.app_install_button);
mRatingView = (RatingView) findViewById(R.id.app_rating);
- mLogoView = (ImageView) findViewById(R.id.store_logo);
+ mLogoView = findViewById(R.id.store_logo);
+ mBannerHighlightView = findViewById(R.id.banner_highlight);
+
assert mIconView != null;
assert mTitleView != null;
assert mButtonView != null;
assert mLogoView != null;
assert mRatingView != null;
+ assert mBannerHighlightView != null;
// Set up the button to fire an event.
mButtonView.setOnClickListener(this);
@@ -199,7 +219,7 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
protected ViewGroup.MarginLayoutParams createLayoutParams() {
// Define the margin around the entire banner that accounts for the drop shadow.
ViewGroup.MarginLayoutParams params = super.createLayoutParams();
- params.setMargins(mMarginSide, 0, mMarginSide, mMarginBottom);
+ params.setMargins(mMarginLeft, 0, mMarginRight, mMarginBottom);
return params;
}
@@ -228,24 +248,25 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
void updateButtonState() {
if (mButtonView == null) return;
- int bgColor;
+ Resources res = getResources();
int fgColor;
String text;
if (mAppData.installState() == AppData.INSTALL_STATE_INSTALLED) {
- bgColor = getResources().getColor(R.color.app_banner_open_button_bg);
- fgColor = getResources().getColor(R.color.app_banner_open_button_fg);
- text = getResources().getString(R.string.app_banner_open);
+ ApiCompatibilityUtils.setBackgroundForView(mButtonView,
+ res.getDrawable(R.drawable.app_banner_button_open));
+ fgColor = res.getColor(R.color.app_banner_open_button_fg);
+ text = res.getString(R.string.app_banner_open);
} else {
- bgColor = getResources().getColor(R.color.app_banner_install_button_bg);
- fgColor = getResources().getColor(R.color.app_banner_install_button_fg);
+ ApiCompatibilityUtils.setBackgroundForView(mButtonView,
+ res.getDrawable(R.drawable.app_banner_button_install));
+ fgColor = res.getColor(R.color.app_banner_install_button_fg);
if (mAppData.installState() == AppData.INSTALL_STATE_NOT_INSTALLED) {
text = mAppData.installButtonText();
} else {
- text = getResources().getString(R.string.app_banner_installing);
+ text = res.getString(R.string.app_banner_installing);
}
}
- mButtonView.setBackgroundColor(bgColor);
mButtonView.setTextColor(fgColor);
mButtonView.setText(text);
}
@@ -260,6 +281,34 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
}
/**
+ * Highlight the banner when the user has held it for long enough and doesn't move.
+ * Passes all touch events through to the parent.
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mIsBannerPressed = true;
+ mInitialXForHighlight = event.getRawX();
+ getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // Highlight the banner if the user is still holding onto it.
+ if (mIsBannerPressed) mBannerHighlightView.setVisibility(View.VISIBLE);
+ }
+ }, MS_HIGHLIGHT_APPEARANCE);
+ } else if (mIsBannerPressed) {
+ float xDifference = Math.abs(event.getRawX() - mInitialXForHighlight);
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
+ || (action == MotionEvent.ACTION_MOVE && xDifference > HIGHLIGHT_DISTANCE)) {
+ mIsBannerPressed = false;
+ mBannerHighlightView.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ return super.onTouchEvent(event);
+ }
+ /**
* Fade the banner back into view.
*/
@Override
@@ -300,6 +349,7 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
mButtonView = null;
mRatingView = null;
mLogoView = null;
+ mBannerHighlightView = null;
AppBannerView cannibalized =
(AppBannerView) LayoutInflater.from(getContext()).inflate(BANNER_LAYOUT, null);
@@ -313,73 +363,125 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
}
/**
- * Measurement for components of the banner are performed using the following procedure:
+ * Measures the banner and its children Views for the given space.
+ *
+ * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ * DPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPD
+ * DP...... cPD
+ * DP...... TITLE-------------------------cPD
+ * DP.ICON. ***** cPD
+ * DP...... LOGO BUTTONcPD
+ * DP...... cccccccccccccccccccccccccccccccPD
+ * DPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPD
+ * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
*
- * 00000000000000000000000000000000000000000000000000000
- * 01111155555555555555555555555555555555555555555555550
- * 01111155555555555555555555555555555555555555555555550
- * 01111144444444444440000000000000000000000222222222220
- * 01111133333333333330000000000000000000000222222222220
- * 00000000000000000000000000000000000000000000000000000
+ * The three paddings mentioned in the class Javadoc are denoted by:
+ * D) Drop shadow padding.
+ * P) Inner card padding.
+ * c) Control padding.
*
- * 0) A maximum width is enforced on the banner, based on the smallest width of the screen,
- * then padding defined by the 9-patch background Drawable is subtracted from all sides.
- * 1) The icon takes up the left side of the banner.
- * 2) The install button occupies the bottom-right of the banner.
- * 3) The Google Play logo occupies the space to the left of the button.
- * 4) The rating is assigned space above the logo and below the title.
- * 5) The title is assigned whatever space is left. The maximum height of the banner is defined
- * by deducting the height of either the install button or the logo + rating, (which is
- * bigger). If the title cannot fit two lines comfortably, it is shrunk down to one.
+ * Measurement for components of the banner are performed assuming that components are laid out
+ * inside of the banner's background as follows:
+ * 1) A maximum width is enforced on the banner to keep the whole thing on screen and keep it a
+ * reasonable size.
+ * 2) The icon takes up the left side of the banner.
+ * 3) The install button occupies the bottom-right of the banner.
+ * 4) The Google Play logo occupies the space to the left of the button.
+ * 5) The rating is assigned space above the logo and below the title.
+ * 6) The title is assigned whatever space is left and sits on top of the tallest stack of
+ * controls.
*
* See {@link #android.view.View.onMeasure(int, int)} for the parameters.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Enforce a maximum width on the banner.
+ // Enforce a maximum width on the banner, which is defined as the smallest of:
+ // 1) The smallest width for the device (in either landscape or portrait mode).
+ // 2) The defined maximum width in the dimens.xml files.
+ // 3) The width passed in through the MeasureSpec.
Resources res = getResources();
float density = res.getDisplayMetrics().density;
int screenSmallestWidth = (int) (res.getConfiguration().smallestScreenWidthDp * density);
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
- int maxWidth = Math.min(Math.min(specWidth, mDefinedMaxWidth), screenSmallestWidth);
- int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
-
- // Track how much space is available for the banner content.
- mSpaceMain.x = maxWidth - ApiCompatibilityUtils.getPaddingStart(this)
- - ApiCompatibilityUtils.getPaddingEnd(this);
- mSpaceMain.y = maxHeight - getPaddingTop() - getPaddingBottom();
-
- // Measure the icon, which hugs the banner's starting edge and defines the banner's height.
- measureChildForSpace(mIconView, mSpaceMain);
- mSpaceMain.x -= getChildWidthWithMargins(mIconView);
- mSpaceMain.y = getChildHeightWithMargins(mIconView) + getPaddingTop() + getPaddingBottom();
-
- // Additional padding is defined by the mock for non-icon content on the end and bottom.
- mSpaceMain.x -= mPaddingContent;
- mSpaceMain.y -= mPaddingContent;
-
- // Measure the install button, which sits in the bottom-right corner.
- measureChildForSpace(mButtonView, mSpaceMain);
+ int bannerWidth = Math.min(Math.min(specWidth, mDefinedMaxWidth), screenSmallestWidth);
+
+ // Track how much space is available inside the banner's card-shaped background Drawable.
+ // To calculate this, we need to account for both the padding of the background (which
+ // is occupied by the card's drop shadows) as well as the padding defined on the inside of
+ // the card.
+ int bgPaddingWidth = mBackgroundDrawablePadding.left + mBackgroundDrawablePadding.right;
+ int bgPaddingHeight = mBackgroundDrawablePadding.top + mBackgroundDrawablePadding.bottom;
+ final int maxControlWidth = bannerWidth - bgPaddingWidth - (mPaddingCard * 2);
+
+ // Control height is constrained to provide a reasonable aspect ratio.
+ // In practice, the only controls which can cause an issue are the title and the install
+ // button, since they have strings that can change size according to user preference. The
+ // other controls are all defined to be a certain height.
+ int specHeight = MeasureSpec.getSize(heightMeasureSpec);
+ int reasonableHeight = maxControlWidth / 4;
+ int paddingHeight = bgPaddingHeight + (mPaddingCard * 2);
+ final int maxControlHeight = Math.min(specHeight, reasonableHeight) - paddingHeight;
+ final int maxStackedControlHeight = maxControlWidth / 3;
+
+ // Determine how big each component wants to be. The icon is measured separately because
+ // it is not stacked with the other controls.
+ measureChildForSpace(mIconView, maxControlWidth, maxControlHeight);
+ for (int i = 0; i < getChildCount(); i++) {
+ if (getChildAt(i) != mIconView) {
+ measureChildForSpace(getChildAt(i), maxControlWidth, maxStackedControlHeight);
+ }
+ }
- // Measure the logo, which sits in the bottom-left corner next to the icon.
- mSpaceForLogo.x = mSpaceMain.x - getChildWidthWithMargins(mButtonView);
- mSpaceForLogo.y = mSpaceMain.y;
- measureChildForSpace(mLogoView, mSpaceForLogo);
+ // Determine how tall the banner needs to be to fit everything by calculating the combined
+ // height of the stacked controls. There are three competing stacks to measure:
+ // 1) The icon.
+ // 2) The app title + control padding + star rating + store logo.
+ // 3) The app title + control padding + install button.
+ // The control padding is extra padding that applies only to the non-icon widgets.
+ int iconStackHeight = getHeightWithMargins(mIconView);
+ int logoStackHeight = getHeightWithMargins(mTitleView) + mPaddingControls
+ + getHeightWithMargins(mRatingView) + getHeightWithMargins(mLogoView);
+ int buttonStackHeight = getHeightWithMargins(mTitleView) + mPaddingControls
+ + getHeightWithMargins(mButtonView);
+ int biggestStackHeight =
+ Math.max(iconStackHeight, Math.max(logoStackHeight, buttonStackHeight));
+
+ // The icon hugs the banner's starting edge, from the top of the banner to the bottom.
+ final int iconSize = biggestStackHeight;
+ measureChildForSpaceExactly(mIconView, iconSize, iconSize);
+
+ // The rest of the content is laid out to the right of the icon.
+ // Additional padding is defined for non-icon content on the end and bottom.
+ final int contentWidth =
+ maxControlWidth - getWidthWithMargins(mIconView) - mPaddingControls;
+ final int contentHeight = biggestStackHeight - mPaddingControls;
+ measureChildForSpace(mButtonView, contentWidth, contentHeight);
+ measureChildForSpace(mLogoView, contentWidth, contentHeight);
// Measure the star rating, which sits below the title and above the logo.
- mSpaceForRating.x = mSpaceForLogo.x;
- mSpaceForRating.y = mSpaceForLogo.y - getChildHeightWithMargins(mLogoView);
- measureChildForSpace(mRatingView, mSpaceForRating);
-
- // The app title spans the top of the banner.
- mSpaceForTitle.x = mSpaceMain.x;
- mSpaceForTitle.y = mSpaceMain.y - getChildHeightWithMargins(mLogoView)
- - getChildHeightWithMargins(mRatingView);
- measureChildForSpace(mTitleView, mSpaceForTitle);
-
- // Set the measured dimensions for the banner.
- int measuredHeight = mIconView.getMeasuredHeight() + getPaddingTop() + getPaddingBottom();
- setMeasuredDimension(maxWidth, measuredHeight);
+ final int ratingWidth = contentWidth;
+ final int ratingHeight = contentHeight - getHeightWithMargins(mLogoView);
+ measureChildForSpace(mRatingView, ratingWidth, ratingHeight);
+
+ // The app title spans the top of the banner and sits on top of the other controls.
+ int biggerStack = Math.max(getHeightWithMargins(mButtonView),
+ getHeightWithMargins(mLogoView) + getHeightWithMargins(mRatingView));
+ final int titleWidth = contentWidth;
+ final int titleHeight = contentHeight - biggerStack;
+ measureChildForSpace(mTitleView, titleWidth, titleHeight);
+
+ // Set the measured dimensions for the banner. The banner's height is defined by the
+ // tallest stack of components, the padding of the banner's card background, and the extra
+ // padding around the banner's components.
+ int bannerPadding = mBackgroundDrawablePadding.top + mBackgroundDrawablePadding.bottom
+ + (mPaddingCard * 2);
+ int bannerHeight = biggestStackHeight + bannerPadding;
+ setMeasuredDimension(bannerWidth, bannerHeight);
+
+ // Make the banner highlight view be the exact same size as the banner's card background.
+ final int cardWidth = bannerWidth - bgPaddingWidth;
+ final int cardHeight = bannerHeight - bgPaddingHeight;
+ measureChildForSpaceExactly(mBannerHighlightView, cardWidth, cardHeight);
}
/**
@@ -389,21 +491,29 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
+ int top = mBackgroundDrawablePadding.top;
+ int bottom = getMeasuredHeight() - mBackgroundDrawablePadding.bottom;
+ int start = mBackgroundDrawablePadding.left;
+ int end = getMeasuredWidth() - mBackgroundDrawablePadding.right;
+
+ // The highlight overlay covers the entire banner (minus drop shadow padding).
+ mBannerHighlightView.layout(start, top, end, bottom);
- int top = getPaddingTop();
- int bottom = getMeasuredHeight() - getPaddingBottom();
- int start = ApiCompatibilityUtils.getPaddingStart(this);
- int end = getMeasuredWidth() - ApiCompatibilityUtils.getPaddingEnd(this);
+ // Apply the padding for the rest of the widgets.
+ top += mPaddingCard;
+ bottom -= mPaddingCard;
+ start += mPaddingCard;
+ end -= mPaddingCard;
// Lay out the icon.
int iconWidth = mIconView.getMeasuredWidth();
int iconLeft = mIsLayoutLTR ? start : (getMeasuredWidth() - start - iconWidth);
mIconView.layout(iconLeft, top, iconLeft + iconWidth, top + mIconView.getMeasuredHeight());
- start += getChildWidthWithMargins(mIconView);
+ start += getWidthWithMargins(mIconView);
- // Factor in the additional padding.
- end -= mPaddingContent;
- bottom -= mPaddingContent;
+ // Factor in the additional padding, which is only tacked onto the end and bottom.
+ end -= mPaddingControls;
+ bottom -= mPaddingControls;
// Lay out the app title text.
int titleWidth = mTitleView.getMeasuredWidth();
@@ -440,37 +550,74 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi
}
/**
+ * Measures a child for the given space, accounting for defined heights and margins.
+ * @param child View to measure.
+ * @param availableWidth Available width for the view.
+ * @param availableHeight Available height for the view.
+ */
+ private void measureChildForSpace(View child, int availableWidth, int availableHeight) {
+ // Handle margins.
+ availableWidth -= getMarginWidth(child);
+ availableHeight -= getMarginHeight(child);
+
+ // Account for any layout-defined dimensions for the view.
+ int childWidth = child.getLayoutParams().width;
+ int childHeight = child.getLayoutParams().height;
+ if (childWidth >= 0) availableWidth = Math.min(availableWidth, childWidth);
+ if (childHeight >= 0) availableHeight = Math.min(availableHeight, childHeight);
+
+ int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
+ int heightSpec = MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST);
+ child.measure(widthSpec, heightSpec);
+ }
+
+ /**
+ * Forces a child to exactly occupy the given space.
+ * @param child View to measure.
+ * @param availableWidth Available width for the view.
+ * @param availableHeight Available height for the view.
+ */
+ private void measureChildForSpaceExactly(View child, int availableWidth, int availableHeight) {
+ int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY);
+ int heightSpec = MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.EXACTLY);
+ child.measure(widthSpec, heightSpec);
+ }
+
+ /**
+ * Calculates how wide the margins are for the given View.
+ * @param view View to measure.
+ * @return Measured width of the margins.
+ */
+ private static int getMarginWidth(View view) {
+ MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
+ return params.leftMargin + params.rightMargin;
+ }
+
+ /**
* Calculates how wide the given View has been measured to be, including its margins.
- * @param child Child to measure.
- * @return Measured width of the child plus its margins.
+ * @param view View to measure.
+ * @return Measured width of the view plus its margins.
*/
- private int getChildWidthWithMargins(View child) {
- MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
- return child.getMeasuredWidth() + ApiCompatibilityUtils.getMarginStart(params)
- + ApiCompatibilityUtils.getMarginEnd(params);
+ private static int getWidthWithMargins(View view) {
+ return view.getMeasuredWidth() + getMarginWidth(view);
}
/**
- * Calculates how tall the given View has been measured to be, including its margins.
- * @param child Child to measure.
- * @return Measured height of the child plus its margins.
+ * Calculates how tall the margins are for the given View.
+ * @param view View to measure.
+ * @return Measured height of the margins.
*/
- private static int getChildHeightWithMargins(View child) {
- MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
- return child.getMeasuredHeight() + params.topMargin + params.bottomMargin;
+ private static int getMarginHeight(View view) {
+ MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
+ return params.topMargin + params.bottomMargin;
}
/**
- * Measures a child so that it fits within the given space, taking into account heights defined
- * in the layout.
- * @param child View to measure.
- * @param available Available space, with width stored in the x coordinate and height in the y.
+ * Calculates how tall the given View has been measured to be, including its margins.
+ * @param view View to measure.
+ * @return Measured height of the view plus its margins.
*/
- private void measureChildForSpace(View child, Point available) {
- int childHeight = child.getLayoutParams().height;
- int maxHeight = childHeight > 0 ? Math.min(available.y, childHeight) : available.y;
- int widthSpec = MeasureSpec.makeMeasureSpec(available.x, MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
- measureChildWithMargins(child, widthSpec, 0, heightSpec, 0);
+ private static int getHeightWithMargins(View view) {
+ return view.getMeasuredHeight() + getMarginHeight(view);
}
}

Powered by Google App Engine
This is Rietveld 408576698