实用的悬浮窗工具类

Android 悬浮窗功能的实现 1.悬浮窗可以显示在其他应用或launchers之上,这个肯定需要悬浮窗权限,而悬浮窗权限属于特殊权限,所以只能通过引导用户去打开无法像危险权限那样直接申请。可以做到后台显示则说明悬浮窗是一个Service。2.通话页面隐藏时悬浮窗显示,通话页面显示时悬浮窗隐藏,可以看出悬浮窗和Activity的生命周期相关联,所以悬浮窗的Service和通话页面的Activity是通过bind去绑定的。 阅读详情

最近工(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.xml与my_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();
    }
}
突破小米悬浮窗权限控制--不需要权限的悬浮窗 上一篇文章讲了Android的Toast拓展,在原生Toast基础上对显示时长和显示动画做了二次封装,强化了Toast的部分功能。也分析了对于二次封装的ExToast设计原理,以及Toast的关键点。Toast其实就是系统悬浮窗的一种,基于Toast我们可以拓展出不需要权限的悬浮窗,而悬浮窗能做什么,你们懂的。但是,小米系统对开发者恶心,你们也懂的,下面分析一下如何突破小米悬浮窗权限封锁。 阅读详情

相关推荐

Android权限动态申请(包括悬浮窗)

【代码】Android权限动态申请。

weixin_42966151的博客 6652

【Demo】iOS可吸附拖动的悬浮窗按钮插件

参考http://www.myexception.cn/operating-system/1924022.html的思路使用一个UIWindow实现按钮悬浮在应用中不受页面切换的影响,之后要实现悬浮窗口的拖动和自动吸附在靠近的屏幕边缘。          开始思路是直接改写UIButton,使用touch代理事件来监听按钮开始触摸,移动,触摸结束等事件获取触点坐标,改变UIWindow的位

Mr_厚厚的博客 1万+

HarmonyOS开发之基于子窗口实现应用内悬浮窗

我们希望实现以下核心功能:编号功能描述✅ 场景一支持动态添加/移除悬浮窗,样式可定制(圆形 & 小视频窗口)✅ 场景二子窗口创建后,主窗口仍能正常响应系统返回手势(如侧滑返回)✅ 场景三悬浮窗支持拖拽并自动靠边显示;跳转页面后仍保持位置不变✅ 场景四悬浮窗内部点击触发主窗口 Router / Navigation 页面跳转✅ 场景五窗口大小自适应内容组件变化✅ 场景六支持隐藏和销毁悬浮窗✅ 场景七视频类应用支持画中画后台播放与桌面返回自动恢复✅ 自定义外观与布局。

Java_fenxiang的博客 875

ios居然自带悬浮窗调试工具

我们经常使用各种调试工具,或者开源库来支持悬浮窗调试信息,但苹果的私有方法就提供了UIDebuggingInformationOverlay。 系统要求:  ios10+,iOS11 目前在我自己的手机上测试是行不通的。如果英语不错的可以去看这篇,看完记得通知我一下噢。 https://www.raywenderlich.com/177890/swizzling-in-ios-11-w

qq_19697705的专栏 3946

Android悬浮窗的简单实现

1. 前言   现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示。下面将介绍下悬浮窗的的一种简单实现方式。 2.原理   Window我们应该很熟悉,它是一个接口类,具体的实现类为PhoneWindow,它可以对View进行管理。WindowManager是一个接口类,继承自ViewManager,从名称就知道它是用来管理Window的,它的实现类是WindowManagerImpl。如果我们想要对Window(View)进行添加、更新和删除操作

weixin_55362248的博客 6527

实验四 基于IDEA+SpringBoot+Maven+Thymeleaf的系统实现实验目的

通过这次实验,我学习了如何成功进行IDEA+SpringBoot+maven的系统实现,搭建好IDEA+SpringBoot+maven的系统环境,成功地安装并配置了maven的运行环境,学会了创建springboot的三种方式,并且能将之前的实验结合起来运用。pom.xml中引入thymeleaf依赖,在classpath:/templates/下新建HTML页面(可采用实验一创建的页面),新建controller进行测试,访问页面后返回success成功数据。同时掌握和thymeleaf的基本语法。

