zoukankan      html  css  js  c++  java
  • Android仿IOS的AssistiveTouch的控件EasyTouch实现

    概述:

      之前我听到过一则新闻,就是说Ipone中的AssistiveTouch的设计初衷是给残疾人使用的。

    而这一功能在亚洲(中国)的使用最为频繁。

      虽不知道这新闻的可靠性,但无庸置疑的是它的确给我们操作手机带来了非常大的便捷。在这个设计之前。可能比較easy想到的就是建立快捷方式。而快捷方式的操作结果还是要去载入界面(有时可能是繁重的界面)。

    一旦走上了这条路。那距离快捷操作的方向可能就渐行渐远了。

      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:

    package com.bumblebee.remindeasy.widgets;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import com.bumblebee.remindeasy.R;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.graphics.drawable.BitmapDrawable;
    import android.os.Handler;
    import android.os.Message;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    import android.view.WindowManager.LayoutParams;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.PopupWindow;
    import android.widget.Toast;
    
    public class EasyTouchView extends View {
        private Context mContext;
        private WindowManager mWManager;
        private WindowManager.LayoutParams mWMParams;
        private View mTouchView;
        private ImageView mIconImageView = null;
        private PopupWindow mPopuWin;
        private ServiceListener mSerLisrener;
        private View mSettingTable;
        private int mTag = 0;
        private int midX;
        private int midY;
        private int mOldOffsetX;
        private int mOldOffsetY;
    
        private Toast mToast;
        private Timer mTimer = null;
        private TimerTask mTask = null;
    
        public EasyTouchView(Context context, ServiceListener listener) {
            super(context);
            mContext = context;
            mSerLisrener = listener;
        }
    
        public void initTouchViewEvent() {
            initEasyTouchViewEvent();
            
            initSettingTableView();
        }
        
        private void initEasyTouchViewEvent() {
            // 设置加载view WindowManager參数
            mWManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            midX = mWManager.getDefaultDisplay().getWidth() / 2 - 25;
            midY = mWManager.getDefaultDisplay().getHeight() / 2 - 44;
            mTouchView = LayoutInflater.from(mContext).inflate(R.layout.easy_touch_view, null);
            mIconImageView = (ImageView) mTouchView.findViewById(R.id.easy_touch_view_imageview);
            mTouchView.setBackgroundColor(Color.TRANSPARENT);
            
            mTouchView.setOnTouchListener(mTouchListener);
            WindowManager wm = mWManager;
            WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
            mWMParams = wmParams;
            wmParams.type = 2003; // 这里的2002表示系统级窗体。你也能够试试2003。
            wmParams.flags = 40; // 设置桌面可控
            wmParams.width = 100;
            wmParams.height = 100;
            wmParams.format = -3; // 透明
            wm.addView(mTouchView, wmParams);
        }
        
        private void initSettingTableView() {
            mSettingTable = LayoutInflater.from(mContext).inflate(R.layout.show_setting_table, null);
            Button commonUseButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_common_use_button);
            Button screenLockButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_screen_lock_button);
            Button notificationButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_notification_button);
            
            Button phoneButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_phone_button);
            Button pageButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_page_button);
            Button cameraButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_camera_button);
            
            Button backButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_back_button);
            Button homeButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_home_button);
            Button exitTouchButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_exit_touch_button);
            
            commonUseButton.setOnClickListener(mClickListener);
            screenLockButton.setOnClickListener(mClickListener);
            notificationButton.setOnClickListener(mClickListener);
            
            phoneButton.setOnClickListener(mClickListener);
            pageButton.setOnClickListener(mClickListener);
            cameraButton.setOnClickListener(mClickListener);
            
            backButton.setOnClickListener(mClickListener);
            homeButton.setOnClickListener(mClickListener);
            exitTouchButton.setOnClickListener(mClickListener);
        }
    
        private OnClickListener mClickListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                case R.id.show_setting_table_item_common_use_button:
                    hideSettingTable("经常使用");
                    break;
                case R.id.show_setting_table_item_screen_lock_button:
                    hideSettingTable("锁屏");
                    break;
                case R.id.show_setting_table_item_notification_button:
                    hideSettingTable("通知");
                    break;
                    
                case R.id.show_setting_table_item_phone_button:
                    hideSettingTable("电话");
                    break;
                case R.id.show_setting_table_item_page_button:
                    hideSettingTable("1");
                    break;
                case R.id.show_setting_table_item_camera_button:
                    hideSettingTable("相机");
                    break;
                    
                case R.id.show_setting_table_item_back_button:
                    hideSettingTable("返回");
                    break;
                case R.id.show_setting_table_item_home_button:
                    hideSettingTable("主页");
                    break;
                case R.id.show_setting_table_item_exit_touch_button:
                    quitTouchView();
                    break;
                }
    
            }
        };
        
        private void quitTouchView() {
            hideSettingTable("退出");
            
            mWManager.removeView(mTouchView);
            mSerLisrener.OnCloseService(true);
            
            clearTimerThead();
        }
        
        private OnTouchListener mTouchListener = new OnTouchListener() {
            float lastX, lastY;
            int paramX, paramY;
    
            public boolean onTouch(View v, MotionEvent event) {
                final int action = event.getAction();
    
                float x = event.getRawX();
                float y = event.getRawY();
    
                if (mTag == 0) {
                    mOldOffsetX = mWMParams.x; // 偏移量
                    mOldOffsetY = mWMParams.y; // 偏移量
                }
    
                switch (action) {
                case MotionEvent.ACTION_DOWN:
                    motionActionDownEvent(x, y);
                    break;
                    
                case MotionEvent.ACTION_MOVE:
                    motionActionMoveEvent(x, y);
                    break;
                    
                case MotionEvent.ACTION_UP:
                    motionActionUpEvent(x, y);
                    break;
    
                default:
                    break;
                }
                
                return true;
            }
            
            private void motionActionDownEvent(float x, float y) {
                lastX = x;
                lastY = y;
                paramX = mWMParams.x;
                paramY = mWMParams.y;
            }
            
            private void motionActionMoveEvent(float x, float y) {
                int dx = (int) (x - lastX);
                int dy = (int) (y - lastY);
                mWMParams.x = paramX + dx;
                mWMParams.y = paramY + dy;
                mTag = 1;
                
                // 更新悬浮窗位置
                mWManager.updateViewLayout(mTouchView, mWMParams);
            }
            
            private void motionActionUpEvent(float x, float y) {
                int newOffsetX = mWMParams.x;
                int newOffsetY = mWMParams.y;
                if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) {
                    mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                    mPopuWin.setTouchInterceptor(new OnTouchListener() {
    
                        public boolean onTouch(View v, MotionEvent event) {
                            if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                                hideSettingTable();
                                return true;
                            }
                            return false;
                        }
                    });
                    
                    mPopuWin.setBackgroundDrawable(new BitmapDrawable());
                    mPopuWin.setTouchable(true);
                    mPopuWin.setFocusable(true);
                    mPopuWin.setOutsideTouchable(true);
                    mPopuWin.setContentView(mSettingTable);
                    
                    if (Math.abs(mOldOffsetX) > midX) {
                        if (mOldOffsetX > 0) {
                            mOldOffsetX = midX;
                        } else {
                            mOldOffsetX = -midX;
                        }
                    }
                    
                    if (Math.abs(mOldOffsetY) > midY) {
                        if (mOldOffsetY > 0) {
                            mOldOffsetY = midY;
                        } else {
                            mOldOffsetY = -midY;
                        }
                    }
                    
                    mPopuWin.setAnimationStyle(R.style.AnimationPreview);
                    mPopuWin.setFocusable(true);
                    mPopuWin.update();
                    mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY);
                    
                    if (mTimer == null) {
                        catchSettingTableDismiss();
                    }
                } else {
                    mTag = 0;
                }
            }
        };
        
        private void catchSettingTableDismiss() {
            mTimer = new Timer();
            mTask = new TimerTask() {
                
                @Override
                public void run() {
                    if (mPopuWin == null || !mPopuWin.isShowing()) {
                        handler.sendEmptyMessage(0x0);
                    } else {
                        handler.sendEmptyMessage(0x1);
                    }
                }
            };
            
            mTimer.schedule(mTask, 0, 100);
        }
        
        private void clearTimerThead() {
            if (mTask != null) {
                mTask.cancel();
                mTask = null;
            }
            
            if (mTimer != null) {
                mTimer.cancel();
                mTimer = null;
            }
        }
    
        Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                if (msg.what == 0x0) {
                    mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.touch_ic));
                } else if (msg.what == 0x1) {
                    mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));
                }
            };
        };
        
        public void showToast(Context context, String text) {
            if (mToast == null) {
                mToast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
            } else {
                mToast.setText(text);
                mToast.setDuration(Toast.LENGTH_SHORT);
            }
            mToast.show();
        }
    
        private void hideSettingTable(String content) {
            hideSettingTable();
            showToast(mContext, content);
        }
        
        private void hideSettingTable() {
            if (null != mPopuWin) {
                mPopuWin.dismiss();
            }
        }
    
        public interface ServiceListener {
            public void OnCloseService(boolean isClose);
        }
    }
    

    AuxiliaryService:

    public class AuxiliaryService extends Service implements ServiceListener {
        private Intent mIntent;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        public void onCreate() {
            super.onCreate();
            new EasyTouchView(this, this).initTouchViewEvent();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            mIntent = intent;
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void OnCloseService(boolean isClose) {
            stopService(mIntent);
        }
    }


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

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


    代码例如以下:

    public class AuxiliaryActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            lockScreen();
        }
        
        private void lockScreen() {
            DevicePolicyManager mDevicePolicyManager;
            ComponentName mComponentName;
            
            mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
            mComponentName = new ComponentName(this, LockReceiver.class);
    
            // 推断是否有权限
            if (mDevicePolicyManager.isAdminActive(mComponentName)) {
                mDevicePolicyManager.lockNow();
                finish();
            } else {
                activeManager(mComponentName);
            }
        }
        
        /**
         * 激活设备管理器获取权限
         */
        private void activeManager(ComponentName componentName) {
            Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
            intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
            intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "One key lock the screen");
            startActivity(intent);
            finish();
        }
    }


    效果图:


    TouchView


    ShowTableView


    代码下载:

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

  • 相关阅读:
    String、StringBuffer、StringBuilder源码解读
    查询条件左边写入函数,导致无法命中索引
    【图形学手记】law of the unconscious statistician
    【图形学手记】蒙特卡洛方法相关笔记
    【图形学手记】抽样分布相关的数学笔记
    C++ lower_bound
    【图形学手记】Inverse Transform Sampling 逆转换抽样
    【Java学习笔记】LinkedList JDK1.6
    【疑难杂症】new Date() 造成的线程阻塞问题
    【疑难杂症】【Solved】maven-compiler-plugin 在 idea 下的问题
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6930292.html
Copyright © 2011-2022 走看看