Android如何仿IOS系统实现悬浮窗效果
发表于:2025-01-17 作者:千家信息网编辑
千家信息网最后更新 2025年01月17日,这篇文章主要介绍Android如何仿IOS系统实现悬浮窗效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!代码如下:在这之前,我们需要在manifest中申请权限:并且,悬浮窗
千家信息网最后更新 2025年01月17日Android如何仿IOS系统实现悬浮窗效果
这篇文章主要介绍Android如何仿IOS系统实现悬浮窗效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
代码如下:
在这之前,我们需要在manifest中申请权限:
并且,悬浮窗这个权限我们需要手动在手机找到应用权限管理,允许这个权限才行
小悬浮窗的界面代码float_normal_view.xml:
大悬浮窗的界面代码float_control_view:
入口activity(FloatActivity ):
public class FloatActivity extends Activity { MyWindowManager myWindowManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myWindowManager = MyWindowManager.getInstance(); myWindowManager.createNormalView(this.getApplicationContext()); }}
悬浮窗管理器MyWindowManager:
/** * Created by shiweixian on 2017/3/7. * 悬浮窗管理器 * 创建,移除 * 单例模式 */public class MyWindowManager { private FloatNormalView normalView; private FloatControlView controlView; private static MyWindowManager instance; private WindowManager windowManager; private MyWindowManager() { } public static MyWindowManager getInstance() { if (instance == null) instance = new MyWindowManager(); return instance; } private WindowManager getWindowManager(Context context) { if (windowManager == null) windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); return windowManager; } /** * 判断小悬浮窗是否存在 * * @return */ public boolean isNormalViewExists() { return normalView != null; } /** * 判断播放器这个大悬浮窗是否存在 * * @return */ public boolean isControlViewExists() { return controlView != null; } /** * 创建小型悬浮窗 */ public void createNormalView(Context context) { if (normalView == null) { normalView = new FloatNormalView(context); } } /** * 移除悬浮窗 * * @param context */ public void removeNormalView(Context context) { if (normalView != null) { windowManager.removeView(normalView); normalView = null; } } /** * 创建小型悬浮窗 */ public void createControlView(Context context) { if (controlView == null) controlView = new FloatControlView(context); } /** * 移除悬浮窗 * * @param context */ public void removeControlView(Context context) { if (controlView != null) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); windowManager.removeView(controlView); controlView = null; } }}
小悬浮窗FloatNormalView:
/** * Created by shiwe on 2017/3/7. * 缩小的悬浮窗 */public class FloatNormalView extends LinearLayout { /** * 记录小悬浮窗的宽度 */ public static int viewWidth; /** * 记录小悬浮窗的高度 */ public static int viewHeight; /** * 记录系统状态栏的高度 */ private static int statusBarHeight; /** * 用于更新小悬浮窗的位置 */ private WindowManager windowManager; /** * 小悬浮窗的参数 */ private WindowManager.LayoutParams mParams; /** * 记录当前手指位置在屏幕上的横坐标值 */ private float xInScreen; /** * 记录当前手指位置在屏幕上的纵坐标值 */ private float yInScreen; /** * 记录手指按下时在屏幕上的横坐标的值 */ private float xDownInScreen; /** * 记录手指按下时在屏幕上的纵坐标的值 */ private float yDownInScreen; /** * 记录手指按下时在小悬浮窗的View上的横坐标的值 */ private float xInView; /** * 记录手指按下时在小悬浮窗的View上的纵坐标的值 */ private float yInView; public FloatNormalView(Context context) { super(context); windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); LayoutInflater.from(context).inflate(R.layout.float_normal_view, this); View view = findViewById(R.id.ll_float_normal); viewWidth = view.getLayoutParams().width; viewHeight = view.getLayoutParams().height; initLayoutParams(); } /** * 初始化参数 */ private void initLayoutParams() { //屏幕宽高 int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); mParams = new WindowManager.LayoutParams(); //总是出现在应用程序窗口之上。 mParams.type = WindowManager.LayoutParams.TYPE_PHONE; // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 // FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按,不设置这个flag的话,home页的划屏会有问题 mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; //悬浮窗默认显示的位置 mParams.gravity = Gravity.START | Gravity.TOP; //指定位置 mParams.x = screenWidth - viewWidth * 2; mParams.y = screenHeight / 2 + viewHeight * 2; //悬浮窗的宽高 mParams.width = WindowManager.LayoutParams.WRAP_CONTENT; mParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mParams.format = PixelFormat.TRANSPARENT; windowManager.addView(this, mParams); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 手指按下时记录必要数据,纵坐标的值都需要减去状态栏高度 xInView = event.getX(); yInView = event.getY(); xDownInScreen = event.getRawX(); yDownInScreen = event.getRawY() - getStatusBarHeight(); xInScreen = event.getRawX(); yInScreen = event.getRawY() - getStatusBarHeight(); break; case MotionEvent.ACTION_MOVE: xInScreen = event.getRawX(); yInScreen = event.getRawY() - getStatusBarHeight(); // 手指移动的时候更新小悬浮窗的位置 updateViewPosition(); break; case MotionEvent.ACTION_UP: // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。 if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) { openOrCloseControlView(); } break; default: break; } return true; } /** * 将小悬浮窗的参数传入,用于更新小悬浮窗的位置。 * * @param params 小悬浮窗的参数 */ public void setParams(WindowManager.LayoutParams params) { mParams = params; } /** * 更新小悬浮窗在屏幕中的位置。 */ private void updateViewPosition() { mParams.x = (int) (xInScreen - xInView); mParams.y = (int) (yInScreen - yInView); windowManager.updateViewLayout(this, mParams); } /** * 打开或关闭大悬浮窗。 */ private void openOrCloseControlView() { MyWindowManager manager = MyWindowManager.getInstance(); if (!manager.isControlViewExists()) manager.createControlView(getContext()); else manager.removeControlView(getContext()); } /** * 用于获取状态栏的高度。 * * @return 返回状态栏高度的像素值。 */ private int getStatusBarHeight() { if (statusBarHeight == 0) { try { Class> c = Class.forName("com.android.internal.R$dimen"); Object o = c.newInstance(); Field field = c.getField("status_bar_height"); int x = (Integer) field.get(o); statusBarHeight = getResources().getDimensionPixelSize(x); } catch (Exception e) { e.printStackTrace(); } } return statusBarHeight; }}
大悬浮窗FloatControlView:
/** * Created by shiwe on 2017/3/7. * 缩小的悬浮窗 */public class FloatNormalView extends LinearLayout { /** * 记录小悬浮窗的宽度 */ public static int viewWidth; /** * 记录小悬浮窗的高度 */ public static int viewHeight; /** * 记录系统状态栏的高度 */ private static int statusBarHeight; /** * 用于更新小悬浮窗的位置 */ private WindowManager windowManager; /** * 小悬浮窗的参数 */ private WindowManager.LayoutParams mParams; /** * 记录当前手指位置在屏幕上的横坐标值 */ private float xInScreen; /** * 记录当前手指位置在屏幕上的纵坐标值 */ private float yInScreen; /** * 记录手指按下时在屏幕上的横坐标的值 */ private float xDownInScreen; /** * 记录手指按下时在屏幕上的纵坐标的值 */ private float yDownInScreen; /** * 记录手指按下时在小悬浮窗的View上的横坐标的值 */ private float xInView; /** * 记录手指按下时在小悬浮窗的View上的纵坐标的值 */ private float yInView; public FloatNormalView(Context context) { super(context); windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); LayoutInflater.from(context).inflate(R.layout.float_normal_view, this); View view = findViewById(R.id.ll_float_normal); viewWidth = view.getLayoutParams().width; viewHeight = view.getLayoutParams().height; initLayoutParams(); } /** * 初始化参数 */ private void initLayoutParams() { //屏幕宽高 int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); mParams = new WindowManager.LayoutParams(); //总是出现在应用程序窗口之上。 mParams.type = WindowManager.LayoutParams.TYPE_PHONE; // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 // FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按,不设置这个flag的话,home页的划屏会有问题 mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; //悬浮窗默认显示的位置 mParams.gravity = Gravity.START | Gravity.TOP; //指定位置 mParams.x = screenWidth - viewWidth * 2; mParams.y = screenHeight / 2 + viewHeight * 2; //悬浮窗的宽高 mParams.width = WindowManager.LayoutParams.WRAP_CONTENT; mParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mParams.format = PixelFormat.TRANSPARENT; windowManager.addView(this, mParams); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 手指按下时记录必要数据,纵坐标的值都需要减去状态栏高度 xInView = event.getX(); yInView = event.getY(); xDownInScreen = event.getRawX(); yDownInScreen = event.getRawY() - getStatusBarHeight(); xInScreen = event.getRawX(); yInScreen = event.getRawY() - getStatusBarHeight(); break; case MotionEvent.ACTION_MOVE: xInScreen = event.getRawX(); yInScreen = event.getRawY() - getStatusBarHeight(); // 手指移动的时候更新小悬浮窗的位置 updateViewPosition(); break; case MotionEvent.ACTION_UP: // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。 if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) { openOrCloseControlView(); } break; default: break; } return true; } /** * 将小悬浮窗的参数传入,用于更新小悬浮窗的位置。 * * @param params 小悬浮窗的参数 */ public void setParams(WindowManager.LayoutParams params) { mParams = params; } /** * 更新小悬浮窗在屏幕中的位置。 */ private void updateViewPosition() { mParams.x = (int) (xInScreen - xInView); mParams.y = (int) (yInScreen - yInView); windowManager.updateViewLayout(this, mParams); } /** * 打开或关闭大悬浮窗。 */ private void openOrCloseControlView() { MyWindowManager manager = MyWindowManager.getInstance(); if (!manager.isControlViewExists()) manager.createControlView(getContext()); else manager.removeControlView(getContext()); } /** * 用于获取状态栏的高度。 * * @return 返回状态栏高度的像素值。 */ private int getStatusBarHeight() { if (statusBarHeight == 0) { try { Class> c = Class.forName("com.android.internal.R$dimen"); Object o = c.newInstance(); Field field = c.getField("status_bar_height"); int x = (Integer) field.get(o); statusBarHeight = getResources().getDimensionPixelSize(x); } catch (Exception e) { e.printStackTrace(); } } return statusBarHeight; }}
以上是"Android如何仿IOS系统实现悬浮窗效果"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!
手指
位置
屏幕
高度
参数
状态
纵坐标
更新
横坐标
应用
系统
事件
权限
代码
管理
效果
必要
像素
内容
图标
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
什么是数据库的回表
用c语言向数据库写东西
网络安全公司第三季度营业额
用手机如何做服务器
thrift 服务器
网优中心 软件开发
服务器硬件开发经理
jdbc 多个数据库
长沙网律互联网科技公司
福建高校网络安全专业
数据库各种约束的中文名
软件开发与云计算哪个就业好
自制无线打印机服务器
天津师范大学考试试卷数据库
服务器远程白屏
移动终端开发软件开发
辛集软件开发商在线咨询
浙江计算机软件开发平台
广州停车系统软件开发价格
网络安全设备配置服务
数据库定制显示
联合国贸易与发展数据库
网络安全公司第三季度营业额
服务器上搭建python接口
国家信息网络安全评级在哪申请
保障数据库的安全性
怎样安全卸载sql数据库
思迅v6怎么连接数据库
数据库技术发展经历了三个阶段
服务器防滑