Android仿IOS的AssistiveTouch的控件EasyTouch实现

来源:互联网 发布:朗文和牛津 知乎 编辑:程序博客网 时间:2024/05/22 01:35

概述:

  之前我听到过一则新闻,就是说Ipone中的AssistiveTouch的设计初衷是给残疾人使用的。而这一功能在亚洲(中国)的使用最为频繁。

  虽不知道这新闻的可靠性,但无庸置疑的是它的确给我们操作手机带来了很大的便捷。在这个设计之前,可能比较容易想到的就是建立快捷方式,而快捷方式的操作结果还是要去加载界面(有时可能是繁重的界面)。一旦走上了这条路,那距离快捷操作的方向可能就渐行渐远了。

  AssistiveTouch的设计的确很赞。Android也是值得拥有这一棒棒的功能,下面我就来简单说明一下在Android上要如何实现这一功能。


思路整理:

  一眼看到这样的功能,我们可能困惑的是在Android中要怎么在系统桌面的上方添加控件。是的,这是一个难点。从大小上,可能你想到了Dialog,不过Android中的Dialog可不能在系统的桌面上显示。那你可能又会说不是一种是针对Activity的Dialog主题的模式吗?是的,这样的确是解决了在系统桌面的上方弹出窗口了。可是,我们又要对控件进行随意拖拽,这一点可能对于Android而言并非易事。

  但是,Android中允许我们在WindowManager上添加View。Android中的窗口机制就是基于WindowManager实现的。WindowManager的作用就是添加View到屏幕,或是从屏幕中移除View。它是显示View的最底层。

  好了,的确是这样的。WindowManger就是实现的关键。下面就来实现它吧。

  不过还有一点需要注意,就我们的EasyTouchView是要基于一个常在的Context来创建,如果EasyTouchView基于了像Activity这样的短生命周期的Context创建,那么EasyTouchView就会很快随着Activity的暂停或是销毁而消失。


实现过程:

EasyTouchView:

