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

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记得解除注册啊!!我深有体会[尴尬]
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android桌面悬浮窗是一种在Android手机或平板电脑的桌面显示的浮动窗口。它可以在其他应用程序之上显示,并且可以在用户使用其他应用程序时保持可见。悬浮窗可以用来显示通知、快捷操作、实时信息等等,为用户提供更方便的操作和查看方式。 要实现Android桌面悬浮窗,你可以使用Android的WindowManager类。首先,你需要在你的应用程序中声明SYSTEM_ALERT_WINDOW权限,以便能够在其他应用程序之上显示悬浮窗。然后,你可以使用WindowManager来创建和管理悬浮窗。 以下是一个简单的示例代码,演示如何创建一个简单的悬浮窗: ```java // 获取WindowManager对象 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); // 创建一个悬浮窗口布局参数 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); // 设置悬浮窗口类型为系统级别的窗口 layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // 设置悬浮窗口的宽高 layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; // 设置悬浮窗口的位置 layoutParams.gravity = Gravity.TOP | Gravity.LEFT; layoutParams.x = 100; layoutParams.y = 100; // 创建一个ImageView作为悬浮窗口的内容 ImageView imageView = new ImageView(this); imageView.setImageResource(R.drawable.icon); // 将ImageView添加到悬浮窗口中 windowManager.addView(imageView, layoutParams); ``` 以上代码创建了一个包含一个图标的悬浮窗口,并将其添加到屏幕上。你可以根据自己的需求修改悬浮窗口的内容和样式。记得在不需要悬浮窗口时,调用`windowManager.removeView(imageView)`来移除悬浮窗口。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值