1、权限管理

直接看我另外一篇博客吧,传送门:

https://my.oschina.net/u/1462828/blog/1933162

2、Base类BaseSuspend


import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;import com.imxiaoyu.common.utils.entity.SizeEntity;public abstract class BaseSuspend {private Context context;private View view;private boolean isShowing = false;/*** UI*/private WindowManager.LayoutParams wmParams;//悬浮窗的布局/*** 变量*/private WindowManager mWindowManager;//创建浮动窗口设置布局参数的对象/*** 接口*/private OnSuspendDismissListener onSuspendDismissListener;public BaseSuspend(Context context) {this.context = context;view = LayoutInflater.from(context).inflate(getLayoutId(), null);init();initView();onCreateSuspension();}public void init() {if (mWindowManager == null) {mWindowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);}wmParams = getParams();//设置好悬浮窗的参数// 悬浮窗默认显示以左上角为起始坐标wmParams.gravity = Gravity.LEFT | Gravity.TOP;}/*** 布局文件id,这里是用不到的,但还是建议填写,方便跳转到布局管理** @return*/protected abstract int getLayoutId();/*** 注册需要使用的控件*/protected abstract void initView();protected abstract void onCreateSuspension();/*** 根据id快速找到控件** @param id* @param <E>* @return*/public final <E extends View> E findView(int id) {try {return (E) view.findViewById(id);} catch (ClassCastException ex) {throw ex;}}/*** 根据id快速找到控件** @param id* @param onClickListener* @param <E>* @return*/public final <E extends View> E findView(int id, View.OnClickListener onClickListener) {E e = findView(id);e.setOnClickListener(onClickListener);return e;}/*** 对windowManager进行设置** @return*/public WindowManager.LayoutParams getParams() {wmParams = new WindowManager.LayoutParams();//设置window type 下面变量2002是在屏幕区域显示,2003则可以显示在状态栏之上//wmParams.type = LayoutParams.TYPE_PHONE;if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;} else {wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;}
//        wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;//设置图片格式,效果为背景透明wmParams.format = PixelFormat.RGBA_8888;//设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)//wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;//设置可以显示在状态栏上wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;return wmParams;}/*** 全屏显示悬浮视图*/public void showSuspend() {showSuspend(0, 0, true);}/*** 显示悬浮视图** @param sizeEntity* @param isMatchParent 是否全屏显示*/public void showSuspend(SizeEntity sizeEntity, boolean isMatchParent) {if (sizeEntity != null) {showSuspend(sizeEntity.getWidth(), sizeEntity.getHeight(), isMatchParent);}}/*** 显示悬浮视图** @param width* @param height*/public void showSuspend(int width, int height, boolean isMatchParent) {//设置悬浮窗口长宽数据if (isMatchParent) {wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;} else {wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;}//悬浮窗的开始位置,读取缓存wmParams.x = width;wmParams.y = height;if (isShowing) {removeView();}mWindowManager.addView(view, wmParams);isShowing = true;}/*** 更新当前视图的位置** @param x 更新后的X轴的增量* @param y 更新后的Y轴的增量*/public void updateSuspend(int x, int y) {if (view != null) {//必须是当前显示的视图才给更新WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) view.getLayoutParams();layoutParams.x += x;layoutParams.y += y;mWindowManager.updateViewLayout(view, layoutParams);}}/*** 移除当前悬浮窗*/public void dismissSuspend() {if (view != null) {mWindowManager.removeView(view);isShowing = false;if (onSuspendDismissListener != null) {onSuspendDismissListener.onDismiss();}}}public Context getContext() {return context;}public View getView() {return view;}/*** 是否正在显示** @return*/public boolean isShowing() {return isShowing;}/*** 移除弹窗的时候回调** @param onSuspendDismissListener*/public void setOnSuspendDismissListener(OnSuspendDismissListener onSuspendDismissListener) {this.onSuspendDismissListener = onSuspendDismissListener;}public interface OnSuspendDismissListener {public void onDismiss();}
}

还有里面用到的一个size类:


/*** 宽高实体* Created by 她叫我小渝 on 2016/11/4.*/public class SizeEntity {private int width;private int height;public SizeEntity(){}public SizeEntity(int width,int height){setWidth(width);setHeight(height);}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}
}

3、定制视图和使用

要实现的逻辑是,显示一个悬浮球,然后可以拖动移动悬浮球的位置,效果图:

          

