Android悬浮球及全局返回功能的实现示例

先来一发效果图:

前面是返回效果,最后一下是实现home键的效果

前言

很久之前,就想做一个悬浮球了,毕竟是程序猿嘛,有想要的功能的时候总是想自己尝试一下,于是兴致勃勃的找了好久,都没有找到全局返回功能该如何实现!最后也无疾而终,就在前两天,又想到了这个功能,今天硬是花了好久,从一个同类软件获得了一点灵感,有一个关键的地方被我察觉到了,顺着这个思路找了很多资料,便实现了全局返回功能。

思路

废话不多说了,说说主要的思路吧,关键的一个类就是:AccessibilityService官方文档地址,这个类与手机里面的一个功能密切相关:辅助功能-服务。官方文档来看,这个功能是为了方便有障碍的人士更好的使用手机。我们这里就不展开介绍里面的API了,为了实现我们的全局返回功能,我们只需要使用一个函数即可:boolean performGlobalAction (int action),官方解释如下:

Performs a global action. Such an action can be performed at any moment regardless of the current application or user location in that application. For example going back, going home, opening recents, etc.

翻译过来就是:

执行全局动作。无论该应用程序中的当前应用程序或用户位置如何,都可以随时执行此类操作。例如执行HOME键,BACK键,任务键等

其中可以传入的参数有四个:

  1. GLOBAL_ACTION_BACK
  2. GLOBAL_ACTION_HOME
  3. GLOBAL_ACTION_NOTIFICATIONS
  4. GLOBAL_ACTION_RECENTS

从字面就可以理解,我们返回功能需要的就是GLOBAL_ACTION_BACK。所以我们只需要开启服务,调用函数就可以实现全局返回功能了。

编写代码

最重要的服务类

我们要新建一个类去继承自上面那个类:

public class MyAccessibilityService extends AccessibilityService {
 public static final int BACK = 1;
 public static final int HOME = 2;
 private static final String TAG = "ICE";

 @Override
 public void onCreate() {
 super.onCreate();
 //使用EventBus代替广播
 EventBus.getDefault().register(this);
 }

 @Override
 public void onAccessibilityEvent(AccessibilityEvent event) { }

 @Override
 public void onInterrupt() {}

 @Subscribe
 public void onReceive(Integer action){
 switch (action){
 case BACK:
 performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
 break;
 case HOME:
 performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
 break;
 }
 }

}

上面的onReceive方法是我们使用EventBus的订阅函数,当其他地方发送消息之后,我们这里就可以收到,然后判断是要执行后退还是回到桌面。

然后我们在AndroiManifest里面要注册我们的服务,但是这个注册的比较特殊:

首先加入权限声明:

代码如下:

<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>

然后注册服务:

<service
 android:name=".MyAccessibilityService"
 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
 <intent-filter>
 <action android:name="android.accessibilityservice.AccessibilityService"/>
 </intent-filter>
 <meta-data
 android:name="android.accessibilityservice"
 android:resource="@xml/accessibilityservice"/>
</service>

其中resource中的内容我们要在xml包中声明,首先新建一个xml包,如下:

然后新建一个accessibilityservice.xml文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:description="@string/start_floatingBall"/>

<!--我这里写的是开启悬浮球功能-->

里面还可以设置许多属性,在这里就不介绍了,有兴趣的可以在官方文档里面查看。

到时候description的显示效果如下:

好了,到现在就已经完成了AccessibilityService服务的创建与注册了,接下来在Activity中启动服务就可以了: startService(new Intent(this,MyAccessibilityService.class));

使用EventBus传递事件即可实现返回:EventBus.getDefault().post(MyAccessibilityService.BACK);

但是要打开服务才行,简单办法是直接调用Intent跳到设置界面:startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));

或者手动进入设置->辅助功能->服务->找到自己的app,然后开启服务即可。(不同的系统可能略有差异,小米就是在无障碍里面),界面如下:

悬浮球的简单实现

1.自定义一个View,画一个悬浮球:

public class FloatingView extends View {

 public int height = 150;
 public int width = 150;
 private Paint paint;

 public FloatingView(Context context){
 super(context);
 paint = new Paint();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 setMeasuredDimension(height,width);
 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 //画大圆
 paint.setStyle(Paint.Style.FILL);
 paint.setAntiAlias(true);
 paint.setColor(getResources().getColor(R.color.state_one));
 canvas.drawCircle(width/2,width/2,width/2,paint);
 //画小圆圈
 paint.setStyle(Paint.Style.STROKE);
 paint.setColor(Color.WHITE);
 canvas.drawCircle(width/2,width/2, (float) (width*1.0/4),paint);

 }

代码很简单,是画了一个大圆,然后一个小点的圆圈。

接下来,把这个view展示在桌面:

public class ViewManager {
 FloatingView floatBall;
 WindowManager windowManager;
 public static ViewManager manager;
 Context context;
 private WindowManager.LayoutParams floatBallParams;

