[mobilesafe] 04_一个可以自由移动的土司

Android 4.0

一个可以自由移动的土司

1、就是给Toast注册一个触摸事件
2、由于是Toast,且配置了params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不可触摸
3、params.type = WindowManager.LayoutParams.TYPE_TOAST;// 类型,本身就不可以被移动
所以要改类型:
public static final int TYPE_PRIORITY_PHONE FIRST_SYSTEM_WINDOW+7;//低级模拟器接电话,那两个接通和挂断的按钮,可以移动,位于所有窗体之上,所以需要权限。 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>  
4、更新界面时,不要layout(),而是用WindowManager中的updateViewLayout()来更新移动的位置
params.x += dX;
params.y += dY;
windowManager.updateViewLayout(view_toastparams); // params。toast在窗体上的参数
5、将移动后的位置,保存起来,下次还是在这个位置
case MotionEvent.ACTION_UP:
    Log.i(TAG"toast弹起了。。。");
    // 拨打电话时Toast移动后,记住移动后的位置,下次还是在这个位置。
    // TODO 记录最后的距离屏幕左边 和 上边位置 存到sp里面,这里获取不到值,这样可以
    params.gravity = Gravity.LEFT + Gravity.TOP;
    int left = params.x;
    int top = params.y;
    // int left = view_toast.getLeft();//这是获取不到值的
    // int top = view_toast.getTop();//这是获取不到值的
    Editor edit = sp.edit();
    edit.putInt("left", left);
    edit.putInt("top", top);
    edit.commit();
    break;
 核心代码:
/**
 * 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);*/
    view_toast = View.inflate(getApplicationContext(), R.layout.toast_info,null);
    int toastWhich = sp.getInt("toastWhich", 0);//选择的是哪一个边框样式
    view_toast.setBackgroundResource(bgs[toastWhich]);
    
    TextView tv_toast_info = (TextView) view_toast.findViewById(R.id.tv_toast_info);
    tv_toast_info.setText(phoneAddress);
    // d)为土司设置触摸事件,可以移动的土司
    view_toast.setOnTouchListener(new OnTouchListener() {
        private int startX;// toast触摸的起始x
        private int startY;// toast触摸的起始y
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG"toast被按下了。。。");
                // 1)获取起始位置
                startX = (int) event.getRawX();
                startY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG"toast移动了。。。");
                // 2)移动时,获取当前x和y的位置
                int newX = (int) event.getRawX();
                int newY = (int) event.getRawY();
                // 3)当前移动到的位置和起始点的距离
                int dX = newX - startX;
                int dY = newY - startY;
                // 4)更新toast的在界面的位置
                params.x += dX;
                params.y += dY;
                windowManager.updateViewLayout(view_toastparams);// params。toast在窗体上的参数
                // 5)重新更新起始位置
                startX = (int) event.getRawX();
                startY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG"toast弹起了。。。");
                // FIXME 移动后,记住移动后的位置,下次还是在这个位置。
                break;
            }
            return true;
        }
    });
    // c)
    params = new WindowManager.LayoutParams();
    // 设置拨打电话提示框显示的位置,根据之前设置的位置来显示
    params.gravity = Gravity.LEFT + Gravity.TOP;// 默认是Gravity.CENTER
    params.x = sp.getInt("left", 0);// 要和上面的Gravity.LEFT等一起使用,否则,会被忽略掉
    params.y = sp.getInt("top", 0);
    
    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;//类型,要想触摸移动,要下面的类型
    params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
    windowManager.addView(view_toastparams);
}