此代码只能应用于 版本号19以上的手机
悬浮窗的关键是 :WindowManager 以下列出了 button ,Imageview,SurfaceView(视频) 三种悬浮窗
要想悬浮窗不影响到其他应用的使用 需要将 WindowManager 的 LayoutParams flag 参数设置成以下的模式
// 设置LayoutParam mLayoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } mLayoutParams.flags = mLayoutParams.FLAG_NOT_TOUCH_MODAL | mLayoutParams.FLAG_NOT_FOCUSABLE | mLayoutParams.FLAG_FULLSCREEN | mLayoutParams.FLAG_LAYOUT_IN_SCREEN;
设置权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
检查是否设置了权限,因为可以再其他应用之上使用 所以需要通过服务来控制悬浮窗
@RequiresApi(api = Build.VERSION_CODES.M) public void startFloatingService(View view) { if(!Settings.canDrawOverlays(this)){ Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT).show(); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:"+getPackageName())),0); } else { startService(new Intent(FloatActivity.this, FloatServices.class)); } }
具体代码如下 Activity:
package com.example.android.recycleautocarousel; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.support.annotation.RequiresApi; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; import com.example.android.recycleautocarousel.services.FloatServices; public class FloatActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_float); } @RequiresApi(api = Build.VERSION_CODES.M) public void startFloatingService(View view) { if(!Settings.canDrawOverlays(this)){ Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT).show(); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:"+getPackageName())),0); } else { startService(new Intent(FloatActivity.this, FloatServices.class)); } } @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 0) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show(); startService(new Intent(FloatActivity.this, FloatServices.class)); } } } }
Service:
package com.example.android.recycleautocarousel.services; import android.app.Service; import android.content.Intent; import android.graphics.Color; import android.graphics.PixelFormat; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.IBinder; import android.provider.Settings; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import com.example.android.recycleautocarousel.R; import java.io.IOException; /** * Created by android on 2018/6/22. */ public class FloatServices extends Service { private Button mButton; private WindowManager mWindowManager; private WindowManager.LayoutParams mLayoutParams; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { showFloatingWindow(); return super.onStartCommand(intent, flags, startId); } private class FloatingOnTouchListener implements View.OnTouchListener{ private int x; private int y; @Override public boolean onTouch(View v, 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(); int movedX = nowX - x; int movedY = nowY - y; x = nowX; y = nowY; mLayoutParams.x = mLayoutParams.x + movedX; mLayoutParams.y = mLayoutParams.y + movedY; // 更新悬浮窗控件布局 mWindowManager.updateViewLayout(v, mLayoutParams); break; default: break; } return false; } } /** * 悬浮窗口 视屏 */ private void showFloatingWindow() { if (Settings.canDrawOverlays(this)) { mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater layoutInflater = LayoutInflater.from(this); View displayView = layoutInflater.inflate(R.layout.image_display, null); displayView.setOnTouchListener(new FloatingOnTouchListener()); // 获取WindowManager服务 final MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); SurfaceView surfaceView = displayView.findViewById(R.id.video_display_surfaceview); final SurfaceHolder surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { mediaPlayer.setDisplay(surfaceHolder); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } }); try { mediaPlayer.setDataSource(this, Uri.parse("https://raw.githubusercontent.com/dongzhong/ImageAndVideoStore/master/Bruno%20Mars%20-%20Treasure.mp4")); mediaPlayer.prepareAsync(); } catch (IOException e) { Toast.makeText(this, "无法打开视频源", Toast.LENGTH_LONG).show(); } // 设置LayoutParam mLayoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } // flag参数必须设置 不然有悬浮窗 但其他应用也无法使用 mLayoutParams.flags = mLayoutParams.FLAG_NOT_TOUCH_MODAL | mLayoutParams.FLAG_NOT_FOCUSABLE | mLayoutParams.FLAG_FULLSCREEN | mLayoutParams.FLAG_LAYOUT_IN_SCREEN; mLayoutParams.format = PixelFormat.RGBA_8888; mLayoutParams.width = 300; mLayoutParams.height = 300; mLayoutParams.x = 300; mLayoutParams.y = 300; // 将悬浮窗控件添加到WindowManager mWindowManager.addView(displayView, mLayoutParams); } } /** * 悬浮窗口Imageview */ private void showFloatingWindow2() { if (Settings.canDrawOverlays(this)) { // 获取WindowManager服务 mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater layoutInflater = LayoutInflater.from(this); View displayView = layoutInflater.inflate(R.layout.image_display, null); displayView.setOnTouchListener(new FloatingOnTouchListener()); ImageView imageView = displayView.findViewById(R.id.image_display_imageview); imageView.setImageResource(R.drawable.item1); // 设置LayoutParam mLayoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } // flag参数必须设置 不然有悬浮窗 但其他应用也无法使用 mLayoutParams.flags = mLayoutParams.FLAG_NOT_TOUCH_MODAL | mLayoutParams.FLAG_NOT_FOCUSABLE | mLayoutParams.FLAG_FULLSCREEN | mLayoutParams.FLAG_LAYOUT_IN_SCREEN; mLayoutParams.format = PixelFormat.RGBA_8888; mLayoutParams.width = 100; mLayoutParams.height = 100; mLayoutParams.x = 300; mLayoutParams.y = 300; // 将悬浮窗控件添加到WindowManager mWindowManager.addView(displayView, mLayoutParams); } } /** * 悬浮窗口button */ private void showFloatingWindow1() { if (Settings.canDrawOverlays(this)) { // 获取WindowManager服务 mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); // 新建悬浮窗控件 mButton = new Button(getApplicationContext()); mButton.setText("Floating Window"); mButton.setBackgroundColor(Color.BLUE); // 设置LayoutParam mLayoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } // flag参数必须设置 不然有悬浮窗 但其他应用也无法使用 mLayoutParams.flags = mLayoutParams.FLAG_NOT_TOUCH_MODAL | mLayoutParams.FLAG_NOT_FOCUSABLE | mLayoutParams.FLAG_FULLSCREEN | mLayoutParams.FLAG_LAYOUT_IN_SCREEN; mLayoutParams.format = PixelFormat.RGBA_8888; mLayoutParams.width = 500; mLayoutParams.height = 100; mLayoutParams.x = 300; mLayoutParams.y = 300; // 将悬浮窗控件添加到WindowManager mWindowManager.addView(mButton, mLayoutParams); } } }
activity_float.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_float" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.android.recycleautocarousel.FloatActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="nihao " android:onClick="startFloatingService" /> </RelativeLayout>
image_display.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:visibility="gone" android:id="@+id/image_display_imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <SurfaceView android:id="@+id/video_display_surfaceview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
打完收工