一、游戏内显示悬浮球
手游SDK的悬浮球和一般的悬浮窗有点不一样,它只需要在游戏内显示即可,不需要也不能在桌面中显示出来。
所以如果使用WindowManager创建悬浮窗,需要监听App是否在前台,如果在,则显示。如果不在则隐藏悬浮窗。
而App不在前台了,可能有三种情况:1、正常退出。2、home键回到主界面了。3、点击任务键切换到别的程序。
正常退出的情况,那只要正常销毁悬浮窗就好。
home键和多任务键的情况,需要对按键进行监听。然后判断App是否在前台,如果不是,则是隐藏/销毁悬浮窗。
home键和多任务键的监听,示例代码:
InnerRecevier innerReceiver = new InnerRecevier(); IntentFilter intentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(innerReceiver, intentFilter); class InnerRecevier extends BroadcastReceiver { final String SYSTEM_DIALOG_REASON_KEY = "reason"; final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); if (reason != null) { if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) { Toast.makeText(MainActivity.this, "Home键被监听", Toast.LENGTH_SHORT).show(); } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { Toast.makeText(MainActivity.this, "多任务键被监听", Toast.LENGTH_SHORT).show(); } } } } }
判断当前App是否在前台,示例代码:
public static boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
String packageName = context.getApplicationContext().getPackageName();
//获取Android设备中所有正在运行的App
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null)
return false;
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(packageName)
&& appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
}
}
return false;
}
但要使用WindowManager还需要用户手动打开悬浮窗权限。
弹出索要权限提示框,然后待用户点击确定后跳转到权限设置界面,寻找悬浮窗权限,并打开。这一系列操作对用户不太友好,因为操作比较过于繁琐。
在SDK中创建悬浮球还可以使用ViewGroup。
ViewGroup最大优势是不需要权限申请。使用ViewGroup作为悬浮球适用于游戏或者单Activity APP。
示例代码:
ViewGroup view = (ViewGroup )AppActivity.getWindow().getDecorView();//获取最顶层的view
ViewGroup floatViewGroup=(ViewGroup) View.inflate(mActivity, Res.getLayout("circle_frame"), view);
floatView = View.inflate(mContext, Res.getLayout("circlemenu"), null);
floatViewGroup.addView(floatView);//把悬浮窗的view加进来
如果是多Activity就需要使用到Application.ActivityLifecycleCallbacks方法。
ActivityLifecycleCallbacks为Activity生命周期监控接口的方法,它包含了一整套Activity的生命周期回调方法,只要有一个Activity触发了声明周期,这个接口的回调就会触发,并且传回触发生命周期方法的Activity对象。
在拿到当前显示的Activity之后,通过activity.getWindow().getDecorView() 来获取Activity的视图组。然后把悬浮窗的view加进去。切换Activity时,把悬浮窗的view销毁,在新显示的Activity同样把悬浮窗的view加进去。
二、悬浮球UI 以及功能
Demo示例:
这个圆形悬浮球UI一共分四部分:
1、最开始的 悬浮球 icon。可以拖动,并且靠边半隐藏。
拖动功能是悬浮窗中很常见的功能,实现拖动功能需要用到触摸事件的处理View.OnTouchListener。监听滑动所造成xy的变化,传去新的坐标,刷新悬浮球即可。
示例代码:
//悬浮窗的滑动监听
floatView.setOnTouchListener(new FloatingOnTouchListener());
private class FloatingOnTouchListener implements View.OnTouchListener {
private int x;
private int y;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int nowX = (int) event.getRawX();
int nowY = (int) event.getRawY();
x = nowX-floatView.getWidth()/2;
y = nowY-floatView.getHeight()/2;
floatView.setX(x);
floatView.setY(y);
floatView.postInvalidate();
break;
default:
break;
}
return false;
}
}
2、圆形菜单,可以转动。主要是参考Android 打造炫目的圆形菜单这篇博客修改。
3、账号页面,一个简单的ListView。ListView的简单使用,可以点击这里。
4、加载WebView页面,分两个。
一个用于显示“新游”,“专区”等。
需要监听网页进度,出现错误时,使用默认界面代替。
示例代码:
webView.setWebChromeClient(new MyWebChromeClient());//监听网页进度
class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) { //接受网页标题
super.onReceivedTitle(view, title);
Log.e("test",title+"");
Web_Title.setText(titleName);//设定显示的标题
if (title.contains("404") || title.contains("500") || title.contains("Error") || title.contains("找不到网页") || title.contains("网页无法打开")||title.contains("about:blank")) {
view.loadUrl("about:blank");// 避免出现默认的错误界面
view.setVisibility(View.GONE); //隐藏WebView
//显示加载失败页面
WebNull.setVisibility(View.VISIBLE);
WebNullPhoto.setBackgroundResource(Res.getDrawable("box_gift_null"));
WebNullTitle.setText("暂无"+titleName);
}
}
}
另一个用于客服。
客服页面需要有导航栏,需要保存聊天记录。
导航:
webview.canGoBack();//判断是否能后退
mWebView.goBack();//后退
mWebView.canGoForward();//判断是否能前进
mWebView.goForward();//前进
mWebView.reload();//刷新
Demo示例: