android创建可拖动的悬浮窗,并实现点击回调
来源:互联网 发布:淘宝网延长收货时间 编辑:程序博客网 时间:2024/06/06 05:52
最近用到悬浮窗的功能,android6.0以下的系统可以进行正常的显示,而android6.0及以上的则创建不了,运行直接崩溃,报如下错误:
Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@96872e8 -- permission denied for this window type
但是我在清单文件明明加了<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />这个权限,为什么还是不行呢?原因是自从android6.0之后,权限改了,权限的授权不是在应用第一次安装时对所有的权限进行授权,而是在需要用到某个权限时对其动态授权。
查看android的官方文档:Note:If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen. The app requests the user's approval by sending an intent with action ACTION_MANAGE_OVERLAY_PERMISSION . The app can check whether it has this authorization by calling Settings.canDrawOverlays() .
能够熟练阅读各类英文文档也是一门非常重要的技能。上面的描述大概意思就是说,如果我们的 targetSdkVersion指定成了23或者更高,在使用 SYSTEM_ALERT_WINDOW权限时,需要先调用 Settings.canDrawOverlays() 来判断一下是否允许创建悬浮窗,如果允许的话就可以创建了,不允许的话还要发送一个action值为 ACTION_MANAGE_OVERLAY_PERMISSION 的Intent来让用户同意创建悬浮窗。
先上效果图:
那下面就这样试着写一下,代码如下:
package com.cool.floatviewdemo;import android.annotation.TargetApi;import android.app.Activity;import android.content.Intent;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.util.Log;import android.view.View;import android.widget.Toast;public class MainActivity extends Activity { private final static int REQUEST_CODE = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void callPhone(View v){ startActivity(new Intent(this, CallPhoneActivity.class)); } /** *显示悬浮窗 * @param v */ public void showFloatView(View v) { if (Build.VERSION.SDK_INT >= 23) { if (Settings.canDrawOverlays(this)) { showFloatView(); } else { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivityForResult(intent, REQUEST_CODE); } } else { showFloatView(); } } @TargetApi(Build.VERSION_CODES.M) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == REQUEST_CODE){ if (Settings.canDrawOverlays(this)) { showFloatView(); } else { Toast.makeText(this,"授权失败",Toast.LENGTH_SHORT).show(); } } } /** * 显示悬浮窗 */ private void showFloatView() { FloatView.showFloatView(getApplication(), R.layout.layout_float_window); FloatView.setOnClickListener(new FloatView.OnClickListener() { @Override public void onClick(View view) { Log.e("399", "点击了"); } }); } /** * 隐藏悬浮窗 * @param v */ public void hideFloatView(View v){ FloatView.hideFloatView(); }}
悬浮窗的View如下:
package com.cool.floatviewdemo;import android.content.Context;import android.graphics.PixelFormat;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;/** * Created by cool on 2016/8/30. */public class FloatView { private static Context mContext; private static WindowManager mWindowManager; private static WindowManager.LayoutParams wmParams; private static View mView; private static boolean isShow = false;//悬浮框是否已经显示 private static OnClickListener mListener;//view的点击回调listener public static void setOnClickListener(OnClickListener listener){ mListener = listener; } interface OnClickListener{ void onClick(View view); } /** * 显示悬浮框 */ public static void showFloatView(Context context,int layoutId){ mContext = context; if(isShow){ return; } mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); wmParams = new WindowManager.LayoutParams(); wmParams.type = WindowManager.LayoutParams.TYPE_PHONE; wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; wmParams.gravity = Gravity.CENTER; wmParams.format = PixelFormat.RGBA_8888; wmParams.x = context.getResources().getDisplayMetrics().widthPixels; wmParams.y = 0; wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mView = LayoutInflater.from(context).inflate(layoutId, null); mWindowManager.addView(mView, wmParams); mView.setOnTouchListener(new View.OnTouchListener() { float downX = 0; float downY = 0; int oddOffsetX = 0; int oddOffsetY = 0; @Override public boolean onTouch(View v, MotionEvent event) { switch(event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); oddOffsetX = wmParams.x; oddOffsetY = wmParams.y; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); //不除以3,拖动的view抖动的有点厉害 wmParams.x += (moveX - downX)/3; wmParams.y += (moveY - downY)/3; if(mView != null){ mWindowManager.updateViewLayout(mView,wmParams); } break; case MotionEvent.ACTION_UP: int newOffsetX = wmParams.x; int newOffsetY = wmParams.y; if(Math.abs(newOffsetX - oddOffsetX) <=20 && Math.abs(newOffsetY - oddOffsetY) <=20){ if(mListener != null){ mListener.onClick(mView); } } break; } return true; } }); isShow = true; } /** * 隐藏悬浮窗 */ public static void hideFloatView(){ if(mWindowManager != null && isShow){ mWindowManager.removeView(mView); isShow = false; } }}
- android创建可拖动的悬浮窗,并实现点击回调
- Android 悬浮并可拖动的实现
- Android 可拖动可点击悬浮窗
- Android在桌面添加可拖动、点击的悬浮窗口
- Android添加可拖动、点击的悬浮窗口
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android 悬浮Activity并可拖动(访悬浮歌词)
- Android可以拖动的悬浮窗实现
- Android 简单实现可全屏拖动,可点击的View
- Android 可随意拖动的悬浮窗体
- Android 可拖动的悬浮按钮
- 可拖动悬浮窗
- iOS 悬浮可拖动可点击按钮
- Leetcode 20 Valid Parentheses
- tabview向下偏移原因及解决办法
- 去掉CodeIgniter(CI)默认url中的index.php
- 深入浅出JMS(一)--JMS基本概念
- RingerMode 设置和勿扰模式关系
- android创建可拖动的悬浮窗,并实现点击回调
- Java 笔记--JAVA transient关键字
- Glide使用
- 深入浅出JMS(二)--ActiveMQ简单介绍以及安装
- iOS中项目的上架流程
- Android学习第十三天---Xposed框架理解
- 一个procedure案例
- spring boot 学习--03---web控制层全局异常处理
- iOS的最小点击区域