概述:

之前我听到过一则新闻,就是说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:

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() {@Overridepublic 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() {@Overridepublic 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;@Overridepublic IBinder onBind(Intent intent) {return null;}public void onCreate() {super.onCreate();new EasyTouchView(this, this).initTouchViewEvent();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {mIntent = intent;return super.onStartCommand(intent, flags, startId);}@Overridepublic void OnCloseService(boolean isClose) {stopService(mIntent);}
}

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

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

代码如下:

public class AuxiliaryActivity extends Activity {@Overrideprotected 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

Android仿IOS的AssistiveTouch的控件EasyTouch实现相关推荐

  1. Android 仿微信语音录音小控件

    Android 仿微信语音录音小控件 前段时间一直在做IM聊天这方面的撸码工作,涉及到了很多小控件,有时间我会慢慢给大家分享一下我的小成果,希望大家一起学习,一起进步,今天来和大家来说一下Androi ...

  2. android裁剪控件,Android 仿抖音音频裁剪控件

    效果图 QQ图片20201126164657.jpg 功能要求:绘制音频效果,音乐播放后进度滚动,控件可拖动,拖动后获取新的起始时间 (后期会加入根据音乐各个时段分贝大小来动态显示音律线的长短) 控件 ...

  3. Android 类似Ios的时间滚轮控件

    之前项目使用的,参考了别人的一个demo,但是原文链接找不到了.... 先说如何使用: //参数1:上下文 //参数2:选中是的ResultHandler回调 //参数3:选择器最早时间 //参数4: ...

  4. Android 仿今日头条的视频播放控件(几行代码快速实现)

    前段时间由于项目需要用到类似于今日头条的视频播放器,实现在线播放,边缓存边播放,当然也可以播放本地文件,如下图: 这里我推荐大家使用的是jiecaovideoplayer开源库,这个库的播放引擎是ij ...

  5. android 按钮回弹效果,Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything: ...

  6. android 布局回弹,Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything: ...

  7. php支付密码控件,Android高仿微信支付密码输入控件实例代码

    这篇文章主要为大家详细介绍了Android高仿微信支付密码输入控件的具体实现代码,供大家参考,具体内容如下 像微信支付密码控件,在app中是一个多么司空见惯的功能.最近,项目需要这个功能,于是乎就实现 ...

  8. android rebound平移,Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

    Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout 前言 IOS 拖拽回弹给用户的体验不得不赞然后 Android 原生的 API 各种不支持, 于是乎出现的很多仿 IO ...

  9. android 仿ios动画效果代码,Android仿IOS上拉下拉弹性效果的实例代码

    用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好:Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果.先看效果,感觉有些时候还 ...

最新文章

  1. jQuery-切换2
  2. centos72安装mysql配置密码_MySQL数据库之170419、Centos7下完美安装并配置mysql5.6
  3. 收藏:发展之道:简单与专注
  4. 串口服务器的通讯模式
  5. linux非阻塞的socket发送数据出现EAGAIN错误的处理方法
  6. 【转】在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证
  7. MS3D model 的 Frame count
  8. Ajax学习笔记-Ajax的封装-8
  9. 用计算机弹歌曲fade,抖音短视频踢脚舞是什么歌 Faded歌曲分享
  10. CNN网络模型大总结【持续更新中...】
  11. Go标准库syscall调用dll
  12. 将Android项目发布到Jcenter
  13. 寻址方法有哪些-七种数据寻址-三种内存寻址
  14. 使用getUserMedia实现录像
  15. TAQ服务器npc多久自动交物资,怀旧服GZS故意拖延TAQ开门,手段无下限?玩家:杀NPC举报也没用!...
  16. 记Vue报错Custom elements in iteration require ‘v-bind:key‘ directives.“错误解决
  17. rrdtool 画图
  18. 蓝鸽集团c++开发工程师笔试题
  19. 【阿里云IoT+YF3300】14.阿里IoT Studio打造手机端APP
  20. 非单一产品采购项目招标文件中是否必须载明核心产品?

热门文章

  1. C++ Primer 5th笔记(chap 13 拷贝控制)阻止拷贝
  2. [密码学] 消息认证码构造方法
  3. React Axios的定义,以及使用方式
  4. python通过requirements.txt文件批量安装依赖包的实现步骤
  5. 【Flask项目】sqlalchemy原生sql查询,返回字典形式数据
  6. TF-A代码阅读: SP_EL3栈内存-cpu_data内存的介绍(cpu_context介绍)
  7. Web安全之XSS漏洞
  8. ajax返回不刷新页面,Jquery ajax不刷新页面提交action取得返回值
  9. C++字符串反转(C++11)
  10. 007 Android之Broadcast Receiver