文章目录
一 需求
实现类似微信聊天的悬浮框效果,加载在Activity页面之上,可以用来做一个唯一的强制操作
二 API
- WindowManager的addView和removeView实现
三 注意事项
1 权限获取
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
动态权限判断
if (!Settings.canDrawOverlays(this)) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
}else{
showView();
}
2 LayoutParams
private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();
3 不能重复定义LayoutParams
四 代码实现
1 MyApplication
public class MyApplication extends Application {
/**
* 创建全局变量
* 全局变量一般都比较倾向于创建一个单独的数据类文件,并使用static静态变量
*
* 这里使用了在Application中添加数据的方法实现全局变量
* 注意在AndroidManifest.xml中的Application节点添加android:name=".MyApplication"属性
*
*/
private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();
public WindowManager.LayoutParams getMywmParams(){
return wmParams;
}
}
2 FloatView
public class FloatView extends View {
private float mTouchStartX;
private float mTouchStartY;
private float x;
private float y;
private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
private WindowManager.LayoutParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();
public FloatView(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//获取相对屏幕的坐标,即以屏幕左上角为原点
x = event.getRawX();
y = event.getRawY()-25; //25是系统状态栏的高度
Log.i("currP", "currX"+x+"====currY"+y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//获取相对View的坐标,即以此View左上角为原点
mTouchStartX = event.getX();
mTouchStartY = event.getY();
Log.i("startP", "startX"+mTouchStartX+"====startY"+mTouchStartY);
break;
case MotionEvent.ACTION_MOVE:
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
updateViewPosition();
mTouchStartX=mTouchStartY=0;
break;
}
return true;
}
private void updateViewPosition(){
//更新浮动窗口位置参数
wmParams.x=(int)( x-mTouchStartX);
wmParams.y=(int) (y-mTouchStartY);
wm.updateViewLayout(this, wmParams);
}
}
3 FloatingWindowActivity
public class FloatingWindowActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 101;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.floating_window_activity);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(REQUEST_CODE == requestCode){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
} else{
showView();
}
}
}
}
public void start(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
}else{
showView();
}
}else{
showView();
}
}
private void addView(){
// 获取WindowManager服务
final WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// 新建悬浮窗
// 控件
final Button button = new Button(getApplicationContext());
button.setText("Floating Window");
button.setBackgroundColor(Color.BLUE);
// 设置LayoutParam
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.width = 500;
layoutParams.height = 100;
layoutParams.x = 300;
layoutParams.y = 300;
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
windowManager.removeView(button);
// startActivity(new Intent(MainActivity.this,SecondActivity.class));
}
});
// 将悬浮窗控件添加到WindowManager
windowManager.addView(button, layoutParams);
}
private WindowManager mWindowManager;
private WindowManager.LayoutParams param;
private List<FloatView> list = new ArrayList<>();
private void showView(){
FloatView mLayout=new FloatView(getApplicationContext());
mLayout.setBackgroundColor(Color.RED);
//获取WindowManager
mWindowManager=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//设置LayoutParams(全局变量)相关参数
param = ((MyApplication)getApplication()).getMywmParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
param.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
param.type = WindowManager.LayoutParams.TYPE_PHONE;
}
param.format=1;
param.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 不能抢占聚焦点
param.flags = param.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
param.flags = param.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; // 排版不受限制
param.alpha = 1.0f;
param.gravity= Gravity.LEFT|Gravity.TOP; //调整悬浮窗口至左上角
//以屏幕左上角为原点,设置x、y初始值
param.x=0;
param.y=0;
//设置悬浮窗口长宽数据
param.width=140;
param.height=140;
//显示myFloatView图像
mWindowManager.addView(mLayout, param);
list.add(mLayout);
}
@Override
protected void onDestroy() {
for(View v:list){
mWindowManager.removeView(v);
}
super.onDestroy();
}
}