Android悬浮窗实现 使用WindowManager

Android  2020年8月14日 pm12:31发布4年前 (2020)更新 91es.com站长
70 0 0

WindowManager介绍

通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager对象。

使用WindowManager可以在其他应用最上层,甚至手机桌面最上层显示窗口。

调用的是WindowManager继承自基类的addView方法和removeView方法来显示和隐藏窗口。

LayoutParams常用参数:

  1. type值

用于确定悬浮窗的类型,一般设为2002,表示在所有应用程序之上,但在状态栏之下。

  1. flags值

用于确定悬浮窗的行为,比如说不可聚焦,非模态对话框等等,属性非常多,大家可以查看文档。

  1. gravity值

用于确定悬浮窗的对齐方式,一般设为左上角对齐,这样当拖动悬浮窗的时候方便计算坐标。

  1. x值

用于确定悬浮窗的位置,如果要横向移动悬浮窗,就需要改变这个值。

  1. y值

用于确定悬浮窗的位置,如果要纵向移动悬浮窗,就需要改变这个值。

  1. width值

用于指定悬浮窗的宽度。

  1. height值

用于指定悬浮窗的高度。

WindowManager实现悬浮窗

声明权限

AndroidManifest.xml中添加如下代码

<!-- 显示顶层浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

注意:

Android 6.0以上【非系统应用】,需要在[系统设置]找到[应用和通知]已经的[我们的应用],然后点击进入[高级],打开[在应用上方显示]开关

demo代码片段

MainActivity.java

public class WindowActivity extends Activity {

    private String TAG = getClass().getSimpleName();

    private WindowManager windowManager;
    private WindowManager.LayoutParams mLayoutParams = null;
    private View seekbarLayoutView = null;
    private boolean hasWindow = false;
    private LayoutInflater inflater = null;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate : ");
        setContentView(R.layout.activity_main);
        initUI();
        initWindow();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }

    private void initUI() {

        findViewById(R.id.main_bt_one).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "onClick  show(): ");
                show();
            }
        });

        return;
    }

    private void initWindow() {
        inflater = LayoutInflater.from(getApplicationContext());
        windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        mLayoutParams = new WindowManager.LayoutParams();

        //设置透明度
        mLayoutParams.alpha = 1.0f;

        //Android 6.0后,非系统应用,需要在[系统设置]找到[应用和通知]已经的[我们的应用],然后点击进入[高级],打开[在应用上方显示]开关
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//6.0 以上
            mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }

        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;

        mLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
        mLayoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
        seekbarLayoutView = inflater.inflate(R.layout.topbar_layout, null);
        seekbarLayoutView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "onClick hide(): ");
                hide();
            }
        });
        return;
    }

    private void show() {
        Log.d(TAG, "show hasWindow : " + hasWindow);
        if (null != windowManager && (null != seekbarLayoutView) &&
                (seekbarLayoutView.getParent() == null) && !hasWindow) {
            hasWindow = true;
            windowManager.addView(seekbarLayoutView, mLayoutParams);
        }
        return;
    }

    private void hide() {
        Log.d(TAG, "hide hasWindow : " + hasWindow);
        if (null != windowManager && (null != seekbarLayoutView) && hasWindow) {
            windowManager.removeView(seekbarLayoutView);
            hasWindow = false;
        }
        return;
    }

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="@android:color/darker_gray"
    android:orientation="vertical">


    <Button
        android:id="@+id/main_bt_one"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:gravity="center"
        android:text="one" />

</LinearLayout>

topbar_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_green_dark"
    android:paddingTop="160dp"
    tools:ignore="MissingDefaultResource">

</RelativeLayout>

参考文档

  1. WindowManager.LayoutParams
  2. Android 之 Window、WindowManager 与窗口管理

 历史上的今天

  1. 2023: Android消息机制源码介绍(0条评论)
  2. 2019: 梁实秋:时间即生命(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

Android动画之TranslateAnimation使用

Android动画View Animation 视图动画(Tween Animation 补间动画),只能用来设置View的动画Drawable Animation 帧动画(Frame动画),一帧帧地显示资源文件中的DrawableProperty Animation 属性动画,在andr...

胡适:赠与今年的大学毕业生

这一两个星期里,各地的大学都有毕业的班次,都有很多的毕业生离开学校去开始他们的成人事业。学生的生活是一种享有特殊优待的生活,不妨幼稚一点,不妨吵吵闹闹,社会都能纵容他们,不肯严格的要他们负行为的责任。现在他们要撑起自己的肩膀来挑他们自己的担子了。在这个国难最紧急的年头,他们的担子真不轻! 我们祝他们...

[摘]SeekBar的thumbOffset属性

Android的控件SeekBar中有个android:thumbOffset的属性,这个属性的作用是指示thumb(滑块)在拖动条的进度最大值与最小值时相对于拖动条的偏移量。thumbOffset值1、thumbOffset:0px最小值时thumb位置:thumb的最左端与SeekBar的...

修改Android系统时间设置到2099

前言修改Android支持的时间大于2037。系统时间限制默认是Int(有符号32位,最大0X7FFFFFFF)最大值即为: Integer.MAX_VALUE = 0X7FFFFFFF=2147483647 = 2038-01-19 11:14:07。个人流水账而已。正文将RTC时间限...

Android新增开关安装apk选项

前言记录一下,Android中设置一个开关进行判断是否允许用户自己安装apk。记录于此,方便自己查阅。正文frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java@Overr...

[代码片段]GradientTextView渐变的TextView

前言本质上就是通过LinearGradient来实现渐变的正文public class GradientTextView extends androidx.appcompat.widget.AppCompatTextView { public GradientTextView(Context...