[java] view plain copy
 print?
  1. package com.bumblebee.remindeasy.widgets;  
  2.   
  3. import java.util.Timer;  
  4. import java.util.TimerTask;  
  5.   
  6. import com.bumblebee.remindeasy.R;  
  7.   
  8. import android.content.Context;  
  9. import android.graphics.Color;  
  10. import android.graphics.drawable.BitmapDrawable;  
  11. import android.os.Handler;  
  12. import android.os.Message;  
  13. import android.view.Gravity;  
  14. import android.view.LayoutInflater;  
  15. import android.view.MotionEvent;  
  16. import android.view.View;  
  17. import android.view.WindowManager;  
  18. import android.view.WindowManager.LayoutParams;  
  19. import android.widget.Button;  
  20. import android.widget.ImageView;  
  21. import android.widget.PopupWindow;  
  22. import android.widget.Toast;  
  23.   
  24. public class EasyTouchView extends View {  
  25.     private Context mContext;  
  26.     private WindowManager mWManager;  
  27.     private WindowManager.LayoutParams mWMParams;  
  28.     private View mTouchView;  
  29.     private ImageView mIconImageView = null;  
  30.     private PopupWindow mPopuWin;  
  31.     private ServiceListener mSerLisrener;  
  32.     private View mSettingTable;  
  33.     private int mTag = 0;  
  34.     private int midX;  
  35.     private int midY;  
  36.     private int mOldOffsetX;  
  37.     private int mOldOffsetY;  
  38.   
  39.     private Toast mToast;  
  40.     private Timer mTimer = null;  
  41.     private TimerTask mTask = null;  
  42.   
  43.     public EasyTouchView(Context context, ServiceListener listener) {  
  44.         super(context);  
  45.         mContext = context;  
  46.         mSerLisrener = listener;  
  47.     }  
  48.   
  49.     public void initTouchViewEvent() {  
  50.         initEasyTouchViewEvent();  
  51.           
  52.         initSettingTableView();  
  53.     }  
  54.       
  55.     private void initEasyTouchViewEvent() {  
  56.         // 设置载入view WindowManager参数  
  57.         mWManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);  
  58.         midX = mWManager.getDefaultDisplay().getWidth() / 2 - 25;  
  59.         midY = mWManager.getDefaultDisplay().getHeight() / 2 - 44;  
  60.         mTouchView = LayoutInflater.from(mContext).inflate(R.layout.easy_touch_view, null);  
  61.         mIconImageView = (ImageView) mTouchView.findViewById(R.id.easy_touch_view_imageview);  
  62.         mTouchView.setBackgroundColor(Color.TRANSPARENT);  
  63.           
  64.         mTouchView.setOnTouchListener(mTouchListener);  
  65.         WindowManager wm = mWManager;  
  66.         WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();  
  67.         mWMParams = wmParams;  
  68.         wmParams.type = 2003// 这里的2002表示系统级窗口,你也可以试试2003。  
  69.         wmParams.flags = 40// 设置桌面可控  
  70.         wmParams.width = 100;  
  71.         wmParams.height = 100;  
  72.         wmParams.format = -3// 透明  
  73.         wm.addView(mTouchView, wmParams);  
  74.     }  
  75.       
  76.     private void initSettingTableView() {  
  77.         mSettingTable = LayoutInflater.from(mContext).inflate(R.layout.show_setting_table, null);  
  78.         Button commonUseButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_common_use_button);  
  79.         Button screenLockButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_screen_lock_button);  
  80.         Button notificationButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_notification_button);  
  81.           
  82.         Button phoneButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_phone_button);  
  83.         Button pageButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_page_button);  
  84.         Button cameraButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_camera_button);  
  85.           
  86.         Button backButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_back_button);  
  87.         Button homeButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_home_button);  
  88.         Button exitTouchButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_exit_touch_button);  
  89.           
  90.         commonUseButton.setOnClickListener(mClickListener);  
  91.         screenLockButton.setOnClickListener(mClickListener);  
  92.         notificationButton.setOnClickListener(mClickListener);  
  93.           
  94.         phoneButton.setOnClickListener(mClickListener);  
  95.         pageButton.setOnClickListener(mClickListener);  
  96.         cameraButton.setOnClickListener(mClickListener);  
  97.           
  98.         backButton.setOnClickListener(mClickListener);  
  99.         homeButton.setOnClickListener(mClickListener);  
  100.         exitTouchButton.setOnClickListener(mClickListener);  
  101.     }  
  102.   
  103.     private OnClickListener mClickListener = new OnClickListener() {  
  104.         @Override  
  105.         public void onClick(View v) {  
  106.             switch (v.getId()) {  
  107.             case R.id.show_setting_table_item_common_use_button:  
  108.                 hideSettingTable("常用");  
  109.                 break;  
  110.             case R.id.show_setting_table_item_screen_lock_button:  
  111.                 hideSettingTable("锁屏");  
  112.                 break;  
  113.             case R.id.show_setting_table_item_notification_button:  
  114.                 hideSettingTable("通知");  
  115.                 break;  
  116.                   
  117.             case R.id.show_setting_table_item_phone_button:  
  118.                 hideSettingTable("电话");  
  119.                 break;  
  120.             case R.id.show_setting_table_item_page_button:  
  121.                 hideSettingTable("1");  
  122.                 break;  
  123.             case R.id.show_setting_table_item_camera_button:  
  124.                 hideSettingTable("相机");  
  125.                 break;  
  126.                   
  127.             case R.id.show_setting_table_item_back_button:  
  128.                 hideSettingTable("返回");  
  129.                 break;  
  130.             case R.id.show_setting_table_item_home_button:  
  131.                 hideSettingTable("主页");  
  132.                 break;  
  133.             case R.id.show_setting_table_item_exit_touch_button:  
  134.                 quitTouchView();  
  135.                 break;  
  136.             }  
  137.   
  138.         }  
  139.     };  
  140.       
  141.     private void quitTouchView() {  
  142.         hideSettingTable("退出");  
  143.           
  144.         mWManager.removeView(mTouchView);  
  145.         mSerLisrener.OnCloseService(true);  
  146.           
  147.         clearTimerThead();  
  148.     }  
  149.       
  150.     private OnTouchListener mTouchListener = new OnTouchListener() {  
  151.         float lastX, lastY;  
  152.         int paramX, paramY;  
  153.   
  154.         public boolean onTouch(View v, MotionEvent event) {  
  155.             final int action = event.getAction();  
  156.   
  157.             float x = event.getRawX();  
  158.             float y = event.getRawY();  
  159.   
  160.             if (mTag == 0) {  
  161.                 mOldOffsetX = mWMParams.x; // 偏移量  
  162.                 mOldOffsetY = mWMParams.y; // 偏移量  
  163.             }  
  164.   
  165.             switch (action) {  
  166.             case MotionEvent.ACTION_DOWN:  
  167.                 motionActionDownEvent(x, y);  
  168.                 break;  
  169.                   
  170.             case MotionEvent.ACTION_MOVE:  
  171.                 motionActionMoveEvent(x, y);  
  172.                 break;  
  173.                   
  174.             case MotionEvent.ACTION_UP:  
  175.                 motionActionUpEvent(x, y);  
  176.                 break;  
  177.   
  178.             default:  
  179.                 break;  
  180.             }  
  181.               
  182.             return true;  
  183.         }  
  184.           
  185.         private void motionActionDownEvent(float x, float y) {  
  186.             lastX = x;  
  187.             lastY = y;  
  188.             paramX = mWMParams.x;  
  189.             paramY = mWMParams.y;  
  190.         }  
  191.           
  192.         private void motionActionMoveEvent(float x, float y) {  
  193.             int dx = (int) (x - lastX);  
  194.             int dy = (int) (y - lastY);  
  195.             mWMParams.x = paramX + dx;  
  196.             mWMParams.y = paramY + dy;  
  197.             mTag = 1;  
  198.               
  199.             // 更新悬浮窗位置  
  200.             mWManager.updateViewLayout(mTouchView, mWMParams);  
  201.         }  
  202.           
  203.         private void motionActionUpEvent(float x, float y) {  
  204.             int newOffsetX = mWMParams.x;  
  205.             int newOffsetY = mWMParams.y;  
  206.             if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) {  
  207.                 mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
  208.                 mPopuWin.setTouchInterceptor(new OnTouchListener() {  
  209.   
  210.                     public boolean onTouch(View v, MotionEvent event) {  
  211.                         if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {  
  212.                             hideSettingTable();  
  213.                             return true;  
  214.                         }  
  215.                         return false;  
  216.                     }  
  217.                 });  
  218.                   
  219.                 mPopuWin.setBackgroundDrawable(new BitmapDrawable());  
  220.                 mPopuWin.setTouchable(true);  
  221.                 mPopuWin.setFocusable(true);  
  222.                 mPopuWin.setOutsideTouchable(true);  
  223.                 mPopuWin.setContentView(mSettingTable);  
  224.                   
  225.                 if (Math.abs(mOldOffsetX) > midX) {  
  226.                     if (mOldOffsetX > 0) {  
  227.                         mOldOffsetX = midX;  
  228.                     } else {  
  229.                         mOldOffsetX = -midX;  
  230.                     }  
  231.                 }  
  232.                   
  233.                 if (Math.abs(mOldOffsetY) > midY) {  
  234.                     if (mOldOffsetY > 0) {  
  235.                         mOldOffsetY = midY;  
  236.                     } else {  
  237.                         mOldOffsetY = -midY;  
  238.                     }  
  239.                 }  
  240.                   
  241.                 mPopuWin.setAnimationStyle(R.style.AnimationPreview);  
  242.                 mPopuWin.setFocusable(true);  
  243.                 mPopuWin.update();  
  244.                 mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY);  
  245.                   
  246.                 if (mTimer == null) {  
  247.                     catchSettingTableDismiss();  
  248.                 }  
  249.             } else {  
  250.                 mTag = 0;  
  251.             }  
  252.         }  
  253.     };  
  254.       
  255.     private void catchSettingTableDismiss() {  
  256.         mTimer = new Timer();  
  257.         mTask = new TimerTask() {  
  258.               
  259.             @Override  
  260.             public void run() {  
  261.                 if (mPopuWin == null || !mPopuWin.isShowing()) {  
  262.                     handler.sendEmptyMessage(0x0);  
  263.                 } else {  
  264.                     handler.sendEmptyMessage(0x1);  
  265.                 }  
  266.             }  
  267.         };  
  268.           
  269.         mTimer.schedule(mTask, 0100);  
  270.     }  
  271.       
  272.     private void clearTimerThead() {  
  273.         if (mTask != null) {  
  274.             mTask.cancel();  
  275.             mTask = null;  
  276.         }  
  277.           
  278.         if (mTimer != null) {  
  279.             mTimer.cancel();  
  280.             mTimer = null;  
  281.         }  
  282.     }  
  283.   
  284.     Handler handler = new Handler() {  
  285.         public void handleMessage(Message msg) {  
  286.             if (msg.what == 0x0) {  
  287.                 mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.touch_ic));  
  288.             } else if (msg.what == 0x1) {  
  289.                 mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));  
  290.             }  
  291.         };  
  292.     };  
  293.       
  294.     public void showToast(Context context, String text) {  
  295.         if (mToast == null) {  
  296.             mToast = Toast.makeText(context, text, Toast.LENGTH_SHORT);  
  297.         } else {  
  298.             mToast.setText(text);  
  299.             mToast.setDuration(Toast.LENGTH_SHORT);  
  300.         }  
  301.         mToast.show();  
  302.     }  
  303.   
  304.     private void hideSettingTable(String content) {  
  305.         hideSettingTable();  
  306.         showToast(mContext, content);  
  307.     }  
  308.       
  309.     private void hideSettingTable() {  
  310.         if (null != mPopuWin) {  
  311.             mPopuWin.dismiss();  
  312.         }  
  313.     }  
  314.   
  315.     public interface ServiceListener {  
  316.         public void OnCloseService(boolean isClose);  
  317.     }  
  318. }  

