作者
大家好,我叫小鑫,也可以叫我蜡笔小鑫😊;
本人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<