在APP内实现顶层窗口,悬浮窗功能。

在做一个电台类的app时,需要一个按钮始终显示在最前端,查找了一些博客,都不尽如人意,选择了其中写的比较好的一篇进行了修改,最终满足了需求。

此方法使用的是系统弹窗,由于我这个项目的特殊性,这个控件是无法移动的,且用户三秒不点就会以动画的形式向上移动一半且半透明化,如果不需要这个功能可以直接删除相关代码,这个类内所有功能都有注释,很好修改,我直接整理成了一个工具类,代码如下:

package com.ijia.customview;

import com.ijia.activity.PlayActivity;
import com.ijia.framework.MyApplication;
import com.ijia.util.CommonUtils;
import com.watch.radio.R;

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.CountDownTimer;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Toast;

/**
 * @author 作者 :WY
 * @version 创建时间:2017年8月24日 上午11:40:50 类说明:始终显示在上层的按钮
 */
public class FloatingFunc {

    /**
     * 浮动窗口在屏幕中的x坐标
     */
    private float x = 0;
    /**
     * 浮动窗口在屏幕中的y坐标
     */
    private float y = 0;
    /**
     * 屏幕触摸状态,暂时未使用
     */
    private float state = 0;
    /**
     * 鼠标触摸开始位置
     */
    private float mTouchStartX = 0;
    /**
     * 鼠标触摸结束位置
     */
    private float mTouchStartY = 0;
    /**
     * windows 窗口管理器
     */
    private WindowManager wm = null;

    /**
     * 当前显示状态(全显示还是半显示中) true为全显示
     */
    public boolean isAllDisplay = true;

    /**
     * 参数设定类
     */
    public WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    private int TOOL_BAR_HIGH = 0;
    /**
     * 要显示在窗口最前面的对象
     */
    private View view_obj = null;

    private static class MapUtilsHolder {
        /** 单例对象 */
        static final FloatingFunc instance = new FloatingFunc();
    }

    public static FloatingFunc getInstance() {
        return MapUtilsHolder.instance;
    }

    /** 防止外部实例化 */
    private FloatingFunc() {
    }

    /** readResolve方法应对单例对象被序列化时候 */
    private Object readResolve() {
        return getInstance();
    }

    /**
     * 要显示在窗口最前面的方法
     * 
     * @param context
     *            调用对象Context getApplicationContext()
     * @param window
     *            调用对象 Window getWindow()
     * @param floatingViewObj
     *            要显示的浮动对象 View
     */
    public void show(final Context context, Window window, View floatingViewObj) {
        // 关闭浮动显示对象然后再显示
        close(context);
        view_obj = floatingViewObj;
        Rect frame = new Rect();
        // 这一句是关键,让其在top 层显示
        // getWindow()
        window.getDecorView().getWindowVisibleDisplayFrame(frame);
        TOOL_BAR_HIGH = frame.top;

        wm = (WindowManager) context// getApplicationContext()
                .getSystemService(Activity.WINDOW_SERVICE);
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
        params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
        // 设置悬浮窗口长宽数据
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.RGBA_8888;
        // 设定透明度
        // params.alpha = 100;
        // 设定内部文字对齐方式
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        // 以屏幕左上角为原点,设置x、y初始值ֵ
//      params.x = (int) MyApplication.mContext.getResources().getDimension(R.dimen.x320);
//      params.y = (int) -100;
        view_obj.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                show(context);
            }
        });
        wm.addView(view_obj, params);
        timer.start();
    }

    /** 全显示(动画) */
    public void displayAll() {
        view_obj.animate().y(0).alpha(1).setDuration(700).start();
        isAllDisplay = true;
    }

    /** 半显示(动画) */
    public void displayHalf() {
        view_obj.animate().y(-(int) MyApplication.mContext.getResources().getDimension(R.dimen.x40)).alpha(0.5f).setDuration(700).start();
        isAllDisplay = false;
    }

    private void show(Context mContext){
        view_obj.setVisibility(View.VISIBLE);
        if (isAllDisplay) {
            if (!CommonUtils.isExsitMianActivity(mContext, PlayActivity.class)) {
                Toast.makeText(mContext, "暂无播放", Toast.LENGTH_SHORT).show();
                return;
            }
            displayHalf();
            CommonUtils.jumpToPage(mContext, PlayActivity.class, null, false, 0);
        }else {
            displayAll();
            timer.start();
        }
    }

    private CountDownTimer timer = new CountDownTimer(3000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onFinish() {
            displayHalf();
        }
    };

    /**
     * 关闭浮动显示对象
     */
    private void close(Context context) {
        if (view_obj != null && view_obj.isShown()) {
            WindowManager wm = (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE);
            wm.removeView(view_obj);
        }
    }

    /**
     * 隐藏按钮
     */
    public void close() {
        if (view_obj != null) {
            view_obj.setVisibility(View.GONE);
        }
    }

    /**
     * 显示按钮
     */
    public void show(){
        if (view_obj != null) {
            view_obj.setVisibility(View.VISIBLE);
        }
    }

    /**
     * 更新弹出窗口位置
     */
    private void updateViewPosition() {
        // 更新浮动窗口位置参数
        params.x = (int) (x - mTouchStartX);
        params.y = (int) (y - mTouchStartY);
        wm.updateViewLayout(view_obj, params);
    }
}

初始化:

FloatingFunc.getInstance().show(mContext, getWindow(), LayoutInflater.from(mContext).inflate(R.layout.floatingfunc_view, null));

里面这个view就是要显示的控件。初始显示位置,还有隐藏显示之类的方法都已写在类里,可以自己看注释找一下,类对象使用单例模式,调用类内的方法都是通过FloatingFunc.getInstance()点出来的,比如:FloatingFunc.getInstance().close()

如有帮助,看完记得点赞

你可能感兴趣的:(技术笔记类)