 private ViewManager(Context context) {
 this.context = context;
 }

 public static ViewManager getInstance(Context context) {
 if (manager == null) {
 manager = new ViewManager(context);
 }
 return manager;
 }
 public void showFloatBall() {
 floatBall = new FloatingView(context);
 windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
 if (floatBallParams == null) {
 floatBallParams = new WindowManager.LayoutParams();
 floatBallParams.width = floatBall.width;
 floatBallParams.height = floatBall.height;
 floatBallParams.gravity = Gravity.TOP | Gravity.LEFT;
 floatBallParams.type = WindowManager.LayoutParams.TYPE_TOAST;
 floatBallParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 floatBallParams.format = PixelFormat.RGBA_8888;
 }

 windowManager.addView(floatBall, floatBallParams);

 floatBall.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 EventBus.getDefault().post(MyAccessibilityService.BACK);
 Toast.makeText(context, "点击了悬浮球 执行后退操作", Toast.LENGTH_SHORT).show();
 }
 });

 floatBall.setOnLongClickListener(new View.OnLongClickListener() {
 @Override
 public boolean onLongClick(View v) {
 EventBus.getDefault().post(MyAccessibilityService.HOME);
 Toast.makeText(context, "长按了悬浮球 执行返回桌面", Toast.LENGTH_SHORT).show();
 return false;
 }
 });

 }

 public int getScreenWidth() {
 return windowManager.getDefaultDisplay().getWidth();
 }

}

为了简单起见,就没有贴上拖动悬浮窗的代码了,如有需要,可以在文章末尾查看源码。

上面代码把view加入到window中,并给view设置了点击事件,以及长按事件,向AccessibilityService传递消息,执行相应的事件。

要显示悬浮窗,要声明权限:

代码如下:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

然后手动开启权限!不然无法显示悬浮窗。

最后我们在Activity中开启我们自定义的悬浮窗即可:

ViewManager.getInstance(MainActivity.this).showFloatBall();

结束语

现在看来,实现一个全局返回功能真的非常简单,但是当初就真的找了非常久,怎么找,怎么试都没法实现这个功能,于是尝试着去学学别的悬浮窗的代码,但是没办法,加壳了,反编译后没法看。但是我注意到了一个细节,它要我打开服务才能使用悬浮窗的功能,所以就从这里下手,慢慢找到了实现全局返回的方法。

源码地址:https://github.com/CHNicelee/FloatingBall

