实用的悬浮窗工具类

Posted 苦逼程序员_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实用的悬浮窗工具类相关的知识,希望对你有一定的参考价值。

最近工(xian)作(de)需(dan)要(teng),封装了一个提示型的悬浮窗工具类,简化了悬浮窗的创建显示和隐藏等步骤,并预定义了上中下三种简单的进场退场动画,拓展了悬浮窗自定义消失时间的功能。

使用方法很简单:

1.实例化悬浮窗工具类FloatView

FloatView floatView = new FloatView(context);

2.传入需要显示在悬浮窗上的view,可以是xml也可以是自定义view

//inflate xml类型view
LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflate.inflate(R.layout.my_view, null);
floatView.setView(mView);

//或自定义类型view
VolumeBar volumeBar = new TVolumeBar(context);
floatView.setView(volumeBar);

3.可自定义悬浮窗的宽高, 默认是wrap_content

//可自定义宽高,不设置则默认均为wrap_content
//单位是px,建议使用资源文件定义宽高,使用resources.getDimensionPixelSize()获取,方便做不同分辨率适配
floatView.setWidth(250);
floatView.setHeight(40);

4.可自定义显示时间,工具类中预定义了三种方案,分别是短时间(2秒)显示,长时间(4秒)显示,一直显示(直至主动隐藏悬浮窗),也可以自定义显示时间(单位秒)

//短时间显示
floatView.setDuration(FloatView.LENGTH_SHORT);

//长时间显示
floatView.setDuration(FloatView.LENGTH_LONG);

//一直显示
floatView.setDuration(FloatView.LENGTH_ALWAYS);

//自定义显示时间,单位秒,10秒后消失
floatView.setDuration(10);

5.自定义布局位置,工具类预定义了3种布局方案

@link #TOP 置顶并水平铺满
@link #CENTER 居中自适应
@link #BOTTOM 置底并水平铺满
预定义方案可以通过 defaultAnim 决定是否使用默认动画
不使用默认动画可以通过 @link #setWindowAnimations 自定义
除了三种预定义方案,还可传入 Gravity 自定义参数进行布局

//使用预定义TOP布局,水平铺满并自适应高度
//使用预定义动画,自上而下淡入,自下而上淡出
floatView.setGravity(FloatView.TOP, true);

//使用预定义CENTER布局,宽度高度均自适应
//不实用预定义动画
floatView.setGravity(FloatView.CENTER, false);

//自定义Gravity,使悬浮窗布局在屏幕右侧
floatView.setGravity(Gravity.RIGHT, false);

6.可自定义进出场动画

<style name="my_anim">
    <item name="@android:windowEnterAnimation">@anim/my_anim_in</item>
    <item name="@android:windowExitAnimation">@anim/my_anim_out</item>
</style>

my_anim_in.xmlmy_anim_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:fromYDelta="-120%"
        android:toXDelta="0%"
        android:toYDelta="0%"
        android:fillAfter="true"
        android:duration="1000"
        />
</set>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="-120%"
        android:fillAfter="true"
        android:duration="1000"
        />
</set>

自定义进出场动画详细写法请自行查找资料.

//参数传入R.style
floatView.setWindowAnimations(R.style.my_anim);

7.最后调用show()方法显示悬浮窗, 悬浮窗已显示的时候更新view的内容可以立即刷新view。已显示的时候再次调用show()方法会刷新悬浮窗的消失时间重新计时。

//调用show()前必须调用过setView(),否则不显示悬浮窗
floatView.show();
//在floatView显示时对显示的view进行内容修改可立刻刷新悬浮窗显示的内容
myView.setText("内容更新");
//再次调用show()方法可以刷新消失时间,重新倒计时
floatView.show();

//调用hide()播放退场动画并隐藏悬浮窗
floatView.hide();
//调用hideImmediate()立即隐藏悬浮窗,适合在悬浮窗父容器退出时调用,防止内存泄漏
floatView. hideImmediate();

8.在悬浮窗隐藏的时候会触发OnHideListener,可以在悬浮窗隐藏时做适当的处理

floatView.setOnHideListener(new FloatView.OnHideListener() 
    @Override
    public void onHide() 
        Log.e(TAG, "onHide");
    
);

FloatView工具类源码

