Android仿微信文章悬浮窗效果

转自:https://mp.weixin.qq.com/s/vABThLqH-7s0Aj9cDiw0Vw

序言

前些日子跟朋友聊天,朋友Z果粉,前些天更新了微信,说微信出了个好方便的功能啊,
我问是啥功能啊,看看我大Android有没有,他说现在阅读公众号文章如果有人给你发微
信你可以把这篇文章当作悬浮窗悬浮起来,方便你聊完天不用找继续阅读,听完是不是觉
得这叫啥啊,我大Android微信版不是早就有这个功能了吗,我看文章的时候看到过有这
个悬浮按钮,但是我一直没有使用过,试了一下还是挺方便的,就想着自己实现一下这个
功能,下面看图,大家都习惯了无图言X
在这里插入图片描述

原理

看完动图我们来分析一下,如何在每个页面上都存在一个View呢,有些人可能会说,写
在base里面,这样每次启动一个新的Activity都要往页面上addView一次,性能不好,再
说了,我们作为一个优秀的程序员能干这种重复的事吗,这种方案果断打回去;既然这样
的话那我们肯定要在全局加了,那么全局是哪呢?相信了解过Activity源码的朋友肯定知
道,全局可以在Window层加啊,这样既能一次性搞定,又不影响性能,说干就干。

实现
1、权限

首先我们要考虑的一个问题就是权限问题,因为要适配Android 7.0 8.0,添加悬浮窗是需
要申请权限的,这里参考了Android 悬浮窗权限各机型各系统适配大全这篇文章,适配的
比较全,可以直接拿来用。这里需要注意的是,为了适配Android 8.0,Window的类型需要配置一下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  //Android 8.0
	mLayoutParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
 //其他版本
	mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

2、添加ViewGroup到Window

判断好权限之后,直接添加就可以了

 @SuppressLint("CheckResult")
    private void showWindow(Context context) {
    	mWindowManager = (WindowManager) 				
    	context.getSystemService(WINDOW_SERVICE);
    	mView = LayoutInflater.from(context).inflate(R.layout.article_window, null);

        ImageView ivImage = mView.findViewById(R.id.aw_iv_image);
        String imageUrl = SPUtil.getStringDefault(ARTICLE_IMAGE_URL, "");
        RequestOptions requestOptions = RequestOptions.circleCropTransform();
        requestOptions.placeholder(R.mipmap.ic_launcher_round).error(R.mipmap.ic_launcher_round);
        Glide.with(context).load(imageUrl).apply(requestOptions).into(ivImage);

        initListener(context);

        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_SYSTEM_ALERT;
        }
        mLayoutParams.format = PixelFormat.RGBA_8888;   //窗口透明
        mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;  //窗口位置
        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        mLayoutParams.width = 200;
        mLayoutParams.height = 200;
        mLayoutParams.x = mWindowManager.getDefaultDisplay().getWidth() - 200;
        mLayoutParams.y = 0;
        mWindowManager.addView(mView, mLayoutParams);
    }

3、View的拖拽实现

借助WindowManager.LayoutParams来实现,mLayoutParams.x和mLayoutParams.y分别
表示mView左上角的横纵坐标,所以我们只需要改动这两个值就行了,当ACTION_UP
时,计算当前mView的中心点相对窗口的位置,然后将mView动态滑动到窗口左边或者右
边:

  //设置触摸滑动事件
