diff --git a/library/src/main/java/com/sergivonavi/materialbanner/Banner.java b/library/src/main/java/com/sergivonavi/materialbanner/Banner.java index 7cf9c4b..d1d9682 100644 --- a/library/src/main/java/com/sergivonavi/materialbanner/Banner.java +++ b/library/src/main/java/com/sergivonavi/materialbanner/Banner.java @@ -35,7 +35,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateDecelerateInterpolator; -import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.google.android.material.button.MaterialButton; @@ -98,6 +97,7 @@ *

*/ public class Banner extends ViewGroup implements BannerInterface { + private static final String TAG = "Banner"; private static final boolean DEBUG = false; @IntDef(value = {VISIBLE, INVISIBLE, GONE}) @@ -133,9 +133,6 @@ public class Banner extends ViewGroup implements BannerInterface { private int mMessageMarginBottomMultiline; private int mMessageMarginBottomWithIcon; - private int mButtonMarginEnd; - private int mButtonMarginBottom; - private int mLineHeight; /** @@ -191,9 +188,6 @@ private void loadDimens(Context context) { mMessageMarginBottomMultiline = getDimen(R.dimen.mb_message_margin_bottom_multiline); mMessageMarginBottomWithIcon = getDimen(R.dimen.mb_message_margin_bottom_with_icon); - mButtonMarginEnd = getDimen(R.dimen.mb_button_margin_end); - mButtonMarginBottom = getDimen(R.dimen.mb_button_margin_bottom); - mLineHeight = getDimen(R.dimen.mb_line_height); mContainerPaddingTopOneLine = getDimen(R.dimen.mb_container_padding_top_singleline); @@ -248,40 +242,10 @@ private void initViewGroup(Context context) { mButtonsContainer = new ButtonsContainer(context); mButtonsContainer.setId(R.id.mb_container_buttons); - mButtonsContainer.setOrientation(LinearLayout.HORIZONTAL); - mButtonsContainer.setBaselineAligned(false); mButtonsContainer.setLayoutParams(relativeLayoutParams); - // BUTTONS' PARAMS - LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(WRAP_CONTENT, - WRAP_CONTENT); - linearLayoutParams.weight = 1.0f; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - linearLayoutParams.setMarginEnd(mButtonMarginEnd); - } else { - linearLayoutParams.rightMargin = mButtonMarginEnd; - } - linearLayoutParams.bottomMargin = mButtonMarginBottom; - - // LEFT BUTTON - mLeftButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle); - mLeftButton.setId(R.id.mb_button_left); - mLeftButton.setSingleLine(true); - mLeftButton.setMaxLines(1); - mLeftButton.setMinWidth(0); - mLeftButton.setMinimumWidth(0); - mLeftButton.setLayoutParams(linearLayoutParams); - mLeftButton.setVisibility(GONE); - - // RIGHT BUTTON - mRightButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle); - mRightButton.setId(R.id.mb_button_right); - mRightButton.setSingleLine(true); - mRightButton.setMaxLines(1); - mRightButton.setMinWidth(0); - mRightButton.setMinimumWidth(0); - mRightButton.setLayoutParams(linearLayoutParams); - mRightButton.setVisibility(GONE); + mLeftButton = mButtonsContainer.getLeftButton(); + mRightButton = mButtonsContainer.getRightButton(); // LINE layoutParams = new LayoutParams(MATCH_PARENT, mLineHeight); @@ -293,9 +257,6 @@ private void initViewGroup(Context context) { addView(mContentContainer); addView(mLine); - mButtonsContainer.addView(mLeftButton, 0); - mButtonsContainer.addView(mRightButton, 1); - mContentContainer.addView(mIconView); mContentContainer.addView(mMessageView); mContentContainer.addView(mButtonsContainer); @@ -457,13 +418,26 @@ private void onMultiline() { .getLayoutParams(); if (mWideLayout) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - messageLayoutParams.addRule(START_OF, mButtonsContainer.getId()); + if (mButtonsContainer.getMeasuredWidth() + > (getMeasuredWidth() - getContainerHorizontalPadding()) / 2) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + messageLayoutParams.addRule(START_OF, 0); + } else { + messageLayoutParams.addRule(LEFT_OF, 0); + } + messageLayoutParams.bottomMargin = mIcon + == null ? mMessageMarginBottomMultiline : mMessageMarginBottomWithIcon; + + buttonsContainerLayoutParams.addRule(BELOW, mMessageView.getId()); } else { - messageLayoutParams.addRule(LEFT_OF, mButtonsContainer.getId()); - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + messageLayoutParams.addRule(START_OF, mButtonsContainer.getId()); + } else { + messageLayoutParams.addRule(LEFT_OF, mButtonsContainer.getId()); + } - buttonsContainerLayoutParams.addRule(ALIGN_BASELINE, mMessageView.getId()); + buttonsContainerLayoutParams.addRule(ALIGN_BASELINE, mMessageView.getId()); + } } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { messageLayoutParams.addRule(START_OF, 0); diff --git a/library/src/main/java/com/sergivonavi/materialbanner/internal/ButtonsContainer.java b/library/src/main/java/com/sergivonavi/materialbanner/internal/ButtonsContainer.java index 7d382fb..bbf2f57 100644 --- a/library/src/main/java/com/sergivonavi/materialbanner/internal/ButtonsContainer.java +++ b/library/src/main/java/com/sergivonavi/materialbanner/internal/ButtonsContainer.java @@ -17,39 +17,288 @@ package com.sergivonavi.materialbanner.internal; import android.content.Context; +import android.os.Build; import android.util.AttributeSet; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.view.ViewGroup; -import androidx.annotation.Nullable; +import com.google.android.material.button.MaterialButton; +import com.sergivonavi.materialbanner.R; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import androidx.annotation.DimenRes; +import androidx.annotation.IntDef; import androidx.annotation.RestrictTo; +import androidx.core.view.ViewCompat; + +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @RestrictTo(RestrictTo.Scope.LIBRARY) -public final class ButtonsContainer extends LinearLayout { +public class ButtonsContainer extends ViewGroup { + + @IntDef({HORIZONTAL, VERTICAL}) + @Retention(RetentionPolicy.SOURCE) + private @interface OrientationMode {} + + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + + private MaterialButton mLeftButton; + private MaterialButton mRightButton; + + private int mButtonMarginEnd; + private int mButtonMarginBottom; + + private int mOrientation; public ButtonsContainer(Context context) { - super(context); + this(context, null); } - public ButtonsContainer(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); + public ButtonsContainer(Context context, AttributeSet attrs) { + this(context, attrs, 0); } - public ButtonsContainer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + public ButtonsContainer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + mButtonMarginEnd = getDimen(R.dimen.mb_button_margin_end); + mButtonMarginBottom = getDimen(R.dimen.mb_button_margin_bottom); + + MarginLayoutParams layoutParams = new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + layoutParams.setMarginEnd(mButtonMarginEnd); + } else { + layoutParams.rightMargin = mButtonMarginEnd; + } + layoutParams.bottomMargin = mButtonMarginBottom; + + mLeftButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle); + mLeftButton.setId(R.id.mb_button_left); + mLeftButton.setSingleLine(true); + mLeftButton.setMaxLines(1); + mLeftButton.setMinWidth(0); + mLeftButton.setMinimumWidth(0); + mLeftButton.setLayoutParams(layoutParams); + mLeftButton.setVisibility(GONE); + + mRightButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle); + mRightButton.setId(R.id.mb_button_right); + mRightButton.setSingleLine(true); + mRightButton.setMaxLines(1); + mRightButton.setMinWidth(0); + mRightButton.setMinimumWidth(0); + mRightButton.setLayoutParams(layoutParams); + mRightButton.setVisibility(GONE); + + addView(mLeftButton); + addView(mRightButton); } @Override - public int getBaseline() { - if (getChildCount() > 0) { - TextView view1 = (TextView) getChildAt(0); - TextView view2 = (TextView) getChildAt(1); - if (view1.isShown() && view1.getText() != null) { - return view1.getBaseline(); - } else if (view2.isShown() && view2.getText() != null) { - return view2.getBaseline(); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthUsed = 0; + + if (mLeftButton.getVisibility() != GONE) { + measureChildWithMargins(mLeftButton, widthMeasureSpec, 0, heightMeasureSpec, 0); + widthUsed += mLeftButton.getMeasuredWidth() + mButtonMarginEnd; + } + + if (mRightButton.getVisibility() != GONE) { + measureChildWithMargins(mRightButton, widthMeasureSpec, 0, heightMeasureSpec, 0); + widthUsed += mRightButton.getMeasuredWidth() + mButtonMarginEnd; + } + + // Allow orientation change only when the both buttons are not hidden + if (mLeftButton.getVisibility() != GONE && mRightButton.getVisibility() != GONE) { + if (widthUsed > MeasureSpec.getSize(widthMeasureSpec)) { + mOrientation = VERTICAL; + } else { + mOrientation = HORIZONTAL; } } + + if (mOrientation == VERTICAL) { + measureVertical(); + } else { + measureHorizontal(); + } + } + + /** + * Measures the children when the orientation of this view is set to {@link #VERTICAL}. + */ + private void measureVertical() { + int widthUsed = 0; + int heightUsed = 0; + + if (mLeftButton.getVisibility() != GONE) { + widthUsed = mLeftButton.getMeasuredWidth() + mButtonMarginEnd; + heightUsed += mLeftButton.getMeasuredHeight() + mButtonMarginBottom; + } + + if (mRightButton.getVisibility() != GONE) { + widthUsed = Math.max(widthUsed, mRightButton.getMeasuredWidth() + mButtonMarginEnd); + heightUsed += mRightButton.getMeasuredHeight() + mButtonMarginBottom; + } + + setMeasuredDimension(widthUsed, heightUsed); + } + + /** + * Measures the children when the orientation of this view is set to {@link #HORIZONTAL}. + */ + private void measureHorizontal() { + int widthUsed = 0; + int heightUsed = 0; + + if (mLeftButton.getVisibility() != GONE) { + widthUsed += mLeftButton.getMeasuredWidth() + mButtonMarginEnd; + heightUsed = mLeftButton.getMeasuredHeight() + mButtonMarginBottom; + } + + if (mRightButton.getVisibility() != GONE) { + widthUsed += mRightButton.getMeasuredWidth() + mButtonMarginEnd; + heightUsed = Math.max(heightUsed, + mRightButton.getMeasuredHeight() + mButtonMarginBottom); + } + + setMeasuredDimension(widthUsed, heightUsed); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (mOrientation == VERTICAL) { + layoutVertical(); + } else { + layoutHorizontal(); + } + } + + /** + * Position the children during a layout pass if the orientation of this view is set to + * {@link #VERTICAL}. + */ + private void layoutVertical() { + int top = 0; + int lBtnRight = getMeasuredWidth() - mButtonMarginEnd; + int lBtnLeft = lBtnRight - mLeftButton.getMeasuredWidth(); + int rBtnRight = getMeasuredWidth() - mButtonMarginEnd; + int rBtnLeft = rBtnRight - mRightButton.getMeasuredWidth(); + + if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) { + lBtnLeft = mButtonMarginEnd; + lBtnRight = lBtnLeft + mLeftButton.getMeasuredWidth(); + rBtnLeft = mButtonMarginEnd; + rBtnRight = rBtnLeft + mRightButton.getMeasuredWidth(); + } + + if (mRightButton.getVisibility() != GONE) { + mRightButton.layout(rBtnLeft, top, rBtnRight, mRightButton.getMeasuredHeight()); + top += mRightButton.getMeasuredHeight() + mButtonMarginBottom; + } + + if (mLeftButton.getVisibility() != GONE) { + mLeftButton.layout(lBtnLeft, top, lBtnRight, top + mLeftButton.getMeasuredHeight()); + } + } + + /** + * Position the children during a layout pass if the orientation of this view is set to + * {@link #HORIZONTAL}. + */ + private void layoutHorizontal() { + int lBtnRight = mLeftButton.getMeasuredWidth(); + int lBtnLeft = 0; + int rBtnRight = getMeasuredWidth() - mButtonMarginEnd; + int rBtnLeft = rBtnRight - mRightButton.getMeasuredWidth(); + + if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) { + rBtnLeft = mButtonMarginEnd; + rBtnRight = rBtnLeft + mRightButton.getMeasuredWidth(); + lBtnRight = getMeasuredWidth(); + lBtnLeft = lBtnRight - mLeftButton.getMeasuredWidth(); + } + + if (mLeftButton.getVisibility() != GONE) { + mLeftButton.layout(lBtnLeft, 0, lBtnRight, mLeftButton.getMeasuredHeight()); + } + + if (mRightButton.getVisibility() != GONE) { + mRightButton.layout(rBtnLeft, 0, rBtnRight, mRightButton.getMeasuredHeight()); + } + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof MarginLayoutParams; + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new MarginLayoutParams(p); + } + + /** + * Returns the baseline of the left button if it's not hidden or the baseline of the right + * button. If both buttons hidden returns -1. + */ + @Override + public int getBaseline() { + if (mLeftButton.getVisibility() != GONE && mLeftButton.getText() != null) { + return mLeftButton.getBaseline(); + } else if (mRightButton.getVisibility() != GONE && mRightButton.getText() != null) { + return mRightButton.getBaseline(); + } return -1; } + + /** + * Should the layout be a column or a row. + * + * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}. Default value is + * {@link #HORIZONTAL}. + */ + public void setOrientation(@OrientationMode int orientation) { + if (mOrientation != orientation) { + mOrientation = orientation; + requestLayout(); + } + } + + /** + * Returns the current orientation. + * + * @return either {@link #HORIZONTAL} or {@link #VERTICAL} + */ + @OrientationMode + public int getOrientation() { + return mOrientation; + } + + public MaterialButton getLeftButton() { + return mLeftButton; + } + + public MaterialButton getRightButton() { + return mRightButton; + } + + private int getDimen(@DimenRes int dimenId) { + return getContext().getResources().getDimensionPixelSize(dimenId); + } }