Snackbar.java revision b7f9224b1495db47eb8fd813b5912250e900770a
1b7f9224b1495db47eb8fd813b5912250e900770aChris Banes/* 2b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Copyright (C) 2015 The Android Open Source Project 3b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 4b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * you may not use this file except in compliance with the License. 6b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * You may obtain a copy of the License at 7b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 8b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * http://www.apache.org/licenses/LICENSE-2.0 9b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 10b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Unless required by applicable law or agreed to in writing, software 11b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * See the License for the specific language governing permissions and 14b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * limitations under the License. 15b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 16b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 17b7f9224b1495db47eb8fd813b5912250e900770aChris Banespackage android.support.design.widget; 18b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 19b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.content.Context; 20b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.content.res.TypedArray; 21b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Build; 22b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Handler; 23b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Looper; 24b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Message; 25b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.IntDef; 26b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.StringRes; 27b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.design.R; 28b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewCompat; 29b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewPropertyAnimatorListenerAdapter; 30b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.text.TextUtils; 31b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.util.AttributeSet; 32b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.LayoutInflater; 33b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.MotionEvent; 34b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.View; 35b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.ViewGroup; 36b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.Animation; 37b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.AnimationUtils; 38b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.LinearLayout; 39b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.TextView; 40b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 41b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.Retention; 42b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.RetentionPolicy; 43b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 44b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport static android.support.design.widget.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR; 45b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 46b7f9224b1495db47eb8fd813b5912250e900770aChris Banes/** 47b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars provide lightweight feedback about an operation. They show a brief message at the 48b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other 49b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * elements on screen and only one can be displayed at a time. 50b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p> 51b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * They automatically disappear after a timeout or after user interaction elsewhere on the screen, 52b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * particularly after interactions that summon a new surface or activity. Snackbars can be swiped 53b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * off screen. 54b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p> 55b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars can contain an action which is set via 56b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * {@link #setAction(CharSequence, android.view.View.OnClickListener)}. 57b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 58b7f9224b1495db47eb8fd813b5912250e900770aChris Banespublic class Snackbar { 59b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 60b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 61b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @hide 62b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 63b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @IntDef({LENGTH_SHORT, LENGTH_LONG}) 64b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Retention(RetentionPolicy.SOURCE) 65b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public @interface Duration {} 66b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 67b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 68b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the Snackbar for a short period of time. 69b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 70b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 71b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 72b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static final int LENGTH_SHORT = -1; 73b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 74b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 75b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the Snackbar for a long period of time. 76b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 77b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 78b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 79b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static final int LENGTH_LONG = 0; 80b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 81b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int ANIMATION_DURATION = 250; 82b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int ANIMATION_FADE_DURATION = 180; 83b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 84b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final Handler sHandler; 85b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int MSG_SHOW = 0; 86b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int MSG_DISMISS = 1; 87b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 88b7f9224b1495db47eb8fd813b5912250e900770aChris Banes static { 89b7f9224b1495db47eb8fd813b5912250e900770aChris Banes sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() { 90b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 91b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean handleMessage(Message message) { 92b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (message.what) { 93b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MSG_SHOW: 94b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ((Snackbar) message.obj).showView(); 95b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return true; 96b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MSG_DISMISS: 97b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ((Snackbar) message.obj).hideView(); 98b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return true; 99b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 100b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return false; 101b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 102b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 103b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 104b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 105b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final ViewGroup mParent; 106b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final Context mContext; 107b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final SnackbarLayout mView; 108b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mDuration; 109b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 110b7f9224b1495db47eb8fd813b5912250e900770aChris Banes Snackbar(ViewGroup parent) { 111b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mParent = parent; 112b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mContext = parent.getContext(); 113b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 114b7f9224b1495db47eb8fd813b5912250e900770aChris Banes LayoutInflater inflater = LayoutInflater.from(mContext); 115b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView = (SnackbarLayout) inflater.inflate(R.layout.layout_snackbar, mParent, false); 116b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 117b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 118b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 119b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Make a Snackbar to display a message. 120b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 121b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param parent The parent to add Snackbars to. 122b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param text The text to show. Can be formatted text. 123b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration How long to display the message. Either {@link #LENGTH_SHORT} or {@link 124b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * #LENGTH_LONG} 125b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 126b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static Snackbar make(ViewGroup parent, CharSequence text, @Duration int duration) { 127b7f9224b1495db47eb8fd813b5912250e900770aChris Banes Snackbar snackbar = new Snackbar(parent); 128b7f9224b1495db47eb8fd813b5912250e900770aChris Banes snackbar.setText(text); 129b7f9224b1495db47eb8fd813b5912250e900770aChris Banes snackbar.setDuration(duration); 130b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return snackbar; 131b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 132b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 133b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 134b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Make a Snackbar to display a message. 135b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 136b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param parent The parent to add Snackbars to. 137b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param resId The resource id of the string resource to use. Can be formatted text. 138b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration How long to display the message. Either {@link #LENGTH_SHORT} or {@link 139b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * #LENGTH_LONG} 140b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 141b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static Snackbar make(ViewGroup parent, int resId, @Duration int duration) { 142b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return make(parent, parent.getResources().getText(resId), duration); 143b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 144b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 145b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 146b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set the action to be displayed in this {@link Snackbar}. 147b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 148b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param resId String resource to display 149b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param listener callback to be invoked when the action is clicked 150b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 151b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setAction(@StringRes int resId, View.OnClickListener listener) { 152b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return setAction(mContext.getText(resId), listener); 153b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 154b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 155b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 156b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set the action to be displayed in this {@link Snackbar}. 157b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 158b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param text Text to display 159b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param listener callback to be invoked when the action is clicked 160b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 161b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setAction(CharSequence text, final View.OnClickListener listener) { 162b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final TextView tv = mView.getActionView(); 163b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 164b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (TextUtils.isEmpty(text) || listener == null) { 165b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setVisibility(View.GONE); 166b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setOnClickListener(null); 167b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 168b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setVisibility(View.VISIBLE); 169b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setText(text); 170b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setOnClickListener(new View.OnClickListener() { 171b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 172b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onClick(View view) { 173b7f9224b1495db47eb8fd813b5912250e900770aChris Banes listener.onClick(view); 174b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 175b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Now dismiss the Snackbar 176b7f9224b1495db47eb8fd813b5912250e900770aChris Banes dismiss(); 177b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 178b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 179b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 180b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 181b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 182b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 183b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 184b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Update the text in this {@link Snackbar}. 185b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 186b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param message The new text for the Toast. 187b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 188b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setText(CharSequence message) { 189b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final TextView tv = mView.getMessageView(); 190b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setText(message); 191b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 192b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 193b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 194b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 195b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Update the text in this {@link Snackbar}. 196b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 197b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param resId The new text for the Toast. 198b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 199b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setText(@StringRes int resId) { 200b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return setText(mContext.getText(resId)); 201b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 202b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 203b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 204b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set how long to show the view for. 205b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 206b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration either be one of the predefined lengths: 207b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * {@link #LENGTH_SHORT}, {@link #LENGTH_LONG}, or a custom duration 208b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * in milliseconds. 209b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 210b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setDuration(@Duration int duration) { 211b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mDuration = duration; 212b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 213b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 214b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 215b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 216b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Return the duration. 217b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 218b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 219b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 220b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Duration 221b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public int getDuration() { 222b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mDuration; 223b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 224b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 225b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 226b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Returns the {@link Snackbar}'s view. 227b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 228b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public View getView() { 229b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mView; 230b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 231b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 232b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 233b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the {@link Snackbar}. 234b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 235b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void show() { 236b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().show(mDuration, mManagerCallback); 237b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 238b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 239b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 240b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Dismiss the {@link Snackbar}. 241b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 242b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void dismiss() { 243b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().dismiss(mManagerCallback); 244b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 245b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 246b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() { 247b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 248b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void show() { 249b7f9224b1495db47eb8fd813b5912250e900770aChris Banes sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this)); 250b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 251b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 252b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 253b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void dismiss() { 254b7f9224b1495db47eb8fd813b5912250e900770aChris Banes sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, Snackbar.this)); 255b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 256b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }; 257b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 258b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final void showView() { 259b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mView.getParent() == null) { 260b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final ViewGroup.LayoutParams lp = mView.getLayoutParams(); 261b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 262b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (lp instanceof CoordinatorLayout.LayoutParams) { 263b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior 264b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 265b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final Behavior behavior = new Behavior(); 266b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setStartAlphaSwipeDistance(0.1f); 267b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setEndAlphaSwipeDistance(0.6f); 268b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END); 269b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setListener(new SwipeDismissBehavior.OnDismissListener() { 270b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 271b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onDismiss(View view) { 272b7f9224b1495db47eb8fd813b5912250e900770aChris Banes dismiss(); 273b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 274b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 275b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 276b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onDragStateChanged(int state) { 277b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (state) { 278b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_DRAGGING: 279b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_SETTLING: 280b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view is being dragged or settling, cancel the timeout 281b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().cancelTimeout(mManagerCallback); 282b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 283b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_IDLE: 284b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view has been released and is idle, restore the timeout 285b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().restoreTimeout(mManagerCallback); 286b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 287b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 288b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 289b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 290b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior); 291b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 292b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 293b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mParent.addView(mView); 294b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 295b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 296b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (ViewCompat.isLaidOut(mView)) { 297b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view is already laid out, animate it now 298b7f9224b1495db47eb8fd813b5912250e900770aChris Banes animateViewIn(); 299b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 300b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Otherwise, add one of our layout change listeners and animate it in when laid out 301b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.setOnLayoutChangeListener(new SnackbarLayout.OnLayoutChangeListener() { 302b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 303b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onLayoutChange(View view, int left, int top, int right, int bottom) { 304b7f9224b1495db47eb8fd813b5912250e900770aChris Banes animateViewIn(); 305b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.setOnLayoutChangeListener(null); 306b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 307b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 308b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 309b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 310b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 311b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private void animateViewIn() { 312b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 313b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setTranslationY(mView, mView.getHeight()); 314b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mView).translationY(0f) 315b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) 316b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setDuration(ANIMATION_DURATION) 317b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setListener(new ViewPropertyAnimatorListenerAdapter() { 318b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 319b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(View view) { 320b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.animateChildrenIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION, 321b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ANIMATION_FADE_DURATION); 322b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 323b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 324b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 325b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(View view) { 326b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().onShown(mManagerCallback); 327b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 328b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }).start(); 329b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 330b7f9224b1495db47eb8fd813b5912250e900770aChris Banes Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.snackbar_in); 331b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); 332b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setDuration(ANIMATION_DURATION); 333b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setAnimationListener(new Animation.AnimationListener() { 334b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 335b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(Animation animation) { 336b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().onShown(mManagerCallback); 337b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 338b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 339b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 340b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(Animation animation) {} 341b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 342b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 343b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationRepeat(Animation animation) {} 344b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 345b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.startAnimation(anim); 346b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 347b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 348b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 349b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private void animateViewOut() { 350b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 351b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mView).translationY(mView.getHeight()) 352b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) 353b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setDuration(ANIMATION_DURATION) 354b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setListener(new ViewPropertyAnimatorListenerAdapter() { 355b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 356b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(View view) { 357b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.animateChildrenOut(0, ANIMATION_FADE_DURATION); 358b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 359b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 360b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 361b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(View view) { 362b7f9224b1495db47eb8fd813b5912250e900770aChris Banes onViewHidden(); 363b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 364b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }).start(); 365b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 366b7f9224b1495db47eb8fd813b5912250e900770aChris Banes Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.snackbar_out); 367b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); 368b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setDuration(ANIMATION_DURATION); 369b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setAnimationListener(new Animation.AnimationListener() { 370b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 371b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(Animation animation) { 372b7f9224b1495db47eb8fd813b5912250e900770aChris Banes onViewHidden(); 373b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 374b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 375b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 376b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(Animation animation) {} 377b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 378b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 379b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationRepeat(Animation animation) {} 380b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 381b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.startAnimation(anim); 382b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 383b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 384b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 385b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final void hideView() { 386b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mView.getVisibility() != View.VISIBLE || isBeingDragged()) { 387b7f9224b1495db47eb8fd813b5912250e900770aChris Banes onViewHidden(); 388b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 389b7f9224b1495db47eb8fd813b5912250e900770aChris Banes animateViewOut(); 390b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 391b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 392b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 393b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private void onViewHidden() { 394b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // First remove the view from the parent 395b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mParent.removeView(mView); 396b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Now, tell the SnackbarManager that it has been dismissed 397b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().onDismissed(mManagerCallback); 398b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 399b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 400b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 401b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @return if the view is being being dragged or settled by {@link SwipeDismissBehavior}. 402b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 403b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private boolean isBeingDragged() { 404b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final ViewGroup.LayoutParams lp = mView.getLayoutParams(); 405b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 406b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (lp instanceof CoordinatorLayout.LayoutParams) { 407b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final CoordinatorLayout.LayoutParams cllp = (CoordinatorLayout.LayoutParams) lp; 408b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final CoordinatorLayout.Behavior behavior = cllp.getBehavior(); 409b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 410b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (behavior instanceof SwipeDismissBehavior) { 411b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return ((SwipeDismissBehavior) behavior).getDragState() 412b7f9224b1495db47eb8fd813b5912250e900770aChris Banes != SwipeDismissBehavior.STATE_IDLE; 413b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 414b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 415b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return false; 416b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 417b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 418b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 419b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @hide 420b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 421b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static class SnackbarLayout extends LinearLayout { 422b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private TextView mMessageView; 423b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private TextView mActionView; 424b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 425b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mMaxWidth; 426b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mMaxInlineActionWidth; 427b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 428b7f9224b1495db47eb8fd813b5912250e900770aChris Banes interface OnLayoutChangeListener { 429b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onLayoutChange(View view, int left, int top, int right, int bottom); 430b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 431b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 432b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private OnLayoutChangeListener mOnLayoutChangeListener; 433b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 434b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public SnackbarLayout(Context context) { 435b7f9224b1495db47eb8fd813b5912250e900770aChris Banes this(context, null); 436b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 437b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 438b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public SnackbarLayout(Context context, AttributeSet attrs) { 439b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super(context, attrs); 440b7f9224b1495db47eb8fd813b5912250e900770aChris Banes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout); 441b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMaxWidth = a.getDimensionPixelSize(R.styleable.SnackbarLayout_android_maxWidth, -1); 442b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMaxInlineActionWidth = a.getDimensionPixelSize( 443b7f9224b1495db47eb8fd813b5912250e900770aChris Banes R.styleable.SnackbarLayout_maxActionInlineWidth, -1); 444b7f9224b1495db47eb8fd813b5912250e900770aChris Banes a.recycle(); 445b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 446b7f9224b1495db47eb8fd813b5912250e900770aChris Banes setClickable(true); 447b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 448b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Now inflate our content. We need to do this manually rather than using an <include> 449b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // in the layout since older versions of the Android do not inflate includes with 450b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // the correct Context. 451b7f9224b1495db47eb8fd813b5912250e900770aChris Banes LayoutInflater.from(context).inflate(R.layout.layout_snackbar_include, this); 452b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 453b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 454b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 455b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onFinishInflate() { 456b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onFinishInflate(); 457b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMessageView = (TextView) findViewById(R.id.snackbar_text); 458b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mActionView = (TextView) findViewById(R.id.snackbar_action); 459b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 460b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 461b7f9224b1495db47eb8fd813b5912250e900770aChris Banes TextView getMessageView() { 462b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mMessageView; 463b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 464b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 465b7f9224b1495db47eb8fd813b5912250e900770aChris Banes TextView getActionView() { 466b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mActionView; 467b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 468b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 469b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 470b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 471b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 472b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 473b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mMaxWidth > 0 && getMeasuredWidth() > mMaxWidth) { 474b7f9224b1495db47eb8fd813b5912250e900770aChris Banes widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY); 475b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 476b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 477b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 478b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int multiLineVPadding = getResources().getDimensionPixelSize( 479b7f9224b1495db47eb8fd813b5912250e900770aChris Banes R.dimen.snackbar_padding_vertical_2lines); 480b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int singleLineVPadding = getResources().getDimensionPixelSize( 481b7f9224b1495db47eb8fd813b5912250e900770aChris Banes R.dimen.snackbar_padding_vertical); 482b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final boolean isMultiLine = mMessageView.getLayout().getLineCount() > 1; 483b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 484b7f9224b1495db47eb8fd813b5912250e900770aChris Banes boolean remeasure = false; 485b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (isMultiLine && mMaxInlineActionWidth > 0 486b7f9224b1495db47eb8fd813b5912250e900770aChris Banes && mActionView.getMeasuredWidth() > mMaxInlineActionWidth) { 487b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (updateViewsWithinLayout(VERTICAL, multiLineVPadding, 488b7f9224b1495db47eb8fd813b5912250e900770aChris Banes multiLineVPadding - singleLineVPadding)) { 489b7f9224b1495db47eb8fd813b5912250e900770aChris Banes remeasure = true; 490b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 491b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 492b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int messagePadding = isMultiLine ? multiLineVPadding : singleLineVPadding; 493b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (updateViewsWithinLayout(HORIZONTAL, messagePadding, messagePadding)) { 494b7f9224b1495db47eb8fd813b5912250e900770aChris Banes remeasure = true; 495b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 496b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 497b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 498b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (remeasure) { 499b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 500b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 501b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 502b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 503b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void animateChildrenIn(int delay, int duration) { 504b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mMessageView, 0f); 505b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mMessageView).alpha(1f).setDuration(duration) 506b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 507b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 508b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mActionView.getVisibility() == VISIBLE) { 509b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mActionView, 0f); 510b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mActionView).alpha(1f).setDuration(duration) 511b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 512b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 513b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 514b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 515b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void animateChildrenOut(int delay, int duration) { 516b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mMessageView, 1f); 517b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mMessageView).alpha(0f).setDuration(duration) 518b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 519b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 520b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mActionView.getVisibility() == VISIBLE) { 521b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mActionView, 1f); 522b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mActionView).alpha(0f).setDuration(duration) 523b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 524b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 525b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 526b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 527b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 528b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onLayout(boolean changed, int l, int t, int r, int b) { 529b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onLayout(changed, l, t, r, b); 530b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (changed && mOnLayoutChangeListener != null) { 531b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mOnLayoutChangeListener.onLayoutChange(this, l, t, r, b); 532b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 533b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 534b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 535b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) { 536b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mOnLayoutChangeListener = onLayoutChangeListener; 537b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 538b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 539b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private boolean updateViewsWithinLayout(final int orientation, 540b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int messagePadTop, final int messagePadBottom) { 541b7f9224b1495db47eb8fd813b5912250e900770aChris Banes boolean changed = false; 542b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (orientation != getOrientation()) { 543b7f9224b1495db47eb8fd813b5912250e900770aChris Banes setOrientation(orientation); 544b7f9224b1495db47eb8fd813b5912250e900770aChris Banes changed = true; 545b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 546b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mMessageView.getPaddingTop() != messagePadTop 547b7f9224b1495db47eb8fd813b5912250e900770aChris Banes || mMessageView.getPaddingBottom() != messagePadBottom) { 548b7f9224b1495db47eb8fd813b5912250e900770aChris Banes updateTopBottomPadding(mMessageView, messagePadTop, messagePadBottom); 549b7f9224b1495db47eb8fd813b5912250e900770aChris Banes changed = true; 550b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 551b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return changed; 552b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 553b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 554b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static void updateTopBottomPadding(View view, int topPadding, int bottomPadding) { 555b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (ViewCompat.isPaddingRelative(view)) { 556b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setPaddingRelative(view, 557b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.getPaddingStart(view), topPadding, 558b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.getPaddingEnd(view), bottomPadding); 559b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 560b7f9224b1495db47eb8fd813b5912250e900770aChris Banes view.setPadding(view.getPaddingLeft(), topPadding, 561b7f9224b1495db47eb8fd813b5912250e900770aChris Banes view.getPaddingRight(), bottomPadding); 562b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 563b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 564b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 565b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 566b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final class Behavior extends SwipeDismissBehavior<SnackbarLayout> { 567b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 568b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarLayout child, 569b7f9224b1495db47eb8fd813b5912250e900770aChris Banes MotionEvent event) { 570b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // We want to make sure that we disable any Snackbar timeouts if the user is 571b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // currently touching the Snackbar. We restore the timeout when complete 572b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY())) { 573b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (event.getActionMasked()) { 574b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_DOWN: 575b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().cancelTimeout(mManagerCallback); 576b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 577b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_UP: 578b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_CANCEL: 579b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().restoreTimeout(mManagerCallback); 580b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 581b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 582b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 583b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 584b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return super.onInterceptTouchEvent(parent, child, event); 585b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 586b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 587b7f9224b1495db47eb8fd813b5912250e900770aChris Banes} 588