Android自定義Toast檢視和動畫
阿新 • • 發佈:2019-02-11
在Android Toast基礎與原理中,我們對Toast的原始碼進行了分析。我們也對Toast的實現原理有了一定的瞭解。接下來我們將編寫一個工具類,來完成Toast的自定義檢視和動畫。
一、實現原理分析
通過上篇文章,我們知道Toast是通過內部類TN(一個ITransientNotification物件)進行實現。通過與INotificationManager進行管理。在原始碼中,我們在TN的建構函式中:
TN() { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately.final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.windowAnimations = com.android.internal.R.style.Animation_Toast; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("Toast"); params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; }
看到在params中設定Toast的顯示動畫。
params.windowAnimations =com.android.internal.R.style.Animation_Toast;
所以我們的實現思路就是通過反射獲取到對應的WindowManager.LayoutParams物件,然後進行設定我們的動畫即可。
二、工具類的實現
/** * Created by Iflytek_dsw on 2017/7/4. */ public class ToastManager { private Toast toast; private Context context; private static ToastManager instance; private ToastManager(Context context){ this.context = context; toast = new Toast(context); } /** * 構造ToastManager物件 * @param context 上下文物件 * @return */ public static ToastManager getInstance(Context context) { if(instance == null){ instance = new ToastManager(context); } return instance; } /** * 自定義View和顯示位置的Toast * @param view Toast的View檢視 * @param gravity Toast的顯示位置 * @param xOffset Toast在x方向上偏移量,x大於0往右,x小於0往左 * @param yOffset Toast在y方向上偏移量,y值大於0往上,小於0往下 */ public void makeToastSelfView(View view, int gravity,int xOffset, int yOffset){ if(toast == null){ toast = new Toast(context); } toast.setView(view); toast.setGravity(gravity, xOffset, yOffset); toast.setDuration(Toast.LENGTH_SHORT); toast.show(); } /** * 構造帶有動畫的Toast * @param tText 提示的文字 * @param animationID style封裝的動畫資源id */ public void makeToastSelfAnimation(String tText,int animationID){ toast = Toast.makeText(context, tText, Toast.LENGTH_SHORT); try { Field mTNField = toast.getClass().getDeclaredField("mTN"); mTNField.setAccessible(true); Object mTNObject = mTNField.get(toast); Class tnClass = mTNObject.getClass(); Field paramsField = tnClass.getDeclaredField("mParams"); /**由於WindowManager.LayoutParams mParams的許可權是private*/ paramsField.setAccessible(true); WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) paramsField.get(mTNObject); layoutParams.windowAnimations = animationID; } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } toast.show(); } /** * 設定自定義View和Animation * @param view 自定義View * @param animationID 動畫資源id */ public void makeToastSelfViewAnim(View view, int animationID){ if(toast == null){ toast = new Toast(context); } toast.setView(view); try { Field mTNField = toast.getClass().getDeclaredField("mTN"); mTNField.setAccessible(true); Object mTNObject = mTNField.get(toast); Class tnClass = mTNObject.getClass(); Field paramsField = tnClass.getDeclaredField("mParams"); /**由於WindowManager.LayoutParams mParams的許可權是private*/ paramsField.setAccessible(true); WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) paramsField.get(mTNObject); layoutParams.windowAnimations = animationID; } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } toast.show(); } }
三、體驗Sample
1、自定義Toast的layout佈局
首先我們自定義一個Toast的檢視layout佈局。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="wrap_content" android:gravity="center_vertical" android:background="#000000" android:padding="10dp" android:layout_height="wrap_content"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/dicus"/> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:text="發表評論+10松果" android:textColor="#FFFFFF"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:text="檢視" android:textColor="#E8C84A"/> </LinearLayout>
2、自定義實現動畫
1、新建anim資料夾,用於儲存我們的enter和out動畫。
enter
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="0" android:toXScale="1" android:pivotX="50%" android:pivotY="50%" android:fromYScale="1" android:toYScale="1" android:duration="1000"> </scale>
out
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:fromXScale="1" android:toXScale="0" android:pivotX="50%" android:pivotY="50%" android:fromYScale="1" android:toYScale="1" android:duration="1000" /> </set>
style樣式
<style name="MyToast" parent="Base.Animation.AppCompat.Dialog"> <item name="android:windowEnterAnimation">@anim/enter</item> <item name="android:windowExitAnimation">@anim/out</item> </style>
3、呼叫工具類實現
public class MainActivity extends AppCompatActivity { private Button btn_toast; private View toastView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LayoutInflater inflater = LayoutInflater.from(MainActivity.this); toastView = inflater.inflate(R.layout.toastlayout, null); btn_toast = (Button) findViewById(R.id.btn_toast); btn_toast.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ToastManager.getInstance(getApplicationContext()). makeToastSelfViewAnim(toastView,R.style.MyToast); } }); } }
效果圖: