[mobilesafe] 10_自定义Toast

Android 4.0

自定义Toast

一、查看Toast的源码1、系统Toast背景:toast_frame.9.png

2、Toast显示在window上
mWM = WindowManagerImpl.getDefault();
...
mWM.addView(mViewmParams);
Toast.java
public void handleShow() {
            if (localLOGV) Log.v(TAG"HANDLE SHOW: " + this + " mView=" + mView
                    + " mNextView=" + mNextView);
            if (mView != mNextView) {
                // remove the old view if necessary
                handleHide();  //显示之前,要将前面的给隐藏掉
                mView = mNextView;
                mWM = WindowManagerImpl.getDefault();
                final int gravity = mGravity;
                mParams.gravity = gravity;
                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
                    mParams.horizontalWeight = 1.0f;
                }
                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
                    mParams.verticalWeight = 1.0f;
                }
                mParams.x = mX;
                mParams.y = mY;
                mParams.verticalMargin = mVerticalMargin;
                mParams.horizontalMargin = mHorizontalMargin;
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG"REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
                }
                if (localLOGV) Log.v(TAG"ADD! " + mView + " in " + this);
                mWM.addView(mViewmParams); //添加布局到当前窗体上
                trySendAccessibilityEvent();
            }
        }
public void handleHide() {
            if (localLOGV) Log.v(TAG"HANDLE HIDE: " + this + " mView=" + mView);
            if (mView != null) {
                // note: checking parent() just to make sure the view has
                // been added...  i have seen cases where we get here when
                // the view isn't yet added, so let's try not to crash.
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG"REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
                }
                mView = null;
            }
        }
3、Toast就是将一个自定义的View对象加载到窗体上
注意:所有在代码中的单位都是像素pixel
二、自定义Toast 

步骤:
1)从系统源码Toasth中我们可以看到,Toast原理就是将一个自定义的View对象显示到界面上
2)然后在显示Toast的地方,自定义自己定义的View到界面上
3)为了Toast好看,我们需要自定义一个View对象-自定义布局修改默认的Toast,
4)
将该自定义的布局转成view对象,设置该布局到Toast,
5)参考金山卫士的归属地显示风格
1、代码创建显示Toast的TextView对象
a) 代码创建
/**
     * 3、弹出自定义的土司
     * @param phoneAddress 要弹出的土司
     */
    public void toastAddress(String phoneAddress) {
        
        //a) 得到窗体管理者
        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        // b) 设置要显示的view
        tv_toast = new TextView(getApplicationContext());
        tv_toast.setText(phoneAddress);
        tv_toast.setTextSize(20);
        tv_toast.setTextColor(Color.RED);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;// 高度包裹内容
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;// 宽度包裹内容
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 标记-不可获取焦点
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不可触摸
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;// 保持屏幕常亮度
        params.format = PixelFormat.TRANSLUCENT;// 透明
        params.type = WindowManager.LayoutParams.TYPE_TOAST;// 类型
        windowManager.addView(tv_toast, params);
    }
b)在电话处于空闲的状态时,移除该窗体的TextView对象
case TelephonyManager.CALL_STATE_IDLE:// 电话空闲,也就是电话挂断了,或者没接通
                if (windowManager != null) {
                    windowManager.removeView(tv_toast);// 在电话空闲的时候,将土司显示到窗体的内容给移除掉
                }
                break;
            }
2、使用xml布局文件来自定义toast显示的界面
和1中,使用代码创建一致,只是用一个布局文件而已
toast_info.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 18、土司弹出来的自定义界面 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/call_locate_green"
    android:gravity="center"
    android:orientation="horizontal" >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/toast_image"
        android:src="@drawable/ic_launcher" />
    <TextView
        android:id="@+id/tv_toast_info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/phone_locale"
        android:textColor="#ffffff"
        android:textSize="20sp" />
</LinearLayout>  
结果:
  

问题1:
Toast显示在所有的窗体上,不会消失,但第二次有电话拨打进来,又会在窗体上显示
 
应用场景:一键锁屏,在每一个窗体上都有一个图标,其实是一个。
问题2:
多个电话拨打进来的时候,后面的会将前面的覆盖掉
a) 用一个List集合保存
b) showAddress()返回该View