【Android】使用WindowManager实现窗口拖动,附加自动停靠边缘效果

Android使用WindowManager实现窗口拖动,附加自动停靠边缘效果

代码

主界面xml文件

主界面activity_main

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/alert_window_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="弹窗"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.13"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.068" />
</androidx.constraintlayout.widget.ConstraintLayout>

窗口xml文件

窗口的视图window_layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:background="@drawable/window_border"
    android:orientation="vertical">

    <TextView
        android:id="@+id/window_bar"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="提示"
        android:gravity="center_vertical"
        android:textSize="20dp"
        android:textColor="@color/white"
        android:background="@color/blue"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:textSize="18dp"
        android:padding="8dp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:padding="5dp"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">
            <Button
                android:id="@+id/window_remove"
                android:layout_width="80dp"
                android:layout_height="40dp"
                android:text="取消"
                android:textStyle="bold"
                android:background="@color/dark_white"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <Button
                android:layout_width="80dp"
                android:layout_height="40dp"
                android:background="@color/blue"
                android:textColor="@color/white"
                android:textStyle="bold"
                android:text="确定"/>
        </LinearLayout>

    </LinearLayout>

</LinearLayout>

效果
在这里插入图片描述

MainActivity

package com.lwh.windowmanagertest;

import androidx.appcompat.app.AppCompatActivity;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    
    

    boolean removed = false;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 申请系统权限
        requestWindowPermission();

        // 导入窗口
        View windowLayout = LayoutInflater.from(this).inflate(R.layout.window_layout, null);
        // 窗口的标题
        TextView windowBar = windowLayout.findViewById(R.id.window_bar);
        // 窗口的取消和确定按钮
        Button windowRemove = windowLayout.findViewById(R.id.window_remove);
        // 弹出窗口按钮
        Button alertWindowButton = findViewById(R.id.alert_window_button);

        // 获取WindowManager
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        // 创建LayoutParams
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();


        // 定义Window类型
        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;;
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE    // 设置窗口不接受输入焦点
                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; // 设置锁屏时也显示窗口

        layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; // window的宽度
        layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;// window的高度

        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        // window的位置
        layoutParams.x = 0;
        layoutParams.y = 100;
        // 往window中添加内容
        windowManager.addView(windowLayout, layoutParams);

        // 屏幕宽度(应用显示部分,不包括系统顶部状态栏)
        int screenWidth = getResources().getDisplayMetrics().widthPixels;

        // 设置拖动窗口标题移动
        windowBar.setOnTouchListener(new View.OnTouchListener() {
    
    
            float oldX;  // 上一次鼠标点击时的X坐标
            float oldY;  // 上一次鼠标点击时的Y坐标
            float windowX;  // 弹出窗口的X坐标
            float windowY; // 弹出窗口的Y坐标

            @SuppressLint("Recycle")
            @Override
            public boolean onTouch(View v, MotionEvent event) {
    
    
                switch (event.getAction()) {
    
    
                    case MotionEvent.ACTION_MOVE:
                        // event.getRawX()-oldX为偏移量
                        // 新位置 = 原始位置 + 偏移量
                        layoutParams.x = (int) (windowX + event.getRawX()-oldX);
                        layoutParams.y = (int) (windowY +  event.getRawY()-oldY);
                        windowManager.updateViewLayout(windowLayout, layoutParams);
                        break;
                    // 鼠标弹起时判断窗口X轴的位置,然后将其贴边
                    case MotionEvent.ACTION_UP:
                        double halfScreenWidth = screenWidth / 2.0;
                        // 如果X轴坐标大于屏幕宽度的一半,则将其置于右边,否则左边
                        if (layoutParams.x >= halfScreenWidth){
    
    
                            // layoutParams.x = screenWidth - windowLayout.getMeasuredWidth();
                            // 执行动画
                            ValueAnimator valueAnimator = ValueAnimator.ofInt(layoutParams.x, screenWidth - windowLayout.getMeasuredWidth());
                            valueAnimator.setDuration(200);
                            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
    
                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
    
    
                                    int x = (int) animation.getAnimatedValue();
                                    layoutParams.x = (int) x;
                                    windowManager.updateViewLayout(windowLayout, layoutParams);
                                }
                            });
                            valueAnimator.start();
                        }else{
    
    
                            // layoutParams.x = 0;
                            // 执行动画
                            ValueAnimator valueAnimator = ValueAnimator.ofInt(layoutParams.x, 0);
                            valueAnimator.setDuration(200);
                            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
    
                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
    
    
                                    int x = (int) animation.getAnimatedValue();
                                    layoutParams.x = (int) x;
                                    windowManager.updateViewLayout(windowLayout, layoutParams);
                                }
                            });

                            valueAnimator.start();
                        }
                        // windowManager.updateViewLayout(windowLayout, layoutParams);
                    default:
                        oldX = event.getRawX();
                        oldY = event.getRawY();
                        // 计算移动后的位置(左上角的坐标)
                        // windowX = event.getRawX() - event.getX();
                        // windowX = event.getRawY() - event.getY();
                        windowX = layoutParams.x;
                        windowY = layoutParams.y;
                        break;
                }
                return true;
            }
        });
        // 点击取消删除窗口
        windowRemove.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                windowManager.removeView(windowLayout);
                removed = true;
            }
        });

        alertWindowButton.setOnClickListener(new View.OnClickListener() {
    
    

            @Override
            public void onClick(View v) {
    
    
                if (removed){
    
    
                    windowManager.addView(windowLayout, layoutParams);
                    removed = false;
                }else{
    
    
                    windowManager.removeView(windowLayout);
                    removed = true;
                }
            }
        });
    }

    private void requestWindowPermission() {
    
    
        //android 6.0或者之后的版本需要发一个intent让用户授权
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
    
            if (!Settings.canDrawOverlays(getApplicationContext())) {
    
    
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                intent.setData(Uri.parse("package:" + getPackageName()));
                startActivity(intent);
                // startActivityForResult(intent, 100);
            }
        }
    }
}

效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44500303/article/details/128498175
今日推荐