package com.rey.material.widget;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.rey.material.R;
import com.rey.material.drawable.RippleDrawable;
import com.rey.material.util.ThemeUtil;
import com.rey.material.util.ViewUtil;
public class SnackBar extends FrameLayout {
private TextView mText;
private Button mAction;
public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
private BackgroundDrawable mBackground;
private int mMarginStart;
private int mMarginBottom;
private int mWidth;
private int mHeight;
private int mMaxHeight;
private int mMinHeight;
private int mInAnimationId;
private int mOutAnimationId;
private long mDuration = -1;
private int mActionId;
private boolean mRemoveOnDismiss;
private Runnable mDismissRunnable = new Runnable() {
@Override
public void run() {
dismiss();
}
};
private int mState = STATE_DISMISSED;
/**
* Indicate this SnackBar is already dismissed.
*/
public static final int STATE_DISMISSED = 0;
/**
* Indicate this SnackBar is already shown.
*/
public static final int STATE_SHOWN = 1;
/**
* Indicate this SnackBar is being shown.
*/
public static final int STATE_SHOWING = 2;
/**
* Indicate this SnackBar is being dismissed.
*/
public static final int STATE_DISMISSING = 3;
private boolean mIsRtl = false;
/**
* Interface definition for a callback to be invoked when action button is clicked.
*/
public interface OnActionClickListener{
/**
* Called when action button is clicked.
* @param sb The SnackBar fire this event.
* @param actionId The ActionId of this SnackBar.
*/
public void onActionClick(SnackBar sb, int actionId);
}
private OnActionClickListener mActionClickListener;
/**
* Interface definition for a callback to be invoked when SnackBar's state is changed.
*/
public interface OnStateChangeListener{
/**
* Called when SnackBar's state is changed.
* @param sb The SnackBar fire this event.
* @param oldState The old state of SnackBar.
* @param newState The new state of SnackBar.
*/
public void onStateChange(SnackBar sb, int oldState, int newState);
}
private OnStateChangeListener mStateChangeListener;
public static SnackBar make(Context context){
return new SnackBar(context);
}
public SnackBar(Context context){
super(context);
init(context, null, 0, 0);
}
public SnackBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
public SnackBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
public SnackBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, defStyleRes);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
mText = new TextView(context);
mText.setGravity(Gravity.START|Gravity.CENTER_VERTICAL);
addView(mText, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mAction = new Button(context);
mAction.setBackgroundResource(0);
mAction.setGravity(Gravity.CENTER);
mAction.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mActionClickListener != null)
mActionClickListener.onActionClick(SnackBar.this, mActionId);
dismiss();
}
});
addView(mAction, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mBackground = new BackgroundDrawable();
ViewUtil.setBackground(this, mBackground);
setClickable(true);
applyStyle(context, attrs, defStyleAttr, defStyleRes);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
boolean rtl = layoutDirection == LAYOUT_DIRECTION_RTL;
if(mIsRtl != rtl) {
mIsRtl = rtl;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
mText.setTextDirection((mIsRtl ? TEXT_DIRECTION_RTL : TEXT_DIRECTION_LTR));
mAction.setTextDirection((mIsRtl ? TEXT_DIRECTION_RTL : TEXT_DIRECTION_LTR));
}
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width;
int height;
if(mAction.getVisibility() == View.VISIBLE){
mAction.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec);
int padding = mIsRtl ? mText.getPaddingLeft() : mText.getPaddingRight();
mText.measure(MeasureSpec.makeMeasureSpec(widthSize - (mAction.getMeasuredWidth() - padding), widthMode), heightMeasureSpec);
width = mText.getMeasuredWidth() + mAction.getMeasuredWidth() - padding;
}
else{
mText.measure(MeasureSpec.makeMeasureSpec(widthSize, widthMode), heightMeasureSpec);
width = mText.getMeasuredWidth();
}
height = Math.max(mText.getMeasuredHeight(), mAction.getMeasuredHeight());
switch (widthMode) {
case MeasureSpec.AT_MOST:
width = Math.min(widthSize, width);
break;
case MeasureSpec.EXACTLY:
width = widthSize;
break;
}
switch (heightMode) {
case MeasureSpec.AT_MOST:
height = Math.min(heightSize, height);
break;
case MeasureSpec.EXACTLY:
height = heightSize;
break;
}
if(mMaxHeight > 0)
height = Math.min(mMaxHeight, height);
if(mMinHeight > 0)
height = Math.max(mMinHeight, height);
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childLeft = getPaddingLeft();
int childRight = r - l - getPaddingRight();
int childTop = getPaddingTop();
int childBottom = b - t - getPaddingBottom();
if(mAction.getVisibility() == View.VISIBLE){
if(mIsRtl) {
mAction.layout(childLeft, childTop, childLeft + mAction.getMeasuredWidth(), childBottom);
childLeft += mAction.getMeasuredWidth() - mText.getPaddingLeft();
}
else {
mAction.layout(childRight - mAction.getMeasuredWidth(), childTop, childRight, childBottom);
childRight -= mAction.getMeasuredWidth() - mText.getPaddingRight();
}
}
mText.layout(childLeft, childTop, childRight, childBottom);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackBar, defStyleAttr, defStyleRes);
int backgroundColor = a.getColor(R.styleable.SnackBar_sb_backgroundColor, 0xFF323232);
int backgroundRadius = a.getDimensionPixelSize(R.styleable.SnackBar_sb_backgroundCornerRadius, 0);
int horizontalPadding = a.getDimensionPixelSize(R.styleable.SnackBar_sb_horizontalPadding, ThemeUtil.dpToPx(context, 24));
int verticalPadding = a.getDimensionPixelSize(R.styleable.SnackBar_sb_verticalPadding, 0);
TypedValue value = a.peekValue(R.styleable.SnackBar_sb_width);
if(value != null && value.type == TypedValue.TYPE_INT_DEC)
mWidth = a.getInteger(R.styleable.SnackBar_sb_width, MATCH_PARENT);
else
mWidth = a.getDimensionPixelSize(R.styleable.SnackBar_sb_width, MATCH_PARENT);
int minWidth = a.getDimensionPixelSize(R.styleable.SnackBar_sb_minWidth, 0);
int maxWidth = a.getDimensionPixelSize(R.styleable.SnackBar_sb_maxWidth, 0);
value = a.peekValue(R.styleable.SnackBar_sb_height);
if(value != null && value.type == TypedValue.TYPE_INT_DEC)
mHeight = a.getInteger(R.styleable.SnackBar_sb_height, WRAP_CONTENT);
else
mHeight = a.getDimensionPixelSize(R.styleable.SnackBar_sb_height, WRAP_CONTENT);
int minHeight = a.getDimensionPixelSize(R.styleable.SnackBar_sb_minHeight, 0);
int maxHeight = a.getDimensionPixelSize(R.styleable.SnackBar_sb_maxHeight, 0);
mMarginStart = a.getDimensionPixelSize(R.styleable.SnackBar_sb_marginStart, 0);
mMarginBottom = a.getDimensionPixelSize(R.styleable.SnackBar_sb_marginBottom, 0);
int textSize = a.getDimensionPixelSize(R.styleable.SnackBar_sb_textSize, 0);
boolean hasTextColor = a.hasValue(R.styleable.SnackBar_sb_textColor);
int textColor = hasTextColor ? a.getColor(R.styleable.SnackBar_sb_textColor, 0xFFFFFFFF) : 0;
int textAppearance = a.getResourceId(R.styleable.SnackBar_sb_textAppearance, 0);
String text = a.getString(R.styleable.SnackBar_sb_text);
boolean singleLine = a.getBoolean(R.styleable.SnackBar_sb_singleLine, true);
int maxLines = a.getInteger(R.styleable.SnackBar_sb_maxLines, 0);
int lines = a.getInteger(R.styleable.SnackBar_sb_lines, 0);
int ellipsize = a.getInteger(R.styleable.SnackBar_sb_ellipsize, 0);
int actionTextSize = a.getDimensionPixelSize(R.styleable.SnackBar_sb_actionTextSize, 0);
ColorStateList actionTextColor;
value = a.peekValue(R.styleable.SnackBar_sb_actionTextColor);
if(value != null && value.type >= TypedValue.TYPE_FIRST_COLOR_INT && value.type <= TypedValue.TYPE_LAST_COLOR_INT)
actionTextColor = ColorStateList.valueOf(a.getColor(R.styleable.SnackBar_sb_actionTextColor, 0xFF000000));
else
actionTextColor = a.getColorStateList(R.styleable.SnackBar_sb_actionTextColor);
int actionTextAppearance = a.getResourceId(R.styleable.SnackBar_sb_actionTextAppearance, 0);
String actionText = a.getString(R.styleable.SnackBar_sb_actionText);
int actionRipple = a.getResourceId(R.styleable.SnackBar_sb_actionRipple, 0);
int duration = a.getInteger(R.styleable.SnackBar_sb_duration, -1);
mInAnimationId = a.getResourceId(R.styleable.SnackBar_sb_inAnimation, 0);
mOutAnimationId = a.getResourceId(R.styleable.SnackBar_sb_outAnimation, 0);
mRemoveOnDismiss = a.getBoolean(R.styleable.SnackBar_sb_removeOnDismiss, true);
a.recycle();
backgroundColor(backgroundColor)
.backgroundRadius(backgroundRadius);
padding(horizontalPadding, verticalPadding);
textAppearance(textAppearance);
if(textSize > 0)
textSize(textSize);
if(hasTextColor)
textColor(textColor);
if(text != null)
text(text);
singleLine(singleLine);
if(maxLines > 0)
maxLines(maxLines);
if(lines > 0)
lines(lines);
if(minWidth > 0)
minWidth(minWidth);
if(maxWidth > 0)
maxWidth(maxWidth);
if(minHeight > 0)
minHeight(minHeight);
if(maxHeight > 0)
maxHeight(maxHeight);
switch (ellipsize) {
case 1:
ellipsize(TruncateAt.START);
break;
case 2:
ellipsize(TruncateAt.MIDDLE);
break;
case 3:
ellipsize(TruncateAt.END);
break;
case 4:
ellipsize(TruncateAt.MARQUEE);
break;
default:
ellipsize(TruncateAt.END);
break;
}
if(textAppearance != 0)
actionTextAppearance(actionTextAppearance);
if(actionTextSize > 0)
actionTextSize(actionTextSize);
if(actionTextColor != null)
actionTextColor(actionTextColor);
if(actionText != null)
actionText(actionText);
if(actionRipple != 0)
actionRipple(actionRipple);
if(duration >= 0)
duration(duration);
}
public SnackBar applyStyle(int resId){
applyStyle(getContext(), null, 0, resId);
return this;
}
/**
* Set the text that this SnackBar is to display.
* @param text The text is displayed.
* @return This SnackBar for chaining methods.
*/
public SnackBar text(CharSequence text){
mText.setText(text);
return this;
}
/**
* Set the text that this SnackBar is to display.
* @param id The resourceId of text is displayed.
* @return This SnackBar for chaining methods.
*/
public SnackBar text(int id){
return text(getContext().getResources().getString(id));
}
/**
* Set the text color.
* @param color The color of text.
* @return This SnackBar for chaining methods.
*/
public SnackBar textColor(int color){
mText.setTextColor(color);
return this;
}
/**
* Set the text size to the given value, interpreted as "scaled pixel" units.
* @param size The size of text.
* @return This SnackBar for chaining methods.
*/
public SnackBar textSize(float size){
mText.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
return this;
}
/**
* Sets the text color, size, style from the specified TextAppearance resource.
* @param resId The resourceId value.
* @return This SnackBar for chaining methods.
*/
public SnackBar textAppearance(int resId){
if(resId != 0)
mText.setTextAppearance(getContext(), resId);
return this;
}
/**
* Causes words in the text that are longer than the view is wide to be ellipsized instead of broken in the middle.
* @param at
* @return This SnackBar for chaining methods.
*/
public SnackBar ellipsize(TruncateAt at){
mText.setEllipsize(at);
return this;
}
/**
* Sets the text will be single-line or not.
* @param b
* @return This SnackBar for chaining methods.
*/
public SnackBar singleLine(boolean b){
mText.setSingleLine(b);
return this;
}
/**
* Makes the text at most this many lines tall.
* @param lines The maximum line value.
* @return This SnackBar for chaining methods.
*/
public SnackBar maxLines(int lines){
mText.setMaxLines(lines);
return this;
}
/**
* Makes the text exactly this many lines tall.
* @param lines The line number.
* @return This SnackBar for chaining methods.
*/
public SnackBar lines(int lines){
mText.setLines(lines);
return this;
}
/**
* Set the actionId of this SnackBar. Used to determine the current action of this SnackBar.
* @param id The actionId value.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionId(int id){
mActionId = id;
return this;
}
/**
* Set the text that the ActionButton is to display.
* @param text If null, then the ActionButton will be hidden.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionText(CharSequence text){
if(TextUtils.isEmpty(text))
mAction.setVisibility(View.INVISIBLE);
else{
mAction.setVisibility(View.VISIBLE);
mAction.setText(text);
}
return this;
}
/**
* Set the text that the ActionButton is to display.
* @param id If 0, then the ActionButton will be hidden.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionText(int id){
if(id == 0)
return actionText(null);
return actionText(getContext().getResources().getString(id));
}
/**
* Set the text color of the ActionButton for all states.
* @param color The color of text.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionTextColor(int color){
mAction.setTextColor(color);
return this;
}
/**
* Set the text color of the ActionButton.
* @param colors
* @return This SnackBar for chaining methods.
*/
public SnackBar actionTextColor(ColorStateList colors){
mAction.setTextColor(colors);
return this;
}
/**
* Sets the text color, size, style of the ActionButton from the specified TextAppearance resource.
* @param resId The resourceId value.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionTextAppearance(int resId){
if(resId != 0)
mAction.setTextAppearance(getContext(), resId);
return this;
}
/**
* Set the text size of the ActionButton to the given value, interpreted as "scaled pixel" units.
* @param size The size of text.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionTextSize(float size){
mAction.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
return this;
}
/**
* Set the style of RippleEffect of the ActionButton.
* @param resId The resourceId of RippleEffect.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionRipple(int resId){
if(resId != 0)
ViewUtil.setBackground(mAction, new RippleDrawable.Builder(getContext(), resId).build());
return this;
}
/**
* Set the duration this SnackBar will be shown before dismissing.
* @param duration If 0, then the SnackBar will not be dismissed until {@link #dismiss() dismiss()} is called.
* @return This SnackBar for chaining methods.
*/
public SnackBar duration(long duration){
mDuration = duration;
return this;
}
/**
* Set the background color of this SnackBar.
* @param color The color of background.
* @return This SnackBar for chaining methods.
*/
public SnackBar backgroundColor(int color){
mBackground.setColor(color);
return this;
}
/**
* Set the background's corner radius of this SnackBar.
* @param radius The corner radius.
* @return This SnackBar for chaining methods.
*/
public SnackBar backgroundRadius(int radius){
mBackground.setRadius(radius);
return this;
}
/**
* Set the horizontal padding between this SnackBar and it's text and button.
* @param padding
* @return This SnackBar for chaining methods.
*/
public SnackBar horizontalPadding(int padding){
mText.setPadding(padding, mText.getPaddingTop(), padding, mText.getPaddingBottom());
mAction.setPadding(padding, mAction.getPaddingTop(), padding, mAction.getPaddingBottom());
return this;
}
/**
* Set the vertical padding between this SnackBar and it's text and button.
* @param padding
* @return This SnackBar for chaining methods.
*/
public SnackBar verticalPadding(int padding){
mText.setPadding(mText.getPaddingLeft(), padding, mText.getPaddingRight(), padding);
mAction.setPadding(mAction.getPaddingLeft(), padding, mAction.getPaddingRight(), padding);
return this;
}
/**
* Set the padding between this SnackBar and it's text and button.
* @param horizontalPadding The horizontal padding.
* @param verticalPadding The vertical padding.
* @return This SnackBar for chaining methods.
*/
public SnackBar padding(int horizontalPadding, int verticalPadding){
mText.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
mAction.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
return this;
}
/**
* Makes this SnackBar exactly this many pixels wide.
* @param width The width value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar width(int width){
mWidth = width;
return this;
}
/**
* Makes this SnackBar at least this many pixels wide
* @param width The minimum width value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar minWidth(int width){
mText.setMinWidth(width);
return this;
}
/**
* Makes this SnackBar at most this many pixels wide
* @param width The maximum width value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar maxWidth(int width){
mText.setMaxWidth(width);
return this;
}
/**
* Makes this SnackBar exactly this many pixels tall.
* @param height The height value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar height(int height){
mHeight = height;
return this;
}
/**
* Makes this SnackBar at most this many pixels tall
* @param height The maximum height value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar maxHeight(int height){
mMaxHeight = height;
return this;
}
/**
* Makes this SnackBar at least this many pixels tall
* @param height The maximum height value in pixels.
* @return This SnackBar for chaining methods.
*/
public SnackBar minHeight(int height){
mMinHeight = height;
return this;
}
/**
* Set the start margin between this SnackBar and it's parent.
* @param size
* @return This SnackBar for chaining methods.
*/
public SnackBar marginStart(int size){
mMarginStart = size;
return this;
}
/**
* Set the bottom margin between this SnackBar and it's parent.
* @param size
* @return This SnackBar for chaining methods.
*/
public SnackBar marginBottom(int size){
mMarginBottom = size;
return this;
}
/**
* Set the listener will be called when the ActionButton is clicked.
* @param listener The {@link SnackBar.OnActionClickListener} will be called.
* @return This SnackBar for chaining methods.
*/
public SnackBar actionClickListener(OnActionClickListener listener){
mActionClickListener = listener;
return this;
}
/**
* Set the listener will be called when this SnackBar's state is changed.
* @param listener The {@link SnackBar.OnStateChangeListener} will be called.
* @return This SnackBar for chaining methods.
*/
public SnackBar stateChangeListener(OnStateChangeListener listener){
mStateChangeListener = listener;
return this;
}
/**
* Indicate that this SnackBar should remove itself from parent view after being dismissed.
* @param b
* @return This SnackBar for chaining methods.
*/
public SnackBar removeOnDismiss(boolean b){
mRemoveOnDismiss = b;
return this;
}
/**
* Show this SnackBar. It will auto attach to the activity's root view.
* @param activity
*/
public void show(Activity activity){
show((ViewGroup)activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT));
}
/**
* Show this SnackBar. It will auto attach to the parent view.
* @param parent Must be {@linke android.widget.FrameLayout} or {@link android.widget.RelativeLayout}
*/
public void show(ViewGroup parent){
if(mState == STATE_SHOWING || mState == STATE_DISMISSING)
return;
if(getParent() != parent) {
if(getParent() != null)
((ViewGroup) getParent()).removeView(this);
parent.addView(this);
}
show();
}
/**
* Show this SnackBar.
* Make sure it already attached to a parent view or this method will do nothing.
*/
public void show(){
ViewGroup parent = (ViewGroup)getParent();
if(parent == null || mState == STATE_SHOWING || mState == STATE_DISMISSING)
return;
if(parent instanceof FrameLayout){
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)getLayoutParams();
params.width = mWidth;
params.height = mHeight;
params.gravity = Gravity.START | Gravity.BOTTOM;
if(mIsRtl)
params.rightMargin = mMarginStart;
else
params.leftMargin = mMarginStart;
params.bottomMargin = mMarginBottom;
}
else if(parent instanceof RelativeLayout){
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)getLayoutParams();
params.width = mWidth;
params.height = mHeight;
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.ALIGN_PARENT_START);
if(mIsRtl)
params.rightMargin = mMarginStart;
else
params.leftMargin = mMarginStart;
params.bottomMargin = mMarginBottom;
}
if(mInAnimationId != 0 && mState != STATE_SHOWN){
Animation anim = AnimationUtils.loadAnimation(getContext(), mInAnimationId);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
setState(STATE_SHOWING);
setVisibility(View.VISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
setState(STATE_SHOWN);
startTimer();
}
});
startAnimation(anim);
}
else{
setVisibility(View.VISIBLE);
setState(STATE_SHOWN);
startTimer();
}
}
private void startTimer(){
removeCallbacks(mDismissRunnable);
if(mDuration > 0)
postDelayed(mDismissRunnable, mDuration);
}
/**
* Dismiss this SnackBar. It must be in {@link #STATE_SHOWN} to be dismissed.
*/
public void dismiss(){
if(mState != STATE_SHOWN)
return;
removeCallbacks(mDismissRunnable);
if(mOutAnimationId != 0){
Animation anim = AnimationUtils.loadAnimation(getContext(), mOutAnimationId);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
setState(STATE_DISMISSING);
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
if(mRemoveOnDismiss && getParent() != null && getParent() instanceof ViewGroup)
((ViewGroup)getParent()).removeView(SnackBar.this);
setState(STATE_DISMISSED);
setVisibility(View.GONE);
}
});
startAnimation(anim);
}
else{
if(mRemoveOnDismiss && getParent() != null && getParent() instanceof ViewGroup)
((ViewGroup)getParent()).removeView(this);
setState(STATE_DISMISSED);
setVisibility(View.GONE);
}
}
/**
* Get the current state of this SnackBar.
* @return The current state of this SnackBar. Can be {@link #STATE_DISMISSED}, {@link #STATE_DISMISSING}, {@link #STATE_SHOWING} or {@link #STATE_SHOWN}.
*/
public int getState(){
return mState;
}
private void setState(int state){
if(mState != state){
int oldState = mState;
mState = state;
if(mStateChangeListener != null)
mStateChangeListener.onStateChange(this, oldState, mState);
}
}
private class BackgroundDrawable extends Drawable{
private int mBackgroundColor;
private int mBackgroundRadius;
private Paint mPaint;
private RectF mRect;
public BackgroundDrawable(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mRect = new RectF();
}
public void setColor(int color){
if(mBackgroundColor != color){
mBackgroundColor = color;
mPaint.setColor(mBackgroundColor);
invalidateSelf();
}
}
public void setRadius(int radius){
if(mBackgroundRadius != radius){
mBackgroundRadius = radius;
invalidateSelf();
}
}
@Override
protected void onBoundsChange(Rect bounds) {
mRect.set(bounds);
}
@Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mRect, mBackgroundRadius, mBackgroundRadius, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
}