m0_73502929的博客 1379

ios开发中常用的第三方

YYKit多功能组件MLPhotoLib  TZImagePickerController MWPhotoBrowser  IDMPhotoBrowser CTAssetsPickerController KSPhotoBrowser JTSImageViewController   ZLPhotoBrowser图片选择,浏览IQKeyboardManager 键盘遮挡输入框的处理MGSwipeT...

ss_aa_aa的博客 1095

从零开始:用君正T23ZN打造智能门锁双摄系统(含代码示例与调试技巧)

本文详细介绍了基于君正T23ZN视频处理芯片构建智能门锁双摄系统的完整实战方案。内容涵盖硬件选型与核心电路设计、软件开发环境搭建、双摄驱动框架、图像信号处理(ISP)调优、人脸识别算法集成与性能优化,以及系统调试与稳定性保障。文章提供了丰富的代码示例和调试技巧,旨在帮助嵌入式开发者高效实现具备人脸识别与监控功能的低功耗智能门锁视觉系统。

opencv7vision的博客 715

10个程序员必逛的网站

大家好,我是知微!相信各位小伙伴都会经常在网上查找学习资料和经验贴,但是光靠搜索引擎,有时候费时费力,效果还不好。下面为大家整理了10个程序员经常会用到的网站,一起来看看吧!

Happy_HZW的博客 2374

第八章 MobileNetv3网络详解

本文介绍了基于互补的搜索技术和新颖的架构设计的MobileNets的下一代。MobileNetV3通过硬件感知网络架构搜索(NAS)和NetAdapt算法相结合,针对移动电话CPU进行优化,随后通过新颖的架构改进技术进行了进一步提高。本文开始探索自动化搜索算法和网络设计如何相互协作,以利用互补的方法改进整体技术水平。通过此过程,我们创建了两个新的MobileNet模型:MobileNetV3-Large和MobileNetV3-Small,分别针对高资源和低资源使用情况。

ADICDFHL的博客 1万+

学Simulink--基础微电网场景实例:基于Simulink的微电网黑启动过程建模与仿真

黑启动(Black Start)是指在全系统停电(无电压、无频率)状态下,微电网依靠内部电源自主恢复供电的能力。🌩️典型场景主网长时间故障自然灾害导致区域停电计划检修后重启❗挑战无参考电压/频率 → 逆变器无法锁相负荷逐级投入 → 需避免过流/过压多电源协调 → 防止环流或失步✅黑启动成功标准在30 秒内恢复关键负荷供电电压/频率稳定在范围内无设备损坏或保护跳闸🎯本文目标:手把手教你使用 Simulink + Simscape + Stateflow 搭建。

amy_mhd的博客 200

推荐10个程序员常去的网站

程序员大佬们常常逛的站点是哪些?

程序大视界 2万+

《C#零基础入门之百识百例》(七十一)委托介绍 -- 战士升级示例

委托的存在是因为,我们有时候需要将一个函数作为另一个函数的参数,这时就要用的委托(Delegate)机制。委托用关键字`delegate`声明,他实际上定义了一种“函数类型”,明确规定了函数参数类型和返回值类型。

陈言必行 -- Unity游戏开发领域优质博主 2109

【Android】通过获取当前 Activity 的包名来显示不同的悬浮窗布局,适用5.0+

转自weixin_41476562 的 [安卓]!新人首贴!安卓开发实现在任何Activity下更新悬浮窗内容,感谢!

Okay 696

基于coze studio开源框架二次定制开发教程

CozeStudio是一站式AIAgent开发工具,支持大模型接入、智能体编排、工作流开发等功能。采用Golang+React技术栈,基于微服务架构设计。项目包含后端API、领域逻辑、前端应用等模块,支持自定义任务流节点开发。开发流程涵盖前后端节点定义、实现逻辑编写等步骤,提供完整的开发规范和参考文档。相比商业版,开源版本在功能上有所精简,但仍保留核心开发能力。

coding change your life 790

【银河麒麟服务器操作系统】安装英伟达4090D显卡驱动操作指南

