登录
  • 欢迎访问 Sharezer Blog

Android 悬浮吸附窗口

Android sharezer 2914次浏览 已收录 2个评论

效果图如下:

Android 悬浮吸附窗口

package com.wangsu.tplibrary.ui;

import android.content.Context;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;

import com.sharezer.util.L;
import com.sharezer.util.ScreenUtils;
import com.wangsu.tplibrary.R;

/**
 * Created by sharezer on 2017/5/20.
 */

public class FloatView extends LinearLayout {

    private float mTouchX;
    private float mTouchY;
    private float x;
    private float y;
    private int startX;
    private int startY;
    private Context mContext;
    private int controlledSpace = 20;
    private int screenWidth;
    boolean isShow = false;
    View downloadView;
    private View.OnClickListener mClickListener;

    private WindowManager windowManager;

    private WindowManager.LayoutParams windowManagerParams = new WindowManager.LayoutParams();

    public FloatView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FloatView(Context context) {
        super(context);
        mContext = context;
        initView(context);
    }

    // 初始化窗体
    public void initView(Context context) {
        windowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        screenWidth = ScreenUtils.getScreenWidth(context);
        LayoutInflater.from(context).inflate(R.layout.view_float, this);
        downloadView = findViewById(R.id.btn_download);
        windowManagerParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        windowManagerParams.format = PixelFormat.RGBA_8888; // 背景透明
        windowManagerParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        // 调整悬浮窗口至左上角,便于调整坐标
        windowManagerParams.gravity = Gravity.LEFT | Gravity.TOP;
        // 以屏幕左上角为原点,设置x、y初始值
        windowManagerParams.x = screenWidth;
        windowManagerParams.y = 0;
        // 设置悬浮窗口长宽数据
        windowManagerParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        windowManagerParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
//        this.setLayoutParams(windowManagerParams);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        //获取到状态栏的高度
        int statusBarHeight = ScreenUtils.getStatusHeight(mContext);
        // 获取相对屏幕的坐标,悬浮窗口所在的位置
        x = event.getRawX();
        y = event.getRawY() - statusBarHeight;


        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mTouchX = event.getX();
                mTouchY = event.getY();
                startX = (int) event.getRawX();
                startY = (int) event.getRawY();
                break;

            }
            case MotionEvent.ACTION_MOVE: {
                updateViewPosition();
                break;
            }
            case MotionEvent.ACTION_UP: {
//                if (Math.abs(x - startX) < controlledSpace && Math.abs(y - startY + statusBarHeight) < controlledSpace) {
//                    if (mClickListener != null) {
//                        mClickListener.onClick(this);
//                    }
//                }
                if(inRangeOfView(downloadView, event))
                {
                    if(mClickListener != null) mClickListener.onClick(this);
                }

                L.i("x=" + x + " startX+" + startX + " y=" + y + " startY=" + startY);
                if (x <= screenWidth / 2) {
                    x = 0;
                } else {
                    x = screenWidth;
                }
                updateViewPosition();

                break;
            }
        }

        return super.onTouchEvent(event);
    }

    private boolean inRangeOfView(View view, MotionEvent ev){
        int[] location = new int[2];
        view.getLocationInWindow(location);
        int x = location[0];
        int y = location[1];
        if(ev.getX() < x || ev.getX() > (x + view.getWidth()) || ev.getY() < y || ev.getY() > (y + view.getHeight())){
            return false;
        }
        return true;
    }

    // 隐藏该窗体
    public void hide() {
        if (isShow) {
            windowManager.removeView(this);
            isShow = false;
        }

    }

    // 显示该窗体
    public void show() {
        if (isShow == false) {
            windowManager.addView(this, windowManagerParams);
            isShow = true;
        }

    }

    public boolean isShow() {return isShow;}

    @Override
    public void setOnClickListener(OnClickListener l) {
        this.mClickListener = l;
    }

    private void updateViewPosition() {
        // 更新浮动窗口位置参数
        windowManagerParams.x = (int) (x - mTouchX);
        windowManagerParams.y = (int) (y - mTouchY);
        windowManager.updateViewLayout(this, windowManagerParams); // 刷新显示
    }
}

使用的时候

FloatView floatView = new FloatView(this); // 创建窗体
floatView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        L.e("click");
    }
}); // 设置事件,你需要实现FloatView里的onclick接口
floatView.show(); // 显示该窗体

记得添加权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />


Sharezer , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Android 悬浮吸附窗口
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 横屏后是不是需要拖拽才会吸附,横屏那一下是不是不会吸附,望回复
    小小范同学2020-12-06 23:58 回复 未知操作系统 | 未知浏览器
    • sharezer
      没有实现横屏自动切换,可以监听一下Settings.System.ACCELEROMETER_ROTATION广播,收到广播后刷新一下位置。
      sharezer2020-12-22 09:45 回复 未知操作系统 | 未知浏览器