提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
此项目为本人刚学习Android
时的练手项目,技术含量不高,如文中代码书写不够严谨处,望各位见谅。
效果图:
一、加速球项目总体实现思路
注:悬浮窗体是居于浮窗管理者FloatViewManager
实现的,是需要在当前窗口添加我们自定义的小球。
- 创建浮窗管理者
FloatViewManager
- 制作浮窗小球
FloatCircleView
- 显示浮窗小球
FloatCircleView
- 处理浮窗小球的触摸和拖动事件
- 制作和显示加速球
FloatMenuView
- 处理加速球
FloatMenuView
的事件 - 加速球
FloatMenuView
的单击和双击动画 - 在底部菜单栏显示加速球
FloatMenuView
二、实现步骤
第一步.创建浮窗管理者FloatViewManager
FloatViewManager
类代码如下(示例):
private final WindowManager wm;
public Context context;
/**
* (第一步)悬浮球管理者
* @param context
*/
public FloatViewManager(Context context) {
this.context = context;
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//1.获取WindowManager实例
}
/**
* 第一步:获取悬浮球的单例对象
* @param context
* @return
*/
public static FloatViewManager getInstance(Context context){
if (instance==null){
synchronized (FloatViewManager.class){
if (instance==null){
instance=new FloatViewManager(context);
}
}
}
return instance;
}
第二步.制作浮窗小球FloatCircleView
FloatCircleView
类代码如下(示例):
/**
1. 自定义悬浮球样式
*/
public class FloatCircleView extends View {
private int width=200;
private int height=200;
private Paint circlePaint;//画圆的笔
private Paint textPaint;//画内容的笔
private String text="50%";
private Boolean isDrag=false;//判断是否是拖拉效果
private Bitmap bitmap;
public FloatCircleView(Context context) {
super(context);
initPaints();//初始化画笔
}
public FloatCircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaints();//初始化画笔
}
public FloatCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaints();//初始化画笔
}
public FloatCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initPaints();//初始化画笔
}
/**
* 创建自定义圆形的样式
*/
private void initPaints() {
circlePaint = new Paint();
circlePaint.setColor(Color.BLUE);
circlePaint.setAntiAlias(true);//启用circlePaint的抗锯齿功能,使绘制的边缘更加平滑。
textPaint = new Paint();
textPaint.setTextSize(25);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);//启用textPaint的抗锯齿功能,使绘制的边缘更加平滑。
textPaint.setFakeBoldText(true);//设置textPaint使文本显示为假粗体,这会在文本的笔画两端添加一些额外的宽度,让文本看起来更粗
Bitmap src = BitmapFactory.decodeResource(getResources(), R.mipmap.img);
//适配大小
bitmap = Bitmap.createScaledBitmap(src, width, height, true);//创建一个缩放后的位图bitmap,原始位图src被缩放到指定的宽度和高度,
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width,height);//setMeasuredDimension是自定义视图的大小
}
@Override
protected void onDraw(Canvas canvas) {
if (isDrag){
canvas.drawBitmap(bitmap,0,0,null);//使用小火箭
}else {
canvas.drawCircle(width/2,height/2,width/2,circlePaint);//1.前面两个参数表示的是圆的圆心 半径为width/2
float textWidth = textPaint.measureText(text);//2.measureText 方法来测量字符串 text 的宽度
float x = width / 2 - textWidth / 2;//3.从画布中心点向左偏移 textWidth / 2 的距离。
Paint.FontMetrics metrics = textPaint.getFontMetrics();//4.这行代码获取 textPaint 画笔的字体度量信息,存储在 metrics 变量中。字体度量信息包括文本的上升、下降、顶部、底部等尺寸。
float dy=-(metrics.descent+metrics.ascent)/2;//5.这行代码计算文本绘制的垂直偏移量 dy,以确保文本垂直居中。metrics.descent 是文本下降的最大距离,metrics.ascent 是文本上升的最大距离。将两者相加后除以2,得到文本基线到画布中心点的垂直偏移量。
float y = height / 2 + dy;//6.从画布中心点向上偏移 dy 的距离。
canvas.drawText(text,x,y,textPaint);//7.文本的起始点坐标为 (x, y)
}
}
}
第三步.显示浮窗小球FloatCircleView
1.FloatViewManager
类代码如下(示例):
/**
* 显示悬浮球
*/
public void showFloatCircleView(){
params=new WindowManager.LayoutParams();//1.新的 WindowManager.LayoutParams 对象,用于定义如何将视图添加到窗口管理器。
params.width=circleView.getWidth();//2.设置了浮动视图的宽度和高度,它们分别等于 circleView 的宽度和高度
params.height=circleView.getHeight();
params.gravity= Gravity.TOP | Gravity.LEFT;//3.设置浮动的位置
params.x=0;//4.浮动视图的初始x和y坐标,这里都设置为0,意味着视图将从屏幕左上角开始。
params.y=20;
//5.设置浮动视图的类型
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else if (Build.VERSION.SDK_INT > 24) {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
} else {
params.type = WindowManager.LayoutParams.TYPE_TOAST;
}
//6.FLAG_NOT_FOCUSABLE 表示视图不会获取焦点,FLAG_NOT_TOUCH_MODAL 表示当触摸事件发生在该视图上时,不会阻塞其他视图的触摸事件。
params.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.format= PixelFormat.RGBA_8888;
wm.addView(circleView,params);//7.添加到窗口
}
MainActivity
类代码如下(示例):
public class MainActivity extends AppCompatActivity {
private Button show_float;
@Override
protected void onCreate(Bundle savedInstanceState) {
Objects.requireNonNull(getSupportActionBar()).hide();//去掉标题栏
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView() {
show_float = findViewById(R.id.show_float);
}
private void initData() {
show_float.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this, MyFloatService.class);
startService(intent);
// finish();
}
});
}
}
MyFloatService
类代码如下(示例):
public class MyFloatService extends Service {
//该方法返回的 IBinder 对象定义了客户端用来与服务进行交互的编程接口。
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
FloatViewManager floatViewManager=FloatViewManager.getInstance(this);
floatViewManager.showFloatCircleView();//展示悬浮球
}
}
第四步.处理浮窗小球的触摸和拖动事件
FloatViewManager
类代码如下(示例):
private View.OnTouchListener circleViewTouchListener=new View.OnTouchListener() {
private float y0;
private float x0;
private float startY;
/**
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//1.移动前记录一下起始位置
startX = event.getRawX();
startY = event.getRawY();
//TODO 为了消费点击事件
x0 = event.getRawX();
y0 = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
//1.记录移动之后所在的位置
float x = event.getRawX();
float y = event.getRawY();
//2.记录移动的偏移量
float dx = x - startX;
float dy = y - startY;
//3.设置在窗口
params.x+=dx;
params.y+=dy;
//3.1移动的时候,悬浮球形状改变
circleView.setDragStage(true);
//4.刷新当前位置
wm.updateViewLayout(circleView,params);
//5.设置当前位置
startX=x;
startY=y;
Log.d("TAG", "偏移了: "+event);
break;
case MotionEvent.ACTION_UP:
//1.记录当前的位置
float endX = event.getRawX();
//2.悬浮球只能靠左或者靠右
if (endX>getScreenWidth()/2){
params.x=getScreenWidth()-circleView.getWidth();
}else {
params.x=0;//表示悬浮球所处在屏幕的位置
}
circleView.setDragStage(false);
wm.updateViewLayout(circleView,params);
//TODO 判断是否消费当前点击事件
if (Math.abs(endX-x0)>6){
return false;
}else {
return false;
}
default:
break;
}
return false;
}
};
//获取屏幕的宽度
private int getScreenWidth(){
return wm.getDefaultDisplay().getWidth();
}
/**
* (第一步)悬浮球管理者
* @param context
*/
public FloatViewManager(Context context) {
this.context = context;
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//1.获取WindowManager实例
circleView= new FloatCircleView(context);
circleView.setOnTouchListener(circleViewTouchListener);
circleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context,"点击悬浮球",Toast.LENGTH_SHORT).show();
//隐藏circleView 显示菜单栏 开启动画
wm.removeView(circleView);
showFloatMenuView();
floatMenuView.startAnimation();
}
});
floatMenuView = new FloatMenuView(context);
}
关键代码:
//3.设置在窗口
params.x+=dx;
params.y+=dy;
//3.1移动的时候,悬浮球形状改变
circleView.setDragStage(true);
//4.刷新当前位置
wm.updateViewLayout(circleView,params);
每一步都要更新当前位置
//TODO 判断是否消费当前点击事件
if (Math.abs(endX-x0)>6){
return false;
}else {
return false;
}
如果是在拖拽的话,则当前就不是点击或者双击事件,要处理好事件的冲突问题
第五步.制作和显示加速球FloatMenuView
FloatCircleView
类代码如下(示例):
/**
1. 自定义加速球
*/
public class FloatMenuView extends LinearLayout {
private LinearLayout ll;
private TranslateAnimation animation;
public FloatMenuView(Context context) {
super(context);
View root = View.inflate(getContext(), R.layout.float_menu_view, null);
ll = root.findViewById(R.id.ll);
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,0,
Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0);
animation.setDuration(500);
animation.setFillAfter(true);
ll.setAnimation(animation);
root.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
FloatViewManager manager=FloatViewManager.getInstance(context);//1.获取浮窗管理者实例
manager.hideFloatMenuView();//2.点击空白处,隐藏加速球,且显示浮窗小球
manager.showFloatCircleView();
return false;//触摸事件没有被消耗,允许事件继续传递。(还可以继续点击浮窗小球)
}
});
addView(root);
}
//执行动画
public void startAnimation(){
animation.start();
}
public FloatMenuView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
View root = View.inflate(getContext(), R.layout.float_menu_view, null);
addView(root);
}
public FloatMenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View root = View.inflate(getContext(), R.layout.float_menu_view, null);
addView(root);
}
public FloatMenuView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
FloatViewManager
类的代码如下
public FloatViewManager(Context context) {
this.context = context;
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//1.获取WindowManager实例
circleView= new FloatCircleView(context);
circleView.setOnTouchListener(circleViewTouchListener);
circleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context,"点击悬浮球",Toast.LENGTH_SHORT).show();
//隐藏circleView 显示菜单栏 开启动画
wm.removeView(circleView);
showFloatMenuView();
floatMenuView.startAnimation();
}
});
floatMenuView = new FloatMenuView(context);
}
/**
* 加速球的显示
*/
private void showFloatMenuView() {
WindowManager.LayoutParams params=new WindowManager.LayoutParams();
params.width=getScreenWidth();
params.height=getScreenHeight()-getStateHeight();
params.gravity=Gravity.BOTTOM | Gravity.LEFT;
params.x=0;
params.y=0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else if (Build.VERSION.SDK_INT > 24) {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
} else {
params.type = WindowManager.LayoutParams.TYPE_TOAST;
}
params.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.format= PixelFormat.RGBA_8888;
wm.addView(floatMenuView,params);
}
//隐藏加速球
public void hideFloatMenuView() {
wm.removeView(floatMenuView);
}
第六步.处理加速球FloatMenuView
的事件
MyProcessView
类代码如下(示例):
public class MyProcessView extends View {
private int width=200;
private int height=200;
private Bitmap bitmap;
private Canvas bitmapCanvas;
private Paint circlePaint;
private Paint progressPaint;
private Paint textPaint;
private Path path=new Path();
private int progress=50;//最高进度
private int currentProgress=0;//当前的进度
private int max=100;
private GestureDetector detector;
private int count=50;
private boolean isSingleTag=false;
//更新UI线程
private Handler handler=new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
public MyProcessView(Context context) {
super(context);
init();
}
public MyProcessView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MyProcessView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public MyProcessView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
/**
* 设置绘制所需的画笔、位图和触摸监听器
*/
private void init() {
//1.绘制圆
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.argb(0xff,0x3a,0x8b,0x6c));
//2.绘制进度效果
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setColor(Color.argb(0xff,0x4e,0x5d,0x6f));
progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//混合模式 遮挡的效果
//3.绘制文本
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(25);
bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
//手势检测器——目的是为了检测是单击还是双击
detector = new GestureDetector(new MyGestureDetectorListener());
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return detector.onTouchEvent(event);
}
});
setClickable(true);//允许点击
}
class MyGestureDetectorListener extends GestureDetector.SimpleOnGestureListener{
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
Toast.makeText(getContext(),"双击",Toast.LENGTH_SHORT).show();
startDoubleTapAnimation();//
return super.onDoubleTap(e);
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
Toast.makeText(getContext(),"单击",Toast.LENGTH_SHORT).show();
isSingleTag=true;
currentProgress=progress;
startSingleTapAnimation();
return super.onSingleTapConfirmed(e);
}
}
private void startSingleTapAnimation() {
handler.postDelayed(singleTapRunnable,200);
}
private SingleTapRunnable singleTapRunnable=new SingleTapRunnable();
class SingleTapRunnable implements Runnable{
@Override
public void run() {
count--;
if (count>=0){
invalidate();
handler.postDelayed(singleTapRunnable,200);
}else {
handler.removeCallbacks(singleTapRunnable);
count=50;
}
}
}
private void startDoubleTapAnimation() {
handler.postDelayed(doubleTapRunnable,50);
}
private DoubleTapRunnable doubleTapRunnable=new DoubleTapRunnable();
class DoubleTapRunnable implements Runnable{
@Override
public void run() {
currentProgress++;
if (currentProgress<=progress){
invalidate();
handler.postDelayed(doubleTapRunnable,50);
}else {
handler.removeCallbacks(doubleTapRunnable);
currentProgress=0;
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
bitmapCanvas.drawCircle(width/2,height/2,width/2,circlePaint);
path.reset();
float y = (1 - (float) currentProgress / max) * height;
path.moveTo(width,y);
path.lineTo(width,height);
path.lineTo(0,height);
path.lineTo(0,y);
if (!isSingleTag){
float d = (1 - ((float) currentProgress / progress)) * 10;
for (int i = 0; i < 5; i++) {//表示的是波浪
path.rQuadTo(10,-d,20,0);
path.rQuadTo(10,d,20,0);
}
}else {
float d=(float) count/50*10;
if (count%2==0){
for (int i = 0; i < 5; i++) {
path.rQuadTo(20,-d,40,0);
path.rQuadTo(20,d,40,0);
}
}else {
for (int i = 0; i < 5; i++) {
path.rQuadTo(20,d,40,0);
path.rQuadTo(20,-d,40,0);
}
}
}
path.close();
bitmapCanvas.drawPath(path,progressPaint);
String text=(int)(((float)currentProgress/max)*100)+"%";
float textWidth = textPaint.measureText(text);
Paint.FontMetrics metrics = textPaint.getFontMetrics();
float baseLine = height / 2 - (metrics.ascent + metrics.descent) / 2;
bitmapCanvas.drawText(text,width/2-textWidth/2,baseLine,textPaint);
canvas.drawBitmap(bitmap,0,0,null);
}
}
第七步.加速球FloatMenuView
的单击和双击动画
MyProcessView
类代码如下(示例):
private void init() {
//1.
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.argb(0xff,0x3a,0x8b,0x6c));
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setColor(Color.argb(0xff,0x4e,0x5d,0x6f));
progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(25);
bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
//监听器
detector = new GestureDetector(new MyGestureDetectorListener());
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return detector.onTouchEvent(event);
}
});
setClickable(true);//允许点击
}
class MyGestureDetectorListener extends GestureDetector.SimpleOnGestureListener{
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
Toast.makeText(getContext(),"双击",Toast.LENGTH_SHORT).show();
startDoubleTapAnimation();//
return super.onDoubleTap(e);
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
Toast.makeText(getContext(),"单击",Toast.LENGTH_SHORT).show();
isSingleTag=true;
currentProgress=progress;
startSingleTapAnimation();
return super.onSingleTapConfirmed(e);
}
}
//单击加速球
private void startSingleTapAnimation() {
handler.postDelayed(singleTapRunnable,200);
}
private SingleTapRunnable singleTapRunnable=new SingleTapRunnable();
class SingleTapRunnable implements Runnable{
@Override
public void run() {
count--;
if (count>=0){
invalidate();
handler.postDelayed(singleTapRunnable,200);
}else {
handler.removeCallbacks(singleTapRunnable);
count=50;
}
}
}
private void startDoubleTapAnimation() {
handler.postDelayed(doubleTapRunnable,50);
}
private DoubleTapRunnable doubleTapRunnable=new DoubleTapRunnable();
class DoubleTapRunnable implements Runnable{
@Override
public void run() {
currentProgress++;
if (currentProgress<=progress){
invalidate();
handler.postDelayed(doubleTapRunnable,50);
}else {
handler.removeCallbacks(doubleTapRunnable);
currentProgress=0;
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width, height);
}
/**
* 自定义绘制一个圆形进度条和动画效果
* @param canvas the canvas on which the background will be drawn
*/
@Override
protected void onDraw(Canvas canvas) {
bitmapCanvas.drawCircle(width/2,height/2,width/2,circlePaint);//1.绘制一个圆
path.reset();//2.绘制新的路径
float y = (1 - (float) currentProgress / max) * height;
path.moveTo(width,y);//3.当前点移动到视图的最右侧
path.lineTo(width,height);//绘制一条线到视图的右下角
path.lineTo(0,height);//绘制一条线到视图的左下角
path.lineTo(0,y);//绘制一条线回到起始y坐标
if (!isSingleTag){
float d = (1 - ((float) currentProgress / progress)) * 10;//4.计算波浪路径的偏移量
for (int i = 0; i < 5; i++) {//表示的是波浪
path.rQuadTo(10,-d,20,0);
path.rQuadTo(10,d,20,0);
}
}else {
float d=(float) count/50*10;//根据count的值计算偏移量
if (count%2==0){
for (int i = 0; i < 5; i++) {
path.rQuadTo(20,-d,40,0);//绘制反向的二次贝塞尔曲线
path.rQuadTo(20,d,40,0);//绘制正向的二次贝塞尔曲线
}
}else {
for (int i = 0; i < 5; i++) {
path.rQuadTo(20,d,40,0);
path.rQuadTo(20,-d,40,0);
}
}
}
path.close();//
bitmapCanvas.drawPath(path,progressPaint);//画笔在bitmapCanvas画布上绘制路径
String text=(int)(((float)currentProgress/max)*100)+"%";//计算进度百分比,并转换成字符串
float textWidth = textPaint.measureText(text);//测量文本宽度
Paint.FontMetrics metrics = textPaint.getFontMetrics();//获取文本的度量信息
float baseLine = height / 2 - (metrics.ascent + metrics.descent) / 2;//计算文本基线位置,确保文本
bitmapCanvas.drawText(text,width/2-textWidth/2,baseLine,textPaint);//绘制文本,位置居中
canvas.drawBitmap(bitmap,0,0,null);//将bitmapCanvas上的绘制结果绘制到主界面
}
第二步.在底部菜单栏显示加速球FloatMenuView
FloatViewManager
类代码如下(示例):
public int getStateHeight(){
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object o = c.newInstance();
Field field = c.getField("status_bar_height");
int x = (int) field.get(o);
return context.getResources().getDimensionPixelSize(x);
} catch (Exception e) {
return 0;
}
}
/**
* 加速球的显示
*/
private void showFloatMenuView() {
WindowManager.LayoutParams params=new WindowManager.LayoutParams();
params.width=getScreenWidth();
params.height=getScreenHeight()-getStateHeight();
params.gravity=Gravity.BOTTOM | Gravity.LEFT;
params.x=0;
params.y=0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else if (Build.VERSION.SDK_INT > 24) {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
} else {
params.type = WindowManager.LayoutParams.TYPE_TOAST;
}
params.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.format= PixelFormat.RGBA_8888;
wm.addView(floatMenuView,params);
}
---
注:本项目内容尚未完全,后续会根据自己的实际情况进行修改和补充>
项目地址:360加速球