应用内悬浮窗适配方案实战

作者

大家好,我叫小鑫,也可以叫我蜡笔小鑫😊;

本人17年毕业于中山大学,于2018年7月加入37手游安卓团队,曾经就职于久邦数码担任安卓开发工程师;

目前是37手游安卓团队的海外负责人,负责相关业务开发;同时兼顾一些基础建设相关工作。

背景

游戏内的悬浮窗通常情况下只出现在游戏内,用做切换账号、客服中心等功能的快速入口。本文将介绍几种实现方案,以及我们踩过的坑

1、方案一:应用外悬浮窗+栈顶权限/生命周期回调

通常实现悬浮窗,首先考虑到的会是要使用悬浮窗权限,用WindowManager在设备界面上addView实现(UI层级较高,应用外显示)

1、弹出悬浮窗需要用到悬浮窗权限

    <!--悬浮窗权限-->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

2、判断悬浮窗游戏内外显示

方式一:使用栈顶权限获取当前

//需要声明权限
<uses-permission android:name="android.permission.GET_TASKS" />

//判断当前是否在后台
private boolean isAppIsInBackground(Context context) {
   
		boolean isInBackground = true;
		ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
   
			List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
			for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
   
				//前台程序
				if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
   
					for (String activeProcess : processInfo.pkgList) {
   
						if (activeProcess.equals(context.getPackageName())) {
   
							isInBackground = false;
						}
					}
				}
			}
		} else {
   
			List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
			ComponentName componentInfo = taskInfo.get(0).topActivity;
			if (componentInfo.getPackageName().equals(context.getPackageName())) {
   
				isInBackground = false;
			}
		}

		return isInBackground;
	}

这里考虑到这种方案网上有很多具体案例,在这里就不实现了。但是这种方案有如下缺点:

1、适配问题,悬浮窗权限在不同设备上由于不同产商实现不同,适配难。

2、向用户申请权限,打开率较低,体验较差

2、方案二:addContentView实现

原理:Activity的接口中除了我们常用的setContentView接口外,还有addContentView接口。利用该接口可以在Activity上添加View。

这里你可能会问:

1、那只能在一个Activity上添加吧?

没错,是只能在当前Activity上添加,但是由于游戏通常也就在一个Activity跑,因此基本上是可以接受的。

2、只add一个view,那拖动怎么实现?

LayoutParams params = new LayoutParams(mWidth, mHeight);
params.setMargins(mLeft, mTop, 0, 0);
setLayoutParams(params);

通过更新LayoutParams调整子View在父View中的位置就能实现

具体代码如下:

/**
 * @author zhuxiaoxin
 * 可拖拽贴边的view
 */
public class DragViewLayout extends RelativeLayout {
   

    //手指拖拽得到的位置
    int mLeft, mRight, mTop, mBottom;

    //view所在的位置
    int mLastX, mLastY;

    /**
     * 屏幕宽度|高度
     */
    int mScreenWidth, mScreenHeight;

    /**
     * view的宽度|高度
     */
    int mWidth, mHeight;


    /**
     * 是否在拖拽过程中
     */
    boolean isDrag = false;

    /**
     * 系统最小滑动距离
     * @param context
     */
    int mTouchSlop = 0;

    public DragViewLayout(Context context) {
   
        this(context, null);
    }

    public DragViewLayout(Context context, AttributeSet attrs) {
   
        this(context, attrs, 0);
    }

    public DragViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
   
        super(context, attrs, defStyleAttr);
        mScreenWidth = context.getResources().getDisplayMetrics().widthPixels;
        mScreenHeight = context.getResources().getDisplayMetrics().heightPixels;
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    protected void onFinishInflate() {
   
        super.onFinishInflate();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
   
        int action = event.getAction();
        switch (action<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值