然后新建一个类,LogoSuspend继承BaseSuspend,里面引用到了一些工具类就不贴出来了,用到的地方我会加上注释


/*** 悬浮球* Created by 她叫我小渝 on 2017/1/1.*/public class LogoSuspend extends BaseSuspend {/*** ui*/private ImageView ivLogo;/*** 变量*/private int width, height;private float mStartX, mStartY, mStopX, mStopY, touchStartX, touchStartY;private long touchStartTime;/*** 接口*/private View.OnClickListener onClickListener;public LogoSuspend(Context context) {super(context);}@Overrideprotected int getLayoutId() {return R.layout.suspend_logo;}@Overrideprotected void initView() {ivLogo = findView(R.id.iv_logo);ivLogo.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent event) {final int action = event.getAction();mStopX = event.getRawX();mStopY = event.getRawY();switch (action) {case MotionEvent.ACTION_DOWN:// 以当前父视图左上角为原点mStartX = event.getRawX();mStartY = event.getRawY();touchStartX = event.getRawX();touchStartY = event.getRawY();touchStartTime = DateUtil.getTimeForLong();//获取当前时间戳break;case MotionEvent.ACTION_MOVE:width = (int) (mStopX - mStartX);height = (int) (mStopY - mStartY);mStartX = mStopX;mStartY = mStopY;updateSuspend(width, height);break;case MotionEvent.ACTION_UP:width = (int) (mStopX - mStartX);height = (int) (mStopY - mStartY);updateSuspend(width, height);WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) getView().getLayoutParams();SuspensionCache.setSuspendSize(getContext(), new SizeEntity(layoutParams.x + width, layoutParams.y + height));//缓存一下当前位置if ((mStopX - touchStartX) < 30 && (mStartY - touchStartY) < 30 && (DateUtil.getTimeForLong() - touchStartTime) < 300) {//左右上下移动距离不超过30的,并且按下和抬起时间少于300毫秒,算是单击事件,进行回调if (onClickListener != null) {onClickListener.onClick(view);}}break;}return true;}});}@Overrideprotected void onCreateSuspension() {}/*** 设置点击监听** @param onClickListener*/public void setOnClickListener(View.OnClickListener onClickListener) {this.onClickListener = onClickListener;}
}

布局文件syspend_logo.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rly_bg"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/iv_logo"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_home_add_normal" />
</RelativeLayout>

因为Activity是有生命周期的,所以打开悬浮窗的Context上下文,不要用Activity的,而是用Service的

创建并注册一个Service,然后在onCreate方法中执行调用代码就好

@Overridepublic void onCreate() {super.onCreate();ALog.e("服务已创建");if (logoSuspend == null) {logoSuspend = new LogoSuspend(this);}logoSuspend.showSuspend(SuspensionCache.getSuspendSize(this), false);//从缓存中提取上一次显示的位置logoSuspend.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//处理单击事件}});}

4、废话

上面的例子,其实还是比较简单的,但一般开发对于悬浮球的需求并不算很大,Base类的话,目前只是最基础的东西,在开发的过程中,需要用到什么了再往里面加就好,问题不大。

目前代码支持同时显示多个悬浮窗、悬浮球,主要用于在于悬浮窗交互的时候,直接弹出其他的交互界面(也是以悬浮窗的状态出现),但建议每一个页面都有关闭按钮或者做返回键关闭的相关操作,毕竟是显示在最前端的,要是关不掉就点哪里都没用,只能是强制关机了…………()&@()……()@#*¥)()@*#…………@#)()*¥)()…………

Android 悬浮窗、悬浮球开发相关推荐

  1. Android 悬浮窗语音识别功能开发详解

    笔者是一个普通不能再普通的程序员,本着出处兴趣,花时间研究了一下,想实现手机的悬浮窗语音识别功能,这样不影响自己其它操作的,语音识别技术是用百度云语音sdk,应该不难实现,很难实现就是核心语音识别技术 ...

  2. android大小悬浮窗,悬浮窗不同android版本适配

    实现添加悬浮窗的核心源码代码WindowManagerService#addWindow方法中有以下几个关键: 1.权限检查 mPolicy.checkAddPermission(attrs, app ...

  3. Android开发笔记(一百一十八)自定义悬浮窗

    WindowManager 在前面< Android开发笔记(六十六)自定义对话框>中,我们提到每个页面都是一个Window窗口,许多的Window对象需要一个管家来打理,这个管家我们称之 ...

  4. android 悬浮窗 输入框_利用DecorView实现悬浮窗的效果

    由于众所周知的原因,Android系统虽然提供了悬浮窗的功能,但使用之前需要用记授权,有些手机对这个授权还要再次确认,以至于很多用户出于谨慎的目地就不去打开了.但我们在实际开发当中却又需要这个功能是该 ...

  5. Android 摄像头预览悬浮窗,可拖动,可显示在其他app上方

    市面上常见的摄像头悬浮窗,如微信.手机QQ的视频通话功能,有如下特点: 整屏页面能切换到一个小的悬浮窗 悬浮窗能运行在其他app上方 悬浮窗能跳回整屏页面,并且悬浮窗消失 我们探讨过用CameraX打 ...

  6. Android窗口Window的创建(悬浮窗)

    创建悬浮窗以及基于无障碍服务的窗口 关于悬浮窗的创建 启动悬浮窗 关于前台服务 启动服务 无障碍窗口 知识点 参考链接 关于悬浮窗的创建 首先需要获取WindowManager WindowManag ...

  7. WindowManager解析(二)Android悬浮框无法弹出输入法的原因和无需权限显示悬浮窗

    Android悬浮框无法弹出输入法 最近要研究悬浮窗方面的东西,遇到一个问题,我的悬浮窗里面有一个输入框,但是不弹出输入法,后来找到一个方法: 在WindowManager的实例获取方式不对,之前是这 ...

  8. android悬浮窗只只点击按钮,只有安卓才能体验的悬浮窗!果粉看了默默收起手机...

    原标题:只有安卓才能体验的悬浮窗!果粉看了默默收起手机 现如今手机的性能越来越强劲,屏幕越来越大,我们在使用手机的时候经常被其他事情所打扰.比如在追剧的时候突然来了一条消息,又不想中断追剧又想回复消息 ...

  9. 悬浮窗权限突破及兼容性处理

    转载请注明出处: http://blog.csdn.net/brucehurrican/article/details/64129000 通常业务需要在桌面显示悬浮窗来展示某些功能,如360的悬浮球, ...

  10. UI悬浮窗控制台脚本交互

    牙叔教程 简单易学 使用场景 有界面, 有悬浮窗, 有脚本, 还不会交互, 就看这个 效果展示 流程图 autojs版本 8.7.7-0 get知识点 导入安卓类 停止其他脚本 设置状态栏颜色 获取状 ...

最新文章

  1. 2022-2028年中国丁基橡胶行业市场深度分析及投资前景展望报告
  2. POJ 3458 Colour Sequence(简单题)
  3. iptables总结
  4. uva1347Tour
  5. html5 --- IDBDatabase创建对象存储和索引
  6. 将二维列表输出到excel
  7. redis哨兵模式没有切换主机_Redis哨兵(Sentinel)模式
  8. Pytest脚本中运行用例方式
  9. Oracle的dbms_jobs 自动计划
  10. linux如何挂载windows下的共享文件
  11. JS--微信浏览器复制到剪贴板实现
  12. 计算机网络超详细笔记(五):网络层
  13. 基于javaweb+mysql的+JPA学生宿舍学生住宿申请管理系统(管理员、学生)
  14. Pandas基础:列方向分组变形
  15. kron matlab_使用kron来实现repmat, repelem的功能
  16. 一键禁用Win10自动更新,联想官方出品!!
  17. JFreechart中文在AIX下显示方框解决方法
  18. Python札记 -- 参数魔法
  19. 盛迈坤电商:电商运营要怎么样进行选款
  20. 基于高德地图的交通数据分析

热门文章

  1. css3制作广告栏效果的疑问? 1
  2. 管理是一门艺术,好坏全在细微之间
  3. 奥维互动地图加载地球引擎Google Earth Engine(GEE)1984-2022 地球卫星资源 亲测有效,路亚 钓鱼 露营 水下结构 水文 温湿度 地貌变化 大数据AI分析 神器
  4. Word及Autocad中中文字号与字体大小的关系
  5. 如何保存window10锁屏壁纸
  6. 关于电脑连不上WiFi,但可以连上网线的解决办法
  7. 橘子学ES19之词项搜索全文检索
  8. 果粉沸腾,iPhone6领衔苹果最顶级明星阵容
  9. 从“人、货、场”搭建数据指标体系,助力电商增长
  10. VS code开发工具的使用教程