本文详细介绍了在银河麒麟高级服务器操作系统V10SP3-2403-X86版本上安装NVIDIA RTX4090D显卡驱动的完整流程。主要内容包括:准备工作检查、开源驱动禁用、运行级别切换、依赖包安装以及交互式安装过程中的关键选项选择(32位库选Yes、X配置选No)。通过禁用nouveau驱动、重建内核引导等步骤确保驱动安装成功,最后通过nvidia-smi命令验证驱动安装情况。文档提供了操作检查表和安装流程图,帮助用户在银河麒麟系统上顺利完成显卡驱动部署。

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 3097

各类demo链接

http://gundumw100.iteye.com/blog/940084 带磁性的悬浮窗体,类似于360绿色小人  主要实现的是:  1.悬浮所有窗体之上  2.有吸引力,吸附于屏幕边上  3.有点击效果  http://blog.youkuaiyun.com/manymore13/article/details/8577286  Android特效开发(可伸缩View带互

行走在路上 3979

构建个体结构脑网络的另一种方法

这篇文献提出了一种构建个体结构脑网络的方法即Morphometric INverse Divergence (MIND),通过T1像数据即可对每个被试构建一个脑网络,且通过多个特征进行构建而非单一的特征。即可获得由4个特征得到的个体结构网络矩阵,可以根据自己的需求采用不同的特征组合得到网络矩阵,也可以结合T1/T2像得到髓鞘化相关的网络矩阵,后续可修改代码批量处理自己的数据。这是文献贴出来的代码。在终端直接克隆到本地。2.修改路径运行代码。

weixin_52073820的博客 822

Android悬浮窗的实现

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 现在很多应用都使用到悬浮窗,例如微信在视频的时候,点击Home键,视频小窗口仍然会在屏幕上显示。这个功能在很多情况下都非常有用。那么今天我们就来实现一下Android悬浮窗,以及探索一下实现悬浮窗时的易错点。

董小虫的专栏 11万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Android悬浮窗看这篇就够了

之前想要实现个全局全浮球的效果,找遍了网上大佬的博客,踩了不少坑,但是还是有一些问题没有解决,比如个别手机设置界面的部分二级界面无法显示(例如:MIUI设置-关于手机[狗头保命]) 索性在此总结一篇关于悬浮窗使用以及适配的详细博客(Kotlin代码) 老规矩先上源码链接https://gitee.com/AndroidLMY/SuspendedWindow 效果图 悬浮窗的基本原理 首先我们来说下悬浮窗的基本原理是什么 动态添加View 我们都知道我们我们想动态的添加View到界面..

qq_37750825的博客 3万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Kotlin 实现 Android 系统悬浮窗

Android 弹窗浅谈 我们知道 Android 弹窗中,有一类弹窗会在应用之外也显示,这是因为他被申明成了系统弹窗,除此之外还有2类弹窗分别是:子弹窗与应用弹窗。 应用弹窗:就是我们常规使用的 Dialog 之类弹窗,依赖于应用的 Activity; 子弹窗:依赖于父窗口,比如 PopupWindow; 系统弹窗:比如状态栏、Toast等,本文所讲的系统悬浮窗就是系统弹窗。 系统悬浮窗具体实现 权限申请 <uses-permission android:name="android.p

让学习编程变得生动有趣~ 5166

鸿蒙-应用内悬浮窗

/ 导入命名路由页面。Text('悬浮窗')

m0_51170428的博客 1135

Android 悬浮窗

悬浮窗是一种比较常见的需求。例如把视频通话界面缩小成一个悬浮窗,然后用户可以在其他界面上处理事情。 本文给出一个简单的悬浮窗实现。可缩小activity和还原大小。可悬浮在其他activity上。使用TouchListener监听触摸事件,拖动悬浮窗。 本文链接 缩放方法 缩放activity需要使用WindowManager.LayoutParams,控制window的宽高 在activity中调用 android.view.WindowManager.LayoutParams p = getWindow

铁手渔夫 1万+
上一篇: Android定制透明悬浮StatusBar 多分辨率适配
下一篇: 巧用Scanner将InputStream转成String
苦逼程序员_
博客等级 码龄14年 59粉丝 19原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值