一、目标
实现自定义的Toast窗口在来电时可以自由移动至屏幕的任意位置,并保存该位置
二、代码实现
1、在“显示号码归属地”服务(ShowPhoneAddService)类中的自定义吐司(myToast)方法中,在窗口对象WindowManager.LayoutParams(params,该变量在后面的移动显示位置时需要用到,所以将其定义成服务类的成员变量)的便签(flag)属性里,需删除不可触摸属性(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE),在类型(type)属性里将其设置为具有电话优先级的类型( WindowManager.LayoutParams.TYPE_PRIORITY_PHONE,Toast类型对象在设计时就是不可触摸的),增加系统窗口弹出权限(SYSTEM_ALERT_WINDOW)(未增加该权限在运行时不会出现错误提示,只会出现权限被拒绝提示 permission denied for this window type);
params中相关属性代码:
1 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 将窗口标记为不获取焦点 2 // 窗口不可触摸的标记为WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 3 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;// 将窗口标记为保持屏幕开启状态 4 params.format = PixelFormat.TRANSLUCENT;// 窗口样式为半透明 5 params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;// 窗口类型为具有电话优先级的类型
2、通过View对象(view)的inflate()方法获取View对象后,通过View对象(View)的
setOnTouchListener(OnTouchListener l)方法为其设置触摸监听事件,参数OnTouchListener l通过new实例化OnTouchListener()对象监听器,并复写其中的onTouch(View v, MotionEvent event)方法,同时在OnTouchListener()中定义六个int类型的变量(取名startX,startY,newX,newY,dX,dY,分别作为手指触摸屏幕时的初始X轴坐标、Y轴坐标、移动后新的X轴坐标、新的Y轴坐标、X轴移动的距离、Y轴移动的距离)
3、在复写的onTouch(View v, MotionEvent event)方法中,通过switch...case...语句判断事件的动作(event.getAction()),
(1)当事件动作为手指按下屏幕时(MotionEvent.ACTION_DOWN),通过onTouch方法传入的移动事件MotionEvent对象(event)的getRawX()方法获取手指按下屏幕时Toast窗口的初始X轴坐标像素位置(注:此坐标轴的原点为屏幕左上角),同理获得Y轴的坐标;
(2)当事件动作为手指在屏幕上移动时(MotionEvent.ACTION_MOVE),
①通过MotionEvent对象(event)的getRawX()、getRawY()方法获取Toast窗口新的X轴、Y轴坐标像素位置,获取新的坐标轴位置和起始坐标轴位置,并将其与Toast窗口的x轴、Y轴位置相加后再赋值给Toast窗口的X轴.Y轴;
②通过判断窗口对象WindowManager.LayoutParams(params)的x轴、Y轴坐标位置,若其小于零(即Toast窗口到达屏幕左边缘或上边缘),则将其设为0;若其大于屏幕宽度与Toast窗口宽度的差值(即Toast窗口到达右边缘或底边缘),则将其设为该差值;
③通过窗口管理对象(wm)的updateViewLayout(View view, LayoutParams params)方法更新Toast窗口显示位置,参数view为已加载的View对象(view),params为窗口对象WindowManager.LayoutParams(params);
④通过event的getRawX()、getRawY()方法重新获取Toast窗口的坐标并赋值给初始的X轴、Y轴坐标(startX、startY);
(3)当事件动作为手指离开屏幕瞬间(MotionEvent.ACTION_UP)通过SharedPreferences对象(sp)的putInt()方法保存窗口对象WindowManager.LayoutParams(params)的x轴、y轴坐标。
(4)返回true,让父控件相应触摸事件;
为View对象设置触摸监听事件的代码:
1 view.setOnTouchListener(new OnTouchListener() { 2 int startX,startY,newX,newY,dX,dY; 3 4 @Override 5 public boolean onTouch(View v, MotionEvent event) { 6 switch (event.getAction()) { 7 case MotionEvent.ACTION_DOWN://手指触摸屏幕时 8 startX = (int) event.getRawX();//获取手指触摸屏幕时的初始X轴位置 9 startY = (int) event.getRawY();//获取手指触摸屏幕时的初始Y轴位置 10 break; 11 case MotionEvent.ACTION_MOVE://手指在屏幕上移动 12 newX = (int) event.getRawX(); 13 newY = (int) event.getRawY(); 14 dX = newX - startX; 15 dY = newY - startY; 16 params.x += dX; 17 params.y += dY; 18 //边界,当Toast到达左边界时其X轴坐标为0,当到达右边界时其y轴为屏幕宽度减去Toast宽度。 19 if(params.x<0){ 20 params.x = 0; 21 } 22 if(params.x>(wm.getDefaultDisplay().getWidth()-view.getWidth())){ 23 params.x = wm.getDefaultDisplay().getWidth()-view.getWidth(); 24 } 25 if(params.y<0){ 26 params.y = 0; 27 } 28 if(params.y>(wm.getDefaultDisplay().getHeight()-view.getHeight())){ 29 params.y = wm.getDefaultDisplay().getHeight()-view.getHeight(); 30 } 31 wm.updateViewLayout(view, params);//更新View对象布局 32 startX = (int) event.getRawX();//重新初始化手指触摸屏幕时的初始X轴位置 33 startY = (int) event.getRawY();//重新初始化手指触摸屏幕时的初始Y轴位置 34 break; 35 case MotionEvent.ACTION_UP://手指离开屏幕瞬间 36 //保存Toast的位置,再下次来电时根据上次移动的位置显示 37 Editor editor = sp.edit(); 38 editor.putInt("ToastX", params.x); 39 editor.putInt("ToastY", params.y); 40 editor.commit(); 41 break; 42 } 43 return false; 44 } 45 });
4、在设置Toast窗口显示位置(params.x、params.y)时,通过SharedPreferences对象(sp)的getInt()方法获取已经保存的显示位置。
从配置文件中获取已保存的显示位置代码;
1 params.x = sp.getInt("ToastX", 0);// 设置Toast窗口左边缘距屏幕窗口左边界的偏移量为50像素 2 params.y = sp.getInt("ToastY", 0);// 设置Toast窗口上边缘距屏幕窗口顶边界的偏移量为50像素