可顶部和底部显示的Snackbar

来源:互联网 发布:淘宝网商城食品香外香 编辑:程序博客网 时间:2024/05/18 07:15


   作为一名懒程序猿,不想写过多的代码,所以我很多都是直接在源码中复制的。代码有很多优化之处,根据自己需求来改吧,这里我只是做一个笔记,分享给大家。再次说明:我!真!的!很!懒!

   既然要修改源码,所以你要清楚目的是什么。这里我的目标很明确,就是想把Snackbar既可以向上显示,也可以在底部显示,并且没有大的改动。我看源码发现布局文件design_layout_snackbar中有个layout_gravity 我猜这个是显示位置的参数了。我把它改为top,没想到成功了!但是问题来了,动画效果很丑!那么我就找到animateViewIn() animateViewOut(final int event) 这两个方法。看源码

import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.os.Build;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.annotation.ColorInt;import android.support.annotation.IntDef;import android.support.annotation.IntRange;import android.support.annotation.NonNull;import android.support.annotation.StringRes;import android.support.design.widget.CoordinatorLayout;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.design.widget.SwipeDismissBehavior;import android.support.v4.view.ViewCompat;import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;import android.support.v4.view.WindowInsetsCompat;import android.text.TextUtils;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.ViewParent;import android.view.accessibility.AccessibilityManager;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.widget.Button;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.TextView;import com.ut.teambrige.R;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import static com.ut.teambrige.widget.bar.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR;/** * Created by Charlie on 2016/10/9. */public final class MySnackbar {    /**     * Callback class for {@link Snackbar} instances.     *     * @see Snackbar#setCallback(Snackbar.Callback)     */    public static abstract class Callback {        /**         * Indicates that the Snackbar was dismissed via a swipe.         */        public static final int DISMISS_EVENT_SWIPE = 0;        /**         * Indicates that the Snackbar was dismissed via an action click.         */        public static final int DISMISS_EVENT_ACTION = 1;        /**         * Indicates that the Snackbar was dismissed via a timeout.         */        public static final int DISMISS_EVENT_TIMEOUT = 2;        /**         * Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}.         */        public static final int DISMISS_EVENT_MANUAL = 3;        /**         * Indicates that the Snackbar was dismissed from a new Snackbar being shown.         */        public static final int DISMISS_EVENT_CONSECUTIVE = 4;        /**         * @hide         */        @IntDef({DISMISS_EVENT_SWIPE, DISMISS_EVENT_ACTION, DISMISS_EVENT_TIMEOUT,                DISMISS_EVENT_MANUAL, DISMISS_EVENT_CONSECUTIVE})        @Retention(RetentionPolicy.SOURCE)        public @interface DismissEvent {        }        /**         * Called when the given {@link Snackbar} has been dismissed, either through a time-out,         * having been manually dismissed, or an action being clicked.         *         * @param snackbar The snackbar which has been dismissed.         * @param event    The event which caused the dismissal. One of either:         *                 {@link #DISMISS_EVENT_SWIPE}, {@link #DISMISS_EVENT_ACTION},         *                 {@link #DISMISS_EVENT_TIMEOUT}, {@link #DISMISS_EVENT_MANUAL} or         *                 {@link #DISMISS_EVENT_CONSECUTIVE}.         * @see Snackbar#dismiss()         */        public void onDismissed(MySnackbar snackbar, @Snackbar.Callback.DismissEvent int event) {            // empty        }        /**         * Called when the given {@link Snackbar} is visible.         *         * @param snackbar The snackbar which is now visible.         * @see Snackbar#show()         */        public void onShown(MySnackbar snackbar) {            // empty        }    }    /**     * @hide     */    @IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG})    @IntRange(from = 1)    @Retention(RetentionPolicy.SOURCE)    public @interface Duration {    }    /**     * Show the Snackbar indefinitely. This means that the Snackbar will be displayed from the time     * that is {@link #show() shown} until either it is dismissed, or another Snackbar is shown.     *     * @see #setDuration     */    public static final int LENGTH_INDEFINITE = -2;    /**     * Show the Snackbar for a short period of time.     *     * @see #setDuration     */    public static final int LENGTH_SHORT = -1;    /**     * Show the Snackbar for a long period of time.     *     * @see #setDuration     */    public static final int LENGTH_LONG = 0;    static final int ANIMATION_DURATION = 250;    static final int ANIMATION_FADE_DURATION = 180;    static final Handler sHandler;    static final int MSG_SHOW = 0;    static final int MSG_DISMISS = 1;    static {        sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {            @Override            public boolean handleMessage(Message message) {                switch (message.what) {                    case MSG_SHOW:                        ((MySnackbar) message.obj).showView();                        return true;                    case MSG_DISMISS:                        ((MySnackbar) message.obj).hideView(message.arg1);                        return true;                }                return false;            }        });    }    private final ViewGroup mTargetParent;    private final Context mContext;    final MySnackbar.SnackbarLayout mView;    private int mDuration;    private MySnackbar.Callback mCallback;    private int mGravity = 0;    private final AccessibilityManager mAccessibilityManager;    private MySnackbar(ViewGroup parent, int gravity) {        mTargetParent = parent;        mContext = parent.getContext();        LayoutInflater inflater = LayoutInflater.from(mContext);        if (gravity == 0) {            mView = (MySnackbar.SnackbarLayout) inflater.inflate(                    R.layout.layout_snackbar_top, mTargetParent, false);        } else {            mView = (MySnackbar.SnackbarLayout) inflater.inflate(                    R.layout.layout_snackbar_bottom, mTargetParent, false);        }        mAccessibilityManager = (AccessibilityManager)                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);    }    /**     * Make a Snackbar to display a message     * <p>     * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given     * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent,     * which is defined as a {@link CoordinatorLayout} or the window decor's content view,     * whichever comes first.     * <p>     * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable     * certain features, such as swipe-to-dismiss and automatically moving of widgets like     * {@link FloatingActionButton}.     *     * @param view     The view to find a parent from.     * @param text     The text to show.  Can be formatted text.     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link     *                 #LENGTH_LONG}     */    @NonNull    public static MySnackbar make(@NonNull View view, @NonNull CharSequence text,                                  @Snackbar.Duration int duration, int gravity) {        MySnackbar snackbar = new MySnackbar(findSuitableParent(view), gravity);        snackbar.setText(text);        snackbar.setDuration(duration);        snackbar.setGravity(gravity);        return snackbar;    }    /**     * Make a Snackbar to display a message.     * <p>     * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given     * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent,     * which is defined as a {@link CoordinatorLayout} or the window decor's content view,     * whichever comes first.     * <p>     * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable     * certain features, such as swipe-to-dismiss and automatically moving of widgets like     * {@link FloatingActionButton}.     *     * @param view     The view to find a parent from.     * @param resId    The resource id of the string resource to use. Can be formatted text.     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link     *                 #LENGTH_LONG}     */    @NonNull    public static MySnackbar make(@NonNull View view, @StringRes int resId, @Snackbar.Duration int duration, int gravity) {        return make(view, view.getResources().getText(resId), duration, gravity);    }    private static ViewGroup findSuitableParent(View view) {        ViewGroup fallback = null;        do {            if (view instanceof CoordinatorLayout) {                // We've found a CoordinatorLayout, use it                return (ViewGroup) view;            } else if (view instanceof FrameLayout) {                if (view.getId() == android.R.id.content) {                    // If we've hit the decor content view, then we didn't find a CoL in the                    // hierarchy, so use it.                    return (ViewGroup) view;                } else {                    // It's not the content view but we'll use it as our fallback                    fallback = (ViewGroup) view;                }            }            if (view != null) {                // Else, we will loop and crawl up the view hierarchy and try to find a parent                final ViewParent parent = view.getParent();                view = parent instanceof View ? (View) parent : null;            }        } while (view != null);        // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback        return fallback;    }    /**     * Set the action to be displayed in this {@link Snackbar}.     *     * @param resId    String resource to display     * @param listener callback to be invoked when the action is clicked     */    @NonNull    public MySnackbar setAction(@StringRes int resId, View.OnClickListener listener) {        return setAction(mContext.getText(resId), listener);    }    /**     * Set the action to be displayed in this {@link Snackbar}.     *     * @param text     Text to display     * @param listener callback to be invoked when the action is clicked     */    @NonNull    public MySnackbar setAction(CharSequence text, final View.OnClickListener listener) {        final TextView tv = mView.getActionView();        if (TextUtils.isEmpty(text) || listener == null) {            tv.setVisibility(View.GONE);            tv.setOnClickListener(null);        } else {            tv.setVisibility(View.VISIBLE);            tv.setText(text);            tv.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    listener.onClick(view);                    // Now dismiss the Snackbar                    dispatchDismiss(Snackbar.Callback.DISMISS_EVENT_ACTION);                }            });        }        return this;    }    /**     * Sets the text color of the action specified in     * {@link #setAction(CharSequence, View.OnClickListener)}.     */    @NonNull    public MySnackbar setActionTextColor(ColorStateList colors) {        final TextView tv = mView.getActionView();        tv.setTextColor(colors);        return this;    }    /**     * Sets the text color of the action specified in     * {@link #setAction(CharSequence, View.OnClickListener)}.     */    @NonNull    public MySnackbar setActionTextColor(@ColorInt int color) {        final TextView tv = mView.getActionView();        tv.setTextColor(color);        return this;    }    /**     * Update the text in this {@link MySnackbar}.     *     * @param message The new text for the Toast.     */    @NonNull    public MySnackbar setText(@NonNull CharSequence message) {        final TextView tv = mView.getMessageView();        tv.setText(message);        return this;    }    /**     * Update the text in this {@link MySnackbar}.     *     * @param resId The new text for the Toast.     */    @NonNull    public MySnackbar setText(@StringRes int resId) {        return setText(mContext.getText(resId));    }    /**     * Set how long to show the view for.     *     * @param duration either be one of the predefined lengths:     *                 {@link #LENGTH_SHORT}, {@link #LENGTH_LONG}, or a custom duration     *                 in milliseconds.     */    @NonNull    public MySnackbar setDuration(@MySnackbar.Duration int duration) {        mDuration = duration;        return this;    }    @NonNull    public MySnackbar setGravity(int gravity) {        mGravity = gravity;        return this;    }    @NonNull    /**     * Return the duration.     *     * @see #setDuration     */    @MySnackbar.Duration    public int getDuration() {        return mDuration;    }    /**     * Returns the {@link MySnackbar}'s view.     */    @NonNull    public View getView() {        return mView;    }    /**     * Show the {@link MySnackbar}.     */    public void show() {        SnackbarManager.getInstance().show(mDuration, mManagerCallback);    }    /**     * Dismiss the {@link Snackbar}.     */    public void dismiss() {        dispatchDismiss(Snackbar.Callback.DISMISS_EVENT_MANUAL);    }    void dispatchDismiss(@Snackbar.Callback.DismissEvent int event) {        SnackbarManager.getInstance().dismiss(mManagerCallback, event);    }    /**     * Set a callback to be called when this the visibility of this {@link Snackbar} changes.     */    @NonNull    public MySnackbar setCallback(MySnackbar.Callback callback) {        mCallback = callback;        return this;    }    /**     * Return whether this {@link Snackbar} is currently being shown.     */    public boolean isShown() {        return SnackbarManager.getInstance().isCurrent(mManagerCallback);    }    /**     * Returns whether this {@link Snackbar} is currently being shown, or is queued to be     * shown next.     */    public boolean isShownOrQueued() {        return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);    }    final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {        @Override        public void show() {            sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, MySnackbar.this));        }        @Override        public void dismiss(int event) {            sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, event, 0, MySnackbar.this));        }    };    final void showView() {        if (mView.getParent() == null) {            final ViewGroup.LayoutParams lp = mView.getLayoutParams();            if (lp instanceof CoordinatorLayout.LayoutParams) {                // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior                final CoordinatorLayout.LayoutParams clp = (CoordinatorLayout.LayoutParams) lp;                final MySnackbar.Behavior behavior = new MySnackbar.Behavior();                behavior.setStartAlphaSwipeDistance(0.1f);                behavior.setEndAlphaSwipeDistance(0.6f);                behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);                behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {                    @Override                    public void onDismiss(View view) {                        view.setVisibility(View.GONE);                        dispatchDismiss(Snackbar.Callback.DISMISS_EVENT_SWIPE);                    }                    @Override                    public void onDragStateChanged(int state) {                        switch (state) {                            case SwipeDismissBehavior.STATE_DRAGGING:                            case SwipeDismissBehavior.STATE_SETTLING:                                // If the view is being dragged or settling, cancel the timeout                                SnackbarManager.getInstance().cancelTimeout(mManagerCallback);                                break;                            case SwipeDismissBehavior.STATE_IDLE:                                // If the view has been released and is idle, restore the timeout                                SnackbarManager.getInstance().restoreTimeout(mManagerCallback);                                break;                        }                    }                });                clp.setBehavior(behavior);                // Also set the inset edge so that views can dodge the snackbar correctly                clp.insetEdge = Gravity.BOTTOM;            }            mTargetParent.addView(mView);        }        mView.setOnAttachStateChangeListener(new MySnackbar.SnackbarLayout.OnAttachStateChangeListener() {            @Override            public void onViewAttachedToWindow(View v) {            }            @Override            public void onViewDetachedFromWindow(View v) {                if (isShownOrQueued()) {                    // If we haven't already been dismissed then this event is coming from a                    // non-user initiated action. Hence we need to make sure that we callback                    // and keep our state up to date. We need to post the call since removeView()                    // will call through to onDetachedFromWindow and thus overflow.                    sHandler.post(new Runnable() {                        @Override                        public void run() {                            onViewHidden(Snackbar.Callback.DISMISS_EVENT_MANUAL);                        }                    });                }            }        });        if (ViewCompat.isLaidOut(mView)) {            if (shouldAnimate()) {                // If animations are enabled, animate it in                if (mGravity == 0) {                    animateViewInTop();                } else {                    animateViewInBottom();                }            } else {                // Else if anims are disabled just call back now                onViewShown();            }        } else {            // Otherwise, add one of our layout change listeners and show it in when laid out            mView.setOnLayoutChangeListener(new MySnackbar.SnackbarLayout.OnLayoutChangeListener() {                @Override                public void onLayoutChange(View view, int left, int top, int right, int bottom) {                    mView.setOnLayoutChangeListener(null);                    if (shouldAnimate()) {                        // If animations are enabled, animate it in                        if (mGravity == 0) {                            animateViewInTop();                        } else {                            animateViewInBottom();                        }                    } else {                        // Else if anims are disabled just call back now                        onViewShown();                    }                }            });        }    }    void animateViewInBottom() {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {            ViewCompat.setTranslationY(mView, mView.getHeight());            ViewCompat.animate(mView)                    .translationY(0f)                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)                    .setDuration(ANIMATION_DURATION)                    .setListener(new ViewPropertyAnimatorListenerAdapter() {                        @Override                        public void onAnimationStart(View view) {                            mView.animateChildrenIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION,                                    ANIMATION_FADE_DURATION);                        }                        @Override                        public void onAnimationEnd(View view) {                            onViewShown();                        }                    }).start();        } else {            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),                    R.anim.design_snackbar_in);            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);            anim.setDuration(ANIMATION_DURATION);            anim.setAnimationListener(new Animation.AnimationListener() {                @Override                public void onAnimationEnd(Animation animation) {                    onViewShown();                }                @Override                public void onAnimationStart(Animation animation) {                }                @Override                public void onAnimationRepeat(Animation animation) {                }            });            mView.startAnimation(anim);        }    }    private void animateViewOutBottom(final int event) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {            ViewCompat.animate(mView)                    .translationY(mView.getHeight())                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)                    .setDuration(ANIMATION_DURATION)                    .setListener(new ViewPropertyAnimatorListenerAdapter() {                        @Override                        public void onAnimationStart(View view) {                            mView.animateChildrenOut(0, ANIMATION_FADE_DURATION);                        }                        @Override                        public void onAnimationEnd(View view) {                            onViewHidden(event);                        }                    }).start();        } else {            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),                    R.anim.design_snackbar_out);            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);            anim.setDuration(ANIMATION_DURATION);            anim.setAnimationListener(new Animation.AnimationListener() {                @Override                public void onAnimationEnd(Animation animation) {                    onViewHidden(event);                }                @Override                public void onAnimationStart(Animation animation) {                }                @Override                public void onAnimationRepeat(Animation animation) {                }            });            mView.startAnimation(anim);        }    }    private void animateViewInTop() {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {            ViewCompat.setTranslationY(mView, -mView.getHeight());            ViewCompat.animate(mView)                    .translationY(0f)                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)                    .setDuration(ANIMATION_DURATION)                    .setListener(new ViewPropertyAnimatorListenerAdapter() {                        @Override                        public void onAnimationStart(View view) {                            mView.animateChildrenIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION,                                    ANIMATION_FADE_DURATION);                        }                        @Override                        public void onAnimationEnd(View view) {                            if (mCallback != null) {                                mCallback.onShown(MySnackbar.this);                            }                            SnackbarManager.getInstance()                                    .onShown(mManagerCallback);                        }                    })                    .start();        } else {            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),                    R.anim.top_in);            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);            anim.setDuration(ANIMATION_DURATION);            anim.setAnimationListener(new Animation.AnimationListener() {                @Override                public void onAnimationEnd(Animation animation) {                    if (mCallback != null) {                        mCallback.onShown(MySnackbar.this);                    }                    SnackbarManager.getInstance()                            .onShown(mManagerCallback);                }                @Override                public void onAnimationStart(Animation animation) {                }                @Override                public void onAnimationRepeat(Animation animation) {                }            });            mView.startAnimation(anim);        }    }    private void animateViewOutTop(final int event) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {            ViewCompat.animate(mView)                    .translationY(-mView.getHeight())                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)                    .setDuration(ANIMATION_DURATION)                    .setListener(new ViewPropertyAnimatorListenerAdapter() {                        @Override                        public void onAnimationStart(View view) {                            mView.animateChildrenOut(0, ANIMATION_FADE_DURATION);                        }                        @Override                        public void onAnimationEnd(View view) {                            onViewHidden(event);                        }                    })                    .start();        } else {            Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.top_out);            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);            anim.setDuration(ANIMATION_DURATION);            anim.setAnimationListener(new Animation.AnimationListener() {                @Override                public void onAnimationEnd(Animation animation) {                    onViewHidden(event);                }                @Override                public void onAnimationStart(Animation animation) {                }                @Override                public void onAnimationRepeat(Animation animation) {                }            });            mView.startAnimation(anim);        }    }    final void hideView(@Snackbar.Callback.DismissEvent final int event) {        if (shouldAnimate() && mView.getVisibility() == View.VISIBLE) {            if (mGravity == 0) {                animateViewOutTop(event);            } else {                animateViewOutBottom(event);            }        } else {            // If anims are disabled or the view isn't visible, just call back now            onViewHidden(event);        }    }    void onViewShown() {        SnackbarManager.getInstance().onShown(mManagerCallback);        if (mCallback != null) {            mCallback.onShown(this);        }    }    void onViewHidden(int event) {        // First tell the SnackbarManager that it has been dismissed        SnackbarManager.getInstance().onDismissed(mManagerCallback);        // Now call the dismiss listener (if available)        if (mCallback != null) {            mCallback.onDismissed(this, event);        }        if (Build.VERSION.SDK_INT < 11) {            // We need to hide the Snackbar on pre-v11 since it uses an old style Animation.            // ViewGroup has special handling in removeView() when getAnimation() != null in            // that it waits. This then means that the calculated insets are wrong and the            // any dodging views do not return. We workaround it by setting the view to gone while            // ViewGroup actually gets around to removing it.            mView.setVisibility(View.GONE);        }        // Lastly, hide and remove the view from the parent (if attached)        final ViewParent parent = mView.getParent();        if (parent instanceof ViewGroup) {            ((ViewGroup) parent).removeView(mView);        }    }    /**     * Returns true if we should animate the Snackbar view in/out.     */    boolean shouldAnimate() {        return !mAccessibilityManager.isEnabled();    }    /**     * @hide     */    public static class SnackbarLayout extends LinearLayout {        private TextView mMessageView;        private Button mActionView;        private int mMaxWidth;        private int mMaxInlineActionWidth;        interface OnLayoutChangeListener {            void onLayoutChange(View view, int left, int top, int right, int bottom);        }        interface OnAttachStateChangeListener {            void onViewAttachedToWindow(View v);            void onViewDetachedFromWindow(View v);        }        private MySnackbar.SnackbarLayout.OnLayoutChangeListener mOnLayoutChangeListener;        private MySnackbar.SnackbarLayout.OnAttachStateChangeListener mOnAttachStateChangeListener;        public SnackbarLayout(Context context) {            this(context, null);        }        public SnackbarLayout(Context context, AttributeSet attrs) {            super(context, attrs);            TypedArray a = context.obtainStyledAttributes(attrs, android.support.design.R.styleable.SnackbarLayout);            mMaxWidth = a.getDimensionPixelSize(android.support.design.R.styleable.SnackbarLayout_android_maxWidth, -1);            mMaxInlineActionWidth = a.getDimensionPixelSize(                    android.support.design.R.styleable.SnackbarLayout_maxActionInlineWidth, -1);            if (a.hasValue(android.support.design.R.styleable.SnackbarLayout_elevation)) {                ViewCompat.setElevation(this, a.getDimensionPixelSize(                        android.support.design.R.styleable.SnackbarLayout_elevation, 0));            }            a.recycle();            setClickable(true);            // Now inflate our content. We need to do this manually rather than using an <include>            // in the layout since older versions of the Android do not inflate includes with            // the correct Context.            LayoutInflater.from(context).inflate(R.layout.layout_snackbar_include, this);            ViewCompat.setAccessibilityLiveRegion(this,                    ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);            ViewCompat.setImportantForAccessibility(this,                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);            // Make sure that we fit system windows and have a listener to apply any insets            ViewCompat.setFitsSystemWindows(this, true);            ViewCompat.setOnApplyWindowInsetsListener(this,                    new android.support.v4.view.OnApplyWindowInsetsListener() {                        @Override                        public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {                            // Copy over the bottom inset as padding so that we're displayed above the                            // navigation bar                            v.setPadding(v.getPaddingLeft(), v.getPaddingTop(),                                    v.getPaddingRight(), insets.getSystemWindowInsetBottom());                            return insets;                        }                    });        }        @Override        protected void onFinishInflate() {            super.onFinishInflate();            mMessageView = (TextView) findViewById(R.id.snackbar_text);            mActionView = (Button) findViewById(R.id.snackbar_action);        }        TextView getMessageView() {            return mMessageView;        }        Button getActionView() {            return mActionView;        }        @Override        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);            if (mMaxWidth > 0 && getMeasuredWidth() > mMaxWidth) {                widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY);                super.onMeasure(widthMeasureSpec, heightMeasureSpec);            }            final int multiLineVPadding = getResources().getDimensionPixelSize(                    R.dimen.design_snackbar_padding_vertical_2lines);            final int singleLineVPadding = getResources().getDimensionPixelSize(                    R.dimen.design_snackbar_padding_vertical);            final boolean isMultiLine = mMessageView.getLayout().getLineCount() > 1;            boolean remeasure = false;            if (isMultiLine && mMaxInlineActionWidth > 0                    && mActionView.getMeasuredWidth() > mMaxInlineActionWidth) {                if (updateViewsWithinLayout(VERTICAL, multiLineVPadding,                        multiLineVPadding - singleLineVPadding)) {                    remeasure = true;                }            } else {                final int messagePadding = isMultiLine ? multiLineVPadding : singleLineVPadding;                if (updateViewsWithinLayout(HORIZONTAL, messagePadding, messagePadding)) {                    remeasure = true;                }            }            if (remeasure) {                super.onMeasure(widthMeasureSpec, heightMeasureSpec);            }        }        void animateChildrenIn(int delay, int duration) {            ViewCompat.setAlpha(mMessageView, 0f);            ViewCompat.animate(mMessageView).alpha(1f).setDuration(duration)                    .setStartDelay(delay).start();            if (mActionView.getVisibility() == VISIBLE) {                ViewCompat.setAlpha(mActionView, 0f);                ViewCompat.animate(mActionView).alpha(1f).setDuration(duration)                        .setStartDelay(delay).start();            }        }        void animateChildrenOut(int delay, int duration) {            ViewCompat.setAlpha(mMessageView, 1f);            ViewCompat.animate(mMessageView).alpha(0f).setDuration(duration)                    .setStartDelay(delay).start();            if (mActionView.getVisibility() == VISIBLE) {                ViewCompat.setAlpha(mActionView, 1f);                ViewCompat.animate(mActionView).alpha(0f).setDuration(duration)                        .setStartDelay(delay).start();            }        }        @Override        protected void onLayout(boolean changed, int l, int t, int r, int b) {            super.onLayout(changed, l, t, r, b);            if (mOnLayoutChangeListener != null) {                mOnLayoutChangeListener.onLayoutChange(this, l, t, r, b);            }        }        @Override        protected void onAttachedToWindow() {            super.onAttachedToWindow();            if (mOnAttachStateChangeListener != null) {                mOnAttachStateChangeListener.onViewAttachedToWindow(this);            }            ViewCompat.requestApplyInsets(this);        }        @Override        protected void onDetachedFromWindow() {            super.onDetachedFromWindow();            if (mOnAttachStateChangeListener != null) {                mOnAttachStateChangeListener.onViewDetachedFromWindow(this);            }        }        void setOnLayoutChangeListener(MySnackbar.SnackbarLayout.OnLayoutChangeListener onLayoutChangeListener) {            mOnLayoutChangeListener = onLayoutChangeListener;        }        void setOnAttachStateChangeListener(MySnackbar.SnackbarLayout.OnAttachStateChangeListener listener) {            mOnAttachStateChangeListener = listener;        }        private boolean updateViewsWithinLayout(final int orientation,                                                final int messagePadTop, final int messagePadBottom) {            boolean changed = false;            if (orientation != getOrientation()) {                setOrientation(orientation);                changed = true;            }            if (mMessageView.getPaddingTop() != messagePadTop                    || mMessageView.getPaddingBottom() != messagePadBottom) {                updateTopBottomPadding(mMessageView, messagePadTop, messagePadBottom);                changed = true;            }            return changed;        }        private static void updateTopBottomPadding(View view, int topPadding, int bottomPadding) {            if (ViewCompat.isPaddingRelative(view)) {                ViewCompat.setPaddingRelative(view,                        ViewCompat.getPaddingStart(view), topPadding,                        ViewCompat.getPaddingEnd(view), bottomPadding);            } else {                view.setPadding(view.getPaddingLeft(), topPadding,                        view.getPaddingRight(), bottomPadding);            }        }    }    final class Behavior extends SwipeDismissBehavior<Snackbar.SnackbarLayout> {        @Override        public boolean canSwipeDismissView(View child) {            return child instanceof Snackbar.SnackbarLayout;        }        @Override        public boolean onInterceptTouchEvent(CoordinatorLayout parent, Snackbar.SnackbarLayout child,                                             MotionEvent event) {            // We want to make sure that we disable any Snackbar timeouts if the user is            // currently touching the Snackbar. We restore the timeout when complete            if (parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY())) {                switch (event.getActionMasked()) {                    case MotionEvent.ACTION_DOWN:                        SnackbarManager.getInstance().cancelTimeout(mManagerCallback);                        break;                    case MotionEvent.ACTION_UP:                    case MotionEvent.ACTION_CANCEL:                        SnackbarManager.getInstance().restoreTimeout(mManagerCallback);                        break;                }            }            return super.onInterceptTouchEvent(parent, child, event);        }    }}

 

   使用方法

  MySnackbar.make(view, "TEST", Snackbar.LENGTH_SHORT, 0).show();


 最后贴上源码地址:http://download.csdn.net/detail/dameinmax/9648770

 


0 0