問題分析
開發中我們經常會在適配5.0以后的機型遇到各種各樣的問題,其中有一個不大不小的問題就是:Toast不顯示問題
其原因是:用戶使用android 5.0以上的系統在安裝APP時,將消息通知的權限關閉掉了。實際上用戶本意只是想關閉Notification,但是Toast的show方法中有調用INotificationManager這個類,而這個類在用戶關閉消息通知權限的同時被禁用了,所以我們的吐司無法顯示。
Toast.show()
效果圖
自定義Toast(上)與Toast(下)比對
問題解決
既然系統不允許我們調用Toast,那么我們就自立門戶——自己寫一個Toast出來。我們總體的思路是:在Activity的布局中添加View實現Toast的效果。
-
Toast背景shape定義
我們知道shape的背景是一個半透明黑色的圓角效果:
Toast
因此我們使用的是shape的corners和solid結點:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#99000000" />
<corners android:radius="8dp" />
</shape>
-
定義布局
布局中我們主要使用TextView控件,設置相應的邊距和背景即可,布局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mbContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="200dp"
android:gravity="bottom|center"
android:orientation="vertical"
android:paddingLeft="50dp"
android:paddingRight="50dp">
<LinearLayout android:id="@+id/toast_linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_toastutils_bg"
android:gravity="bottom|center"
android:orientation="vertical"
android:padding="8dp">
<TextView android:id="@+id/mbMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:layout_weight="1"
android:gravity="center"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
android:textSize="12sp"
android:textColor="#FFFFFFFF" />
</LinearLayout>
</LinearLayout>
- java代碼邏輯
自定義Toast的java代碼邏輯主要模仿系統Toast的makeText()、show()兩個方法,此外還需要reset()方法,實現Toast顯示過程中Activity切換時context也隨之切換,關鍵代碼如下:
makeText(Context context, String message, int HIDE_DELAY)方法:
public static ToastUtils makeText(Context context, String message,
int HIDE_DELAY) {
if (mInstance == null) {
mInstance = new ToastUtils(context);
} else {
// 考慮Activity切換時,Toast依然顯示
if (!mContext.getClass().getName().endsWith(context.getClass().getName())) {
mInstance = new ToastUtils(context);
}
}
if (HIDE_DELAY == LENGTH_LONG) {
mInstance.HIDE_DELAY = 2500;
} else {
mInstance.HIDE_DELAY = 1500;
}
mTextView.setText(message);
return mInstance;
}
makeText(Context context, int resId, int HIDE_DELAY)方法
public static ToastUtils makeText(Context context, int resId, int HIDE_DELAY) {
String mes = "";
try {
mes = context.getResources().getString(resId);
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
return makeText(context, mes, HIDE_DELAY);
}
show()方法
public void show() {
if (isShow) {
// 若已經顯示,則不再次顯示
return;
}
isShow = true;
// 顯示動畫
mFadeInAnimation = new AlphaAnimation(0.0f, 1.0f);
// 消失動畫
mFadeOutAnimation = new AlphaAnimation(1.0f, 0.0f);
mFadeOutAnimation.setDuration(ANIMATION_DURATION);
mFadeOutAnimation
.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 消失動畫后更改狀態為 未顯示
isShow = false;
}
@Override
public void onAnimationEnd(Animation animation) {
// 隱藏布局,不使用remove方法為防止多次創建多個布局
mContainer.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mContainer.setVisibility(View.VISIBLE);
mFadeInAnimation.setDuration(ANIMATION_DURATION);
mContainer.startAnimation(mFadeInAnimation);
mHandler.postDelayed(mHideRunnable, HIDE_DELAY);
}
-
方法調用
自定義Toast的使用與系統Toast類似,調用方法如下:
ToastUtils.makeText(context, "消息內容",ToastUtils.LENGTH_SHORT).show();
代碼鏈接
代碼已上傳Github,點擊這里查看詳細。