AuxiliaryService:

[java] view plain copy
 print?
  1. public class AuxiliaryService extends Service implements ServiceListener {  
  2.     private Intent mIntent;  
  3.   
  4.     @Override  
  5.     public IBinder onBind(Intent intent) {  
  6.         return null;  
  7.     }  
  8.   
  9.     public void onCreate() {  
  10.         super.onCreate();  
  11.         new EasyTouchView(thisthis).initTouchViewEvent();  
  12.     }  
  13.   
  14.     @Override  
  15.     public int onStartCommand(Intent intent, int flags, int startId) {  
  16.         mIntent = intent;  
  17.         return super.onStartCommand(intent, flags, startId);  
  18.     }  
  19.   
  20.     @Override  
  21.     public void OnCloseService(boolean isClose) {  
  22.         stopService(mIntent);  
  23.     }  
  24. }  


  这里有一点需要注意一下。大家可以通过上面的代码看出,我们启动EasyTouchView是通过Service来启动的。一般的EasyTouch都会提供一个锁屏的功能。要使用一键锁屏就需要激活设备管理器,就要去跳转到系统的一些界面,而这些界面的启动不可以是基于Service的,需要基于Activity来做处理。基于Service启动的过程是闪烁一下后就消失了。

  这里我们可以在Service中启动一个我们自己的Activity,然后在这个Activity中启动这个设置设备管理器的界面。


代码如下:

[java] view plain copy
 print?
  1. public class AuxiliaryActivity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  7.         lockScreen();  
  8.     }  
  9.       
  10.     private void lockScreen() {  
  11.         DevicePolicyManager mDevicePolicyManager;  
  12.         ComponentName mComponentName;  
  13.           
  14.         mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);  
  15.         mComponentName = new ComponentName(this, LockReceiver.class);  
  16.   
  17.         // 判断是否有权限  
  18.         if (mDevicePolicyManager.isAdminActive(mComponentName)) {  
  19.             mDevicePolicyManager.lockNow();  
  20.             finish();  
  21.         } else {  
  22.             activeManager(mComponentName);  
  23.         }  
  24.     }  
  25.       
  26.     /** 
  27.      * 激活设备管理器获取权限 
  28.      */  
  29.     private void activeManager(ComponentName componentName) {  
  30.         Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);  
  31.         intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);  
  32.         intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "One key lock the screen");  
  33.         startActivity(intent);  
  34.         finish();  
  35.     }  
  36. }  


效果图:


TouchView


ShowTableView


代码下载:

http://download.csdn.NET/detail/u013761665/8894583

0 0
原创粉丝点击