制作浮窗小球: 步骤1:浮窗管理者创建(单例) * a.私有化构造函数 * b.创建静态的返回浮窗管理类的方法。 * * 步骤2:浮窗球小球的制作(自定义控件) * a.onMeasure确定该控件或子控件的大小 * b.onLayout确定该控件及子控件在父窗体中的位置 * c.onDraw绘制该控件的内容 * * 步骤3:显示浮窗小球(Window Manager) * a.addView()向当前的手机窗口界面添加view * b.removeView()从当前的窗体上移除View * c.updateviewLayout()刷新当前View的显示
问题描述:
按照以前的写法:用
TYPE_PHONE和<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>会报错:
AndroidRuntime: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@c8d1f1a -- permission denied for window type 2002
* 后面的2002表示设置的type为TYPE_PHONE
解决方法:(对于Android O之后)
1。注册文件中声明权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
2.将windowmanager的addview()中的params参数中的type改为如下:
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
“TYPE_APPLICATION_OVERLAY”是重点。
如果不设置该TYPE,应用会Crash。
3.申请android.permission.SYSTEM_ALERT_WINDOW(该权限不能使用 requestPermissions 方法。)
if (! Settings.canDrawOverlays(MainActivity.this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent,10);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == 10) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
Toast.makeText(MainActivity.this,"not granted",Toast.LENGTH_SHORT);
}
}
}
然后运行app,按照下图勾选后返回即可看见浮窗。
1.Windowmanager配置:
package com.yinlei.jiasuqiu.engine;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.WindowManager;
import com.yinlei.jiasuqiu.view.FloatCircleView;
/**
* @date on 2019/6/22
* @author Yinlei
* @packagename
* @email [email protected]
* @describe 浮窗管理者创建.
* 记得在清单文件中声明权限:
* <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
*
* 报错:AndroidRuntime: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@c8d1f1a -- permission denied for window type 2002
* 后面的2002表示设置的type为TYPE_PHONE
* 危险权限需要动态申请
*/
public class FloatViewManager {
private Context context;
private WindowManager wm;//通过这个WindowManager来操控父窗体的显示和隐藏以及位置的改变
private FloatCircleView circleView;//自定义浮窗小球view
private FloatViewManager(Context context){
this.context = context;
wm= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
circleView=new FloatCircleView(context);
}
private static FloatViewManager instance;
public static FloatViewManager getInstance(Context context){
if(instance ==null){
synchronized (FloatViewManager.class){
if(instance ==null){
instance = new FloatViewManager(context);
}
}
}
return instance;
}
/**
* 展示浮窗小球到窗口上
*/
public void showFloatCircleView(){
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.width=circleView.width;
params.height=circleView.height;
params.gravity= Gravity.TOP|Gravity.LEFT;
params.x=0;
params.y=0;
//以悬浮在其他应用上的权限展示。因为打电话是悬浮在其他应用上的。用此type即可。
params.type= WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
// params.type= WindowManager.LayoutParams.TYPE_PHONE;
//不去抢焦点
params.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.format= PixelFormat.RGBA_8888;
wm.addView(circleView,params);
}
}
2.相关浮窗小球的配置代码如下:(简易版)
package com.yinlei.jiasuqiu.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* @date on 2019/6/22
* @author Yinlei
* @packagename
* @email [email protected]
* @describe 浮窗球小球的制作.
*/
public class FloatCircleView extends View {
public int width = 150;
public int height = 150;
Paint circlePaint;
Paint textPaint;
private String text = "50%";
public FloatCircleView(Context context) {
super(context);
initPaints();
}
public FloatCircleView(Context context, @Nullable AttributeSet attrs) {//AttributeSet表示自定义属性在attr.xml中
super(context, attrs);
initPaints();
}
public FloatCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {//defStyleAttr表示在xml布局文件中
super(context, attrs, defStyleAttr);
initPaints();
}
private void initPaints() {
circlePaint = new Paint();
circlePaint.setColor(Color.GRAY);
circlePaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setTextSize(25);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setFakeBoldText(true);
}
// public FloatCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
// super(context, attrs, defStyleAttr, defStyleRes);
// }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width,height);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(width/2,height/2,width/2,circlePaint);
float textWidth=textPaint.measureText(text);
float x = width/2-textWidth/2;
//考虑基线base line
Paint.FontMetrics metrics = textPaint.getFontMetrics();
float dy = (metrics.descent+metrics.ascent)/2;
float y = height/2+dy;
canvas.drawText(text,x,y,textPaint);
}
}