天天看点

Android使用WindowManager在界面添加一个悬浮框

项目中需要在一个service里面显示一个悬浮框,刚开始用一个对话框,但是对话框有背景,而且对话框不好控制,后来使用WindowManger实现需求。

需求是:A项目有一个service用来监听用户说的话;B项目就一个界面,基本设置的

要是实现,B项目界面启动,调用A的service来监听用户说的话,所以要在service上悬浮一个标志,代表目前是监听用户说话,还是未监听状态;并且实现悬浮框随意移动。

实现步骤:

1,先自己定义了一个布局类作为悬浮的视图;

代码:

public class ForewarnLayout extends RelativeLayout {
    private float mTouchX;
    private float mTouchY;
    private float x;
    private float y;
    private float mStartX;
    private float mStartY;

    // 窗口视图
    private WindowManager mWindowManager;
    private WindowManager.LayoutParams mLayoutParams;
    private OnClickListener mOnClickListener;
    //语音图片
    private ImageView voiceBtn = null;
    private View mView = null;
    private static int sign = ;

    public ForewarnLayout(Context context) {
        super(context);

        WindowManager.LayoutParams myparams = new WindowManager.LayoutParams();
        myparams.height = LayoutParams.WRAP_CONTENT;
        myparams.width = LayoutParams.WRAP_CONTENT;
        this.setLayoutParams(myparams);

        // 加载布局
        LayoutInflater lf = LayoutInflater.from(context);
        mWindowManager = (WindowManager) context.getApplicationContext()
                .getSystemService(Context.WINDOW_SERVICE);
        mLayoutParams = new WindowManager.LayoutParams();
        mView = lf.inflate(R.layout.forewarn_layout, null);
        this.addView(mView, myparams);

        voiceBtn = (ImageView) findViewById(R.id.serviceVoiceBtn);
    }

    /**
     * tounch事件
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 获取到状态栏的高度
        Rect frame = new Rect();
        getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
        System.out.println("statusBarHeight:" + statusBarHeight);
        // 获取相对屏幕的坐标,即以屏幕左上角为原点
        x = event.getRawX();
        y = event.getRawY() - statusBarHeight; // statusBarHeight是系统状态栏的高度
        Log.i("tag", "currX" + x + "====currY" + y);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: // 捕获手指触摸按下动作
            // 获取相对View的坐标,即以此View左上角为原点
            mTouchX = event.getX();
            mTouchY = event.getY();
            mStartX = x;

            mStartY = y;
            Log.i("tag", "startX" + mTouchX + "====startY" + mTouchY);
            break;

        case MotionEvent.ACTION_MOVE: // 捕获手指触摸移动动作
            updateViewPosition();
            break;

        case MotionEvent.ACTION_UP: // 捕获手指触摸离开动作
            updateViewPosition();
            mTouchX = mTouchY = ;
            if ((x - mStartX) <  && (y - mStartY) < ) {
                // 设置监听
                if (mOnClickListener != null) {
                    mOnClickListener.onClick(this);
                }
            }
            break;
        }
        return true;
    }

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

    // 获取界面布局参数对象
    public WindowManager.LayoutParams getLayoutParams() {
        return mLayoutParams;
    }

    // 设置界面布局参数
    public void setWmParams(WindowManager.LayoutParams layoutParams) {
        mLayoutParams = layoutParams;
    }

    // 界面点击事件监听
    @Override
    public void setOnClickListener(OnClickListener listener) {
        mOnClickListener = listener;
    }

    /**
     * 设置语音浮动按钮状态
     * 
     * @param type
     */
    public void setVoiceBtnType(int type) {
        // 录音
        if (type == ) {
            voiceBtn.setImageResource(R.drawable.voice_bar_click_ok_pressed);
            // 暂停录音
        } else if (type == ) {
            voiceBtn.setImageResource(R.drawable.voice_bar_click_normal);
        }
    }

}
           

2,service里面写了一个创建悬浮视图的方法

private WindowManager mwWindowManager = null;
private ForewarnLayout mForewarnLayout;
/**
     * 浮动框视图
     */
    private void createForewarnLayout() {

        mForewarnLayout = new ForewarnLayout(getApplicationContext());
        // 浮动视图点击事件
        mForewarnLayout.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        // 获取window管理对象
        mwWindowManager = (WindowManager) getApplicationContext()
                .getSystemService(Context.WINDOW_SERVICE);
        // 设置布局参数
        LayoutParams forewarnLayoutParams = mForewarnLayout.getLayoutParams();
        forewarnLayoutParams.type = LayoutParams.TYPE_PHONE; // 设置window TYPE
        forewarnLayoutParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果位背景透明
        // 设置Window flag
        forewarnLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
                | LayoutParams.FLAG_NOT_FOCUSABLE;
        forewarnLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; //
        // 调整悬浮窗口至左上角,便于调整坐标
        // 以屏幕左上角为原点,设置X y初始值
        forewarnLayoutParams.x = ;
        forewarnLayoutParams.y = ;
        // 设置悬浮窗口长宽数据
        forewarnLayoutParams.width = LayoutParams.WRAP_CONTENT;
        forewarnLayoutParams.height = LayoutParams.WRAP_CONTENT;
        // forewarnLayoutParams.windowAnimations = R.style.anim_view;// 添加进入动画
        // 添加布局视图
        mwWindowManager.addView(mForewarnLayout, forewarnLayoutParams);
    }
           

3,然后在service的onbind方法调用createForewarnLayout()方法,

service销毁需要移除视图,

// 移除浮动框
        if (mwWindowManager != null) {
            mwWindowManager.removeView(mForewarnLayout);
        }
           

终结:WindowManager Android窗口管理类,可以理解为当前的屏幕,可以对视图添加,删除等处理。