public class FloatView 

    public static final int TOP = 0x9731;
    public static final int CENTER = 0x9732;
    public static final int BOTTOM = 0x9733;

    public static final int LENGTH_ALWAYS = 0;
    public static final int LENGTH_SHORT = 2;
    public static final int LENGTH_LONG = 4;

    protected Context mContext;
    protected WindowManager.LayoutParams params;
    protected WindowManager mWM;
    protected View mView;
    protected Handler mHandler;
    protected int mDuration = LENGTH_SHORT;

    public FloatView(Context context)
        this.mContext = context;
        mHandler = new Handler();
        params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
        params.setTitle("FloatView");
        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
    

    /**
     * 为悬浮窗设置View
     * @param view 自定义view
     */
    public void setView(View view) 
        if(mView != null && mView.getParent() != null) 
            mWM.removeView(mView);
        
        mView = view;
    

    /**
     * 设置悬浮窗宽度
     * @param width 宽度
     */
    public void setWidth(int width) 
        params.width = width;
    

    /**
     * 设置悬浮窗高度
     * @param height 高度
     */
    public void setHeight(int height) 
        params.height = height;
    

    /**
     * 自定义透明度,0.0f全透明,1.0f全不透明
     * @param alpha 透明度
     */
    public void setAlpha(float alpha) 
        params.alpha = alpha;
    

    /**
     * 自定义窗口类型,默认 @link WindowManager.LayoutParams#TYPE_SYSTEM_OVERLAY
     * @param type 窗口类型
     */
    public void setType(int type) 
        params.type = type;
    

    /**
     * 自定义窗口进出场动画
     * @param windowAnimations 动画资源res
     */
    public void setWindowAnimations(int windowAnimations) 
        params.windowAnimations = windowAnimations;
    

    /**
     * 设置Gravity,已预定义三种Gravity分别是
     * @link #TOP 置顶并水平铺满
     * @link #CENTER 居中自适应
     * @link #BOTTOM 置底并水平铺满
     * 预定义方案可以通过 defaultAnim 决定是否使用默认动画
     * 不使用默认动画可以通过 @link #setWindowAnimations 自定义
     * 除了三种预定义方案,还可传入 Gravity 自定义参数进行布局
     * @param gravity 预定义或自定义Gravity
     * @param defaultAnim 是否使用默认动画
     */
    public void setGravity(int gravity, boolean defaultAnim) 
        switch (gravity) 
            case TOP:
                params.gravity = Gravity.FILL_HORIZONTAL | Gravity.TOP;
                if (defaultAnim) 
                    params.windowAnimations = R.style.top_anim_view;
                
                break;
            case CENTER:
                params.gravity = Gravity.CENTER;
                params.width = WindowManager.LayoutParams.WRAP_CONTENT;
                if (defaultAnim) 
                    params.windowAnimations = R.style.center_anim_view;
                
                break;
            case BOTTOM:
                params.gravity = Gravity.FILL_HORIZONTAL | Gravity.BOTTOM;
                params.width = WindowManager.LayoutParams.MATCH_PARENT;
                if (defaultAnim) 
                    params.windowAnimations = R.style.bottom_anim_view;
                
                break;
            default:
                params.gravity = gravity;
        
    

    private Runnable hideRunnable = new Runnable() 
        @Override
        public void run() 
            hide();
        
    ;

    /**
     * 显示悬浮窗,如果mView还未初始化则不做处理
     * 如果mView已经显示,则只刷新显示时间,未显示添加到mWM
     */
    public void show() 
        if(mView == null) 
            return;
        
        if (mView.getParent() == null) 
            mWM.addView(mView, params);
        
        refreshHideTime();
    

    /**
     * 隐藏悬浮窗,并触发onHide回调
     * 该隐藏方法会触发window退场动画
     * 如果mView的容器退出,建议调用@link #hideImmediate()
     * 否则有可能会导致 Activity 出现内存泄漏
     */
    public void hide()
        if (mView != null && mView.getParent() != null) 
            mWM.removeView(mView);
            if (onHideListener != null) 
                onHideListener.onHide();
            
        
    

    /**
     * 立刻隐藏悬浮窗,触发onHide回调
     * 不会触发window退场动画
     */
    public void hideImmediate()
        if (mView != null && mView.getParent() != null) 
            params.windowAnimations = 0;
            mWM.updateViewLayout(mView, params);
            mWM.removeView(mView);
            if (onHideListener != null) 
                onHideListener.onHide();
            
        
    

    /**
     * 设置悬浮窗持续显示时间,预定义三种方案
     * @link #LENGTH_SHORT 2秒后自动消失
     * @link #LENGTH_LONG 4秒后自动消失
     * @link #LENGTH_ALWAYS 持续显示悬浮窗,直至调用 hide 或 hideImmediate
     * 除了三种预定义方案,也可自定义显示时间,传入的参数值代表n秒后自动消失
     * @param duration 持续时间
     */
    public void setDuration(int duration) 
        mDuration = duration;
    

    /**
     * 返回悬浮窗持续显示时间
     * @return 持续时间
     */
    public int getDuration() 
        return mDuration;
    

    // 刷新悬浮窗的消失时间
    private void refreshHideTime() 
        //判断duration,如果大于#LENGTH_ALWAYS 则设置消失时间
        if (mDuration > LENGTH_ALWAYS) 
            mHandler.removeCallbacks(hideRunnable);
            mHandler.postDelayed(hideRunnable, mDuration * 1000);
        
    

    private OnHideListener onHideListener;

    public void setOnHideListener(OnHideListener onHideListener) 
        this.onHideListener = onHideListener;
    

    public interface OnHideListener 
        void onHide();
    

以上是关于实用的悬浮窗工具类的主要内容,如果未能解决你的问题,请参考以下文章

Qt实用技巧:将QWidget作为输入窗口,接收键盘消息输入法并且控制输入法悬浮工具栏位置控制

华为mate9的悬浮窗怎么操作

Android 悬浮窗如何能让它和他的的下层一起响应触摸事件?

电脑悬浮窗口怎么设置?

华为p50pro的悬浮窗怎么使用?

悬浮窗是啥,怎么开启悬浮窗?