mView.setOnTouchListener(new View.OnTouchListener()

    {
        int startX, startY;  //起始点
        boolean isMove;  //是否在移动
        long startTime;
        int finalMoveX;  //最后通过动画将mView的X轴坐标移动到finalMoveX

        @Override
        public boolean onTouch (View v, MotionEvent event){
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) event.getX();
                startY = (int) event.getY();
                startTime = System.currentTimeMillis();
                isMove = false;
                return false;
            case MotionEvent.ACTION_MOVE:
                mLayoutParams.x = (int) (event.getRawX() - startX);
                mLayoutParams.y = (int) (event.getRawY() - startY);
                updateViewLayout();   //更新mView 的位置
                return true;
            case MotionEvent.ACTION_UP:
                long curTime = System.currentTimeMillis();
                isMove = curTime - startTime > 100;

//判断mView是在Window中的位置,以中间为界
                if (mLayoutParams.x + mView.getMeasuredWidth() / 2 >= mWindowManager.getDefaultDisplay().getWidth() / 2) {
                    finalMoveX = mWindowManager.getDefaultDisplay().getWidth() - mView.getMeasuredWidth();
                } else {
                    finalMoveX = 0;
                }

//使用动画移动mView
                ValueAnimator animator = ValueAnimator.ofInt(mLayoutParams.x, finalMoveX).setDuration(Math.abs(mLayoutParams.x - finalMoveX));
                animator.addUpdateListener((ValueAnimator animation) -> {
                    mLayoutParams.x = (int) animation.getAnimatedValue();
                    updateViewLayout();
                });
                animator.start();

                return isMove;
        }
        return false;
    }
    });

4、注意

为了让Window与Activity脱离,这里我们采用Service来做,通过Service来添加和移除
View;在权限申请成功之后我们需要通知Service(其实是Activity,可能会有保存数据等
操作)作相应改变(提供一个接口给Service),然后在Service中使用广播来通知
Activity;最后一个需要注意的地方就是我们需要判断应用程序是否在前台还是后台来添
加或移除Window,这里通过使用ActivityLifecycleCallbacks来监听Activity在前台的数量
来判断应用程序是在前台还是后台

  class ApplicationLifecycle :Application.ActivityLifecycleCallbacks

{

    private var started:Int = 0

    override fun onActivityPaused(activity:Activity ?){
}

    override fun onActivityResumed(activity:Activity ?){
}

    override fun onActivityStarted(activity:Activity ?){
    started++
    if (started == 1) {
        Log.e("TAG", "应用在前台了!!!")
    }
}

    override fun onActivityDestroyed(activity:Activity ?){
}

    override fun onActivitySaveInstanceState(activity:Activity ?, outState:Bundle ?){
}

    override fun onActivityStopped(activity:Activity ?){
    started--
    if (started == 0) {
        Log.e("TAG", "应用在后台了!!!")
    }
}

    override fun onActivityCreated(activity:Activity ?, savedInstanceState:Bundle ?){
}
}

本文代码
CSDN:https://download.csdn.net/download/m0_38048084/10713037
Github:https://github.com/24Kshign/SuspensionWindow
有需要的朋友可以下载下来看看。
参考

https://blog.csdn.net/mai763727999/article/details/78983375/

https://blog.csdn.net/self_study/article/details/52859790

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您!要实现仿微信视频通话悬浮窗功能,您可以按照以下步骤进行操作: 1. 创建悬浮窗权限:在 AndroidManifest.xml 文件中添加悬浮窗权限声明,如下所示: ```xml <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> ``` 2. 创建悬浮窗服务:创建一个继承自 Service 的类,用于管理悬浮窗的创建、更新和移除等操作。在该类中,您可以使用 WindowManager 来显示悬浮窗,并监听触摸事件来实现拖拽和缩放等操作。 3. 设计悬浮窗布局:创建一个 XML 布局文件,用于定义悬浮窗的界面。您可以自定义界面元素,如视频画面、控制按钮等。 4. 实现悬浮窗功能:在悬浮窗服务类中,根据需要添加相应的逻辑。例如,您可以使用 MediaProjection API 来捕获屏幕内容,并将其显示在悬浮窗中;您还可以使用 Camera API 来获取摄像头数据,并实现视频通话功能。 5. 添加权限申请逻辑:在需要使用悬浮窗功能的地方,添加权限申请逻辑,以确保用户在安装应用时授予悬浮窗权限。 请注意,实现仿微信视频通话悬浮窗功能需要一定的 Android 开发知识和经验。如果您对 Android 开发不太熟悉,建议您先学习相关的基础知识,然后再尝试实现该功能。同时,还要注意遵守 Android 官方的开发规范和安全要求。希望对您有所帮助!如果您有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值