android悬浮窗(支持退回桌面后显示)

xiaoxiao2025-09-19  307

1、需求

首先说一下需求吧,看看是不是你们想要的: 在IM音视频聊天页面,点击页面上的最小化按钮,将Activity最小化并开启一个悬浮窗,悬浮窗可拖动可点击,点击进入当前通话页面。

2、思路

1、听到开启悬浮窗,第一时间就想到了要开启一个Service,在Service中进行布局的设置及拖动、点击逻辑的设定。 2、通话界面点击最小化按钮,将Activity最小化并保持后台运行,同时开启Service展示悬浮窗

3、实现

1、创建FloatVideoWindowService继承Service类 2、实现父类抽象方法 3、在onCreate()中进行布局设置,并获得WindowManager对象。 4、在onStartCommand()方法中将布局、参数添加到WindowManager中 5、增加全局变量boolean isStarted记录悬浮窗是否已打开。 6、在onDestroy()中将布局从WindowManager中移除 7、在onStartCommand()中进行控件的点击、拖动监听 8、点击最小化按钮执行moveTaskToBack(true),并启动Service,isStarted = true; 9、onRestart()中关闭Service;

以下是代码

Service.class
import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.graphics.PixelFormat; import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.SystemClock; import android.provider.Settings; import android.support.annotation.Nullable; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.TextView; public class FloatVideoWindowService extends Service { private WindowManager mWindowManager; private WindowManager.LayoutParams wmParams; private LayoutInflater inflater; public static boolean isStarted = false; //view private View mFloatingLayout; //布局View @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); isStarted = true; initWindow(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { showFloatingWindow(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); if (mWindowManager != null) { mWindowManager.removeView(mFloatingLayout); isStarted = false; } } /** * 设置悬浮框基本参数(位置、宽高等) */ private void initWindow() { mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); wmParams = getParams(); inflater = LayoutInflater.from(getApplicationContext()); mFloatingLayout = inflater.inflate(R.layout.layout_window, null); } private WindowManager.LayoutParams getParams() { wmParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; } wmParams.format = PixelFormat.RGBA_8888; //设置可以显示在状态栏上 wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; //这是悬浮窗居中位置 wmParams.gravity = Gravity.LEFT | Gravity.TOP; //70、210是我项目中的位置哦 wmParams.x = 70; wmParams.y = 210; return wmParams; } private void showFloatingWindow() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本 if (Settings.canDrawOverlays(this)) { mFloatingLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class); startActivity(intent); } }); mFloatingLayout.setOnTouchListener(new FloatingListener()); mWindowManager.addView(mFloatingLayout, wmParams); } } else { mFloatingLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class); startActivity(intent); } }); mFloatingLayout.setOnTouchListener(new FloatingListener()); mWindowManager.addView(mFloatingLayout, wmParams); } } private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY; private int mStartX, mStartY, mStopX, mStopY; private boolean isMove; private class FloatingListener implements View.OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: isMove = false; mTouchStartX = (int) event.getRawX(); mTouchStartY = (int) event.getRawY(); mStartX = (int) event.getX(); mStartY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: mTouchCurrentX = (int) event.getRawX(); mTouchCurrentY = (int) event.getRawY(); wmParams.x += mTouchCurrentX - mTouchStartX; wmParams.y += mTouchCurrentY - mTouchStartY; mWindowManager.updateViewLayout(mFloatingLayout, wmParams); mTouchStartX = mTouchCurrentX; mTouchStartY = mTouchCurrentY; break; case MotionEvent.ACTION_UP: mStopX = (int) event.getX(); mStopY = (int) event.getY(); if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) { isMove = true; } break; } return isMove; } } }
Activity.class
private Intent serviceIntent; private static HomeWatcherReceiver mHomeKeyReceiver = null; public void openMinWindow() { if (!FloatVideoWindowService.isStarted) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本 if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0); } else { serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class); startService(serviceIntent); moveTaskToBack(true); } } else { serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class); startService(serviceIntent); moveTaskToBack(true); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 0) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show(); serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class); startService(serviceIntent); moveTaskToBack(true); } } } } @Override protected void onRestart() { super.onRestart(); if (serviceIntent != null) { stopService(serviceIntent); } } //以下为Home键监听,最小化到桌面时也让悬浮窗启动 @Subscribe public void onEvent(String event) { if (event.equals("startService")) { openMinWindow(); } } @Override protected void onResume() { super.onResume(); registerHomeKeyReceiver(this); } @Override protected void onPause() { super.onPause(); unregisterHomeKeyReceiver(this); } private static void registerHomeKeyReceiver(Context context) { mHomeKeyReceiver = new HomeWatcherReceiver(); final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.registerReceiver(mHomeKeyReceiver, homeFilter); } private static void unregisterHomeKeyReceiver(Context context) { if (null != mHomeKeyReceiver) { context.unregisterReceiver(mHomeKeyReceiver); } }
HomeWatcherReceiver.class (手机底部按键监听)
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import de.greenrobot.event.EventBus; /** * PROJECT_NAME:meteor_dog_android * Created by ENZO on 2018/10/19,16:18 * Description: Home键监听 */ public class HomeWatcherReceiver extends BroadcastReceiver { private static final String LOG_TAG = "HomeReceiver"; private static final String SYSTEM_DIALOG_REASON_KEY = "reason"; private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; private static final String SYSTEM_DIALOG_REASON_LOCK = "lock"; private static final String SYSTEM_DIALOG_REASON_ASSIST = "assist"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.i(LOG_TAG, "onReceive: action: " + action); if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); Log.i(LOG_TAG, "reason: " + reason); if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) { //发送通知,启动Service EventBus.getDefault().post("startService"); } else if (SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { // 长按Home键 或者 activity切换键 } else if (SYSTEM_DIALOG_REASON_LOCK.equals(reason)) { // 锁屏 } else if (SYSTEM_DIALOG_REASON_ASSIST.equals(reason)) { // samsung 长按Home键 } } } }

4、注意

4.1: Service记得在AndroidManifest.xml中注册哦
4.2: 6.0以上(23)判断是否有悬浮窗权限请用Settings.canDrawOverlays(this)方法
4.3: 需要添加权限 android.permission.SYSTEM_ALERT_WINDOW
4.4: Eventbus记得解除注册啊!!我深有体会[尴尬]
转载请注明原文地址: https://www.6miu.com/read-5036624.html

最新回复(0)