demo下载地址:FloatingBall_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 实现按两次返回键退出程序(两种方法)

    Android 实现按两次返回键退出程序(两种方法) 第一种方法: // 是否退出程序 private static Boolean isExit = false; // 定时触发器 private static Timer tExit = null; 第二种方法: public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (isExit == false) {

  • Android 滑动返回Activity的实现代码

    Android 滑动返回Activity的实现代码 近来玩微信的时候偶然发现,向左滑动朋友圈竟然可以返回主页,故引起兴趣特研究 代码很简洁 package com.example.wyj.cainiaoshopping.activity; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import com.

  • Android 自定义返回按钮的实例详解

    Android 自定义返回按钮的实例详解 程序中我们有时候想让放回按钮按照自己的需求调整页面而不是单纯的按照系统返回上一级,这个问题很简单,重写 onKeyDown 方法即可. 下面方法,包含了 webview 中的返回上一页和普通 activity 的单击设置和双击退出程序. @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //如果我们用的是webview页面,想返回网页的上一页设置这里就可以了 if (key

  • Android悬浮按钮点击返回顶部FloatingActionButton

    先看一下Android悬浮按钮点击回到顶部的效果: FloatingActionButton是Design Support库中提供的一个控件,这个控件可以轻松实现悬浮按钮的效果 首先,要在项目中使用这个悬浮按钮就要先把design这个包导入项目 gradle中加入依赖 compile 'com.android.support:design:25.0.0' 接下来就是在xml中使用: 我这里是放置一个listView模拟返回顶部 <?xml version="1.0" encodi

  • Android标题栏中添加返回按钮功能

    标题栏中的返回按钮在实际使用中用的比较多,今天就来讲讲我在项目开发中的使用经历,话不多说,还是直接上源码,上源码是最给力的. 一. 编写自定义类 public class CustomTitle { private static Activity mActivity; public static void getCustomTitle(Activity activity, String title) { mActivity = activity; mActivity.requestWindowF

  • Android onKeyDown监听返回键无效的解决办法

     Android onKeyDown监听返回键无效的解决办法 当我们的Activity继承了TabActivity,在该类中重写onKeyDown是监听不到返回键的, 具体解决方法如下: 重写dispatchKeyEvent /** * 退出 */ @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAc

  • ionic2如何处理android硬件返回按钮

    问题 注册安卓硬件返回按钮事件是必须的,因为用户不小心点击了返回按钮就退出app体验很不好,所以有几种方法: 1.实现按返回键最小化应用(最小化应用需要装cordova-plugin-appminimize插件,使用window['AppMinimize'].minimize();). 2.要么请求用户确认(添加一个Confirmation Alerts). 3.按一下提示,按两下退出(加一个方法用toast提醒). 这里用第三种展示. 解决 在app.html中,添加#myNav,在app.c

  • Android悬浮球及全局返回功能的实现示例

    先来一发效果图: 前面是返回效果,最后一下是实现home键的效果 前言 很久之前,就想做一个悬浮球了,毕竟是程序猿嘛,有想要的功能的时候总是想自己尝试一下,于是兴致勃勃的找了好久,都没有找到全局返回功能该如何实现!最后也无疾而终,就在前两天,又想到了这个功能,今天硬是花了好久,从一个同类软件获得了一点灵感,有一个关键的地方被我察觉到了,顺着这个思路找了很多资料,便实现了全局返回功能. 思路 废话不多说了,说说主要的思路吧,关键的一个类就是:AccessibilityService,官方文档地址,

  • Android仿微信右滑返回功能的实例代码

    先上效果图,如下: 先分析一下功能的主要技术点,右滑即手势判断,当滑到一直距离时才执行返回,并且手指按下的位置是在屏幕的最左边(这个也是有一定范围的),  这些可以实现onTouchEvent来实现. 接着就是返回时,有滑动效果,很显然这个是Acitivty切换动画实现的.好啦,分析完了就开干.下面上代码: @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case Mot

  • Android 选择相册照片并返回功能的实现代码

    首先由于进行读写操作,要在 AndroidManifest.xml中声明权限: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 调用系统相册: private static final in

  • Android使用Walle实现多渠道打包功能的实现示例

    目录 介绍 使用 对应的属性: 可使用以下变量: 介绍 Walle(瓦力)是Android Signature V2 Scheme签名下的新一代渠道包打包神器. 瓦力通过在Apk中的APK Signature Block区块添加自定义的渠道信息来生成渠道包,从而提高了渠道包生成效率,可以作为单机工具来使用,也可以部署在HTTP服务器上来实时处理渠道包Apk的升级网络请求. 使用 使用Walle生成多渠道的速度是很快的,原来的项目打一个包就需要两分钟多,每次发布打7个包需要十几分钟.用了Walle

  • Android开发之ViewFlipper自动播放图片功能实现方法示例

    本文实例讲述了Android开发之ViewFlipper自动播放图片功能实现方法.分享给大家供大家参考,具体如下: 简介: 1.ViewFlipper继承了ViewAnimator 可以调用addView()添加组件 2.ViewAnimator与AdapterViewFlipper类似,区别在于 : AdapterViewFlipper可以通过Adapter直接添加多个view,而ViewAnimator 需要通过调用addView()方法添加View 效果呈现: 有此实例可以看出 ViewF

  • Android左滑返回功能的实现示例代码

    前几天用了个app发现左滑可以返回首页,发现这个功能很炫酷,就想着自己能不能做出来,于是研究了一下 原理 将activity的背景设置为透明同时设置切换动画 手指滑动的时候,根View跟着滑动,滑倒一定的距离就finish掉. 原理很简单,但实现起来可能有些坑.这里记录一下.源码参考 处理onInterceptTouchEvent 事件拦截要处理一件事情:确定这次触摸事件是不是应该交给SlideFinishLayout的onTouchEvent处理. override fun onInterce

  • Android仿iOS实现侧滑返回功能(类似微信)

    我们都知道侧滑返回操作是 iOS 里面比较常见的功能,一般是手指在靠近手机屏幕左边缘向右滑动就可以关闭当前的界面,iOS 系统提供了这样的 API,但是 Android 怎么实现呢?网上找了许多方法,比较了一下,个人觉得还是这个比较方便也容易理解, 先上个效果再说: 原理 Activity 本身是不可以滑动的,但是我们可以制造一个正在滑动 Activity 的假象,使得看起来这个 Activity 正在被手指滑动.其原理其实很简单,我们滑动的其实是 Activity 里面的可见View元素,而我

  • iOS push侧滑返回功能实现方法

    本文实例为大家分享了iOS push侧滑返回功能的具体代码,供大家参考,具体内容如下 开启iOS自带的push的侧滑返回功能(只有左侧边缘地带响应侧滑返回,并不是全局响应): - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { [self.navigationContr

  • Android 实现可任意拖动的悬浮窗功能(类似悬浮球)

    最近开发项目中,有个在屏幕上任意拖动的悬浮窗功能,其实就是利用 WindowManager的api来完成这个需求,具体的实现的功能如下: 1.自定义view import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.util.Log; import android.util.TypedValu

随机推荐