利用悬浮窗加PopupWindow实现从手机屏幕右边划出应用快捷切换

这篇具有很好参考价值的文章主要介绍了利用悬浮窗加PopupWindow实现从手机屏幕右边划出应用快捷切换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

利用悬浮窗加PopupWindow实现从手机屏幕右边划出应用快捷切换

效果如上图所示

安卓小白记录学习过程。一起交流学习。有问题请多多指出。话不多说进入正题。

一、思路

首先明确需求,我们需要做一个右划弹出一个快捷切换应用的弹窗。

悬浮窗可以在其他应用上层显示出来,那么我们可以设置一个透明的悬浮窗让它显示在其他应用上层,然后通过这个悬浮窗只需要写一个滑动的监听事件。满足条件去弹出一个PopupWindow即可。那么有了思路按部就班去实现就OK了。

二、实现

(1)第一步实现一个显示在其他应用上层的悬浮窗

主布局简单写个按钮去弹出悬浮窗就行,这个看情况而定。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/button_star_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动悬浮窗"/>

</LinearLayout>

我们需要右划去弹出PopupWindow那么我们可以写一个透明的控件放在右边缘,我用的是一个宽10dp和和手机屏幕等高的一个TextView,用什么都可以只要看不到即可。

float_window.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textview_float_window"
        android:layout_width="10dp"
        android:layout_height="match_parent"/>

</LinearLayout>

MainActivity简单写个Button点击事件去启动悬浮窗就行了

MainActivity.java

package com.example.floatingwindow;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button_star_service);
        button.setOnClickListener(this::onClick);

    }

    @Override
    public void onClick(View view) {
        /**
         * 启动悬浮窗并且获取悬浮窗权限
         */
        FloatWindowManager floatWindowManager = new FloatWindowManager();
        floatWindowManager.requestPermission(this);
        floatWindowManager.initManager(this);
        floatWindowManager.showFloatWindow();
    }
}

FloatWindowManager用于创建悬浮窗,和设置悬浮窗的滑动事件

FloatWindowManager.java

package com.example.floatingwindow;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;

public class FloatWindowManager {
    private volatile static FloatWindowManager mInstance;
    private WindowManager mWindowManager;
    private Context mContext;
    private WindowManager.LayoutParams mLayoutParams;
    private int layoutY;
    private int layoutX;
    private View view;


    public static synchronized FloatWindowManager getInstance() {
        if (mInstance == null) {
            synchronized (FloatWindowManager.class) {
                if (mInstance == null) {
                    mInstance = new FloatWindowManager();
                }
            }
        }
        return mInstance;
    }

    /**
     * 创建悬浮窗
     * @param context
     * @return
     */

    public FloatWindowManager initManager(Context context) {
        mContext = context;
        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        showWindow();
        return this;
    }

    /**
     * 是否有悬浮框权限
     *
     * @return
     */
    public boolean requestPermission(Context context) {
        return SettingsCompat.canDrawOverlays(context, true, false);
    }

    /**
     * 加载 悬浮窗   没有内容
     */
    private synchronized void showWindow() {
        view = LayoutInflater.from(mContext).inflate(R.layout.float_window,null);
        mLayoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        mLayoutParams.format = PixelFormat.RGBA_8888; //窗口透明
        mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; //窗口位置
        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
        layoutY = 0;
        layoutX = displayMetrics.widthPixels;
        mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        mLayoutParams.x = layoutX;
        mLayoutParams.y = layoutY;
        setListener();
    }

    /**
     * 显示悬浮窗
     */

    public void showFloatWindow(){
        mWindowManager.addView(view,mLayoutParams);
    }


    /**
     * 设置 悬浮窗 view 滑动事件
     */
    private void setListener() {
        if (view != null) {
            view.setOnTouchListener(new View.OnTouchListener() {
                private int moveX;   //平移距离
                int startX, startY,endX,endY;  //起始点
                boolean isMove;  //是否在移动
                long startTime;//划动时间
                boolean downMove = false;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            startX = (int) event.getX();
                            startY = (int) event.getY();
                            startTime = System.currentTimeMillis();
                            isMove = false;
                            downMove = false;
                            return false;
                        case MotionEvent.ACTION_MOVE:

                            return true;
                        case MotionEvent.ACTION_UP:
                            long curTime = System.currentTimeMillis();
                            endX = (int) event.getX();
                            endY = (int) event.getY();
                            isMove = curTime - startTime > 100;
                            if (isMove && Math.abs(endX-startX)>Math.abs(endY-startY)) {
                                //判断左右滑动距离大于上下滑动距离并且滑动时间大于100
                                PopupWindow mPopupWindow = new PopupWindow();
                                mPopupWindow.popupWindow(mContext,view);
                            }

                            return isMove;
                    }
                    return false;
                }
            });
        }
    }
}

 SettingsCompat获取悬浮窗权限

 SettingsCompat.java

package com.example.floatingwindow;

import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.provider.Settings;
import android.widget.Toast;

import java.lang.reflect.Method;
import java.util.List;

public class SettingsCompat {
    private static final int OP_WRITE_SETTINGS = 23;
    private static final int OP_SYSTEM_ALERT_WINDOW = 24;

    /**
     * 检查悬浮窗权限  当没有权限,跳转到权限设置界面
     *
     * @param context          上下文
     * @param isShowDialog     没有权限,是否弹框提示跳转到权限设置界面
     * @param isShowPermission 是否跳转权限开启界面
     * @return true 有权限   false 没有权限(跳转权限界面、权限失败 提示用户手动设置权限)
     */
    public static boolean canDrawOverlays(Context context, boolean isShowDialog, boolean isShowPermission) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(context)) {
                if (isShowDialog) {
                    //去授权
                    SettingsCompat.manageDrawOverlays(context);
                } else if (isShowPermission) {
                    manageDrawOverlays(context);
                }
                return false;
            }
            return true;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            if (checkOp(context, OP_SYSTEM_ALERT_WINDOW)) {
                return true;
            } else {
                if (isShowPermission)
                    startFloatWindowPermissionErrorToast(context);
                return false;
            }
        } else {
            return true;
        }
    }


    /**
     * 打开 悬浮窗 授权界面
     *
     * @param context
     */
    public static void manageDrawOverlays(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                intent.setData(Uri.parse("package:" + context.getPackageName()));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            } catch (Exception e) {
                e.printStackTrace();
                startFloatWindowPermissionErrorToast(context);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            if (!manageDrawOverlaysForRom(context)) {
                startFloatWindowPermissionErrorToast(context);
            }
        }
    }

    /**
     * 权限设置 失败提示。
     *
     * @param context
     */
    public static void startFloatWindowPermissionErrorToast(Context context) {
        if (context != null)
            Toast.makeText(context, "进入设置页面失败,请手动开启悬浮窗权限", Toast.LENGTH_SHORT).show();
    }

    private static boolean manageDrawOverlaysForRom(Context context) {
        if (RomUtil.isMiui()) {
            return manageDrawOverlaysForMiui(context);
        }
        if (RomUtil.isEmui()) {
            return manageDrawOverlaysForEmui(context);
        }
        if (RomUtil.isFlyme()) {
            return manageDrawOverlaysForFlyme(context);
        }
        if (RomUtil.isOppo()) {
            return manageDrawOverlaysForOppo(context);
        }
        if (RomUtil.isVivo()) {
            return manageDrawOverlaysForVivo(context);
        }
        if (RomUtil.isQiku()) {
            return manageDrawOverlaysForQihu(context);
        }
        if (RomUtil.isSmartisan()) {
            return manageDrawOverlaysForSmartisan(context);
        }
        return false;
    }


    private static boolean checkOp(Context context, int op) {
        AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        try {
            Method method = AppOpsManager.class.getDeclaredMethod("checkOp", int.class, int.class, String.class);
            return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
        } catch (Exception e) {
        }
        return false;
    }

    // 可设置Android 4.3/4.4的授权状态
    private static boolean setMode(Context context, int op, boolean allowed) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return false;
        }

        AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        try {
            Method method = AppOpsManager.class.getDeclaredMethod("setMode", int.class, int.class, String.class, int.class);
            method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName(), allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
            return true;
        } catch (Exception e) {

        }
        return false;
    }

    /**
     * 跳转界面
     *
     * @param context
     * @param intent
     * @return
     */
    private static boolean startSafely(Context context, Intent intent) {
        List<ResolveInfo> resolveInfos = null;
        try {
            resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
            if (resolveInfos != null && resolveInfos.size() > 0) {
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    // 小米
    private static boolean manageDrawOverlaysForMiui(Context context) {
        Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        intent.putExtra("extra_pkgname", context.getPackageName());
        intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        // miui v5 的支持的android版本最高 4.x
        // http://www.romzj.com/list/search?keyword=MIUI%20V5#search_result
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent1.setData(Uri.fromParts("package", context.getPackageName(), null));
            return startSafely(context, intent1);
        }
        return false;
    }

    private final static String HUAWEI_PACKAGE = "com.huawei.systemmanager";

    // 华为
    private static boolean manageDrawOverlaysForEmui(Context context) {
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            intent.setClassName(HUAWEI_PACKAGE, "com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity");
            if (startSafely(context, intent)) {
                return true;
            }
        }
        // Huawei Honor P6|4.4.4|3.0
        intent.setClassName(HUAWEI_PACKAGE, "com.huawei.notificationmanager.ui.NotificationManagmentActivity");
        intent.putExtra("showTabsNumber", 1);
        if (startSafely(context, intent)) {
            return true;
        }
        intent.setClassName(HUAWEI_PACKAGE, "com.huawei.permissionmanager.ui.MainActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        return false;
    }

    // VIVO
    private static boolean manageDrawOverlaysForVivo(Context context) {
        // 不支持直接到达悬浮窗设置页,只能到 i管家 首页
        Intent intent = new Intent("com.iqoo.secure");
        intent.setClassName("com.iqoo.secure", "com.iqoo.secure.MainActivity");
        // com.iqoo.secure.ui.phoneoptimize.SoftwareManagerActivity
        // com.iqoo.secure.ui.phoneoptimize.FloatWindowManager
        return startSafely(context, intent);
    }

    // OPPO
    private static boolean manageDrawOverlaysForOppo(Context context) {
        Intent intent = new Intent();
        intent.putExtra("packageName", context.getPackageName());
        // OPPO A53|5.1.1|2.1
        intent.setAction("com.oppo.safe");
        intent.setClassName("com.oppo.safe", "com.oppo.safe.permission.floatwindow.FloatWindowListActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        // OPPO R7s|4.4.4|2.1
        intent.setAction("com.color.safecenter");
        intent.setClassName("com.color.safecenter", "com.color.safecenter.permission.floatwindow.FloatWindowListActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        intent.setAction("com.coloros.safecenter");
        intent.setClassName("com.coloros.safecenter", "com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity");
        return startSafely(context, intent);
    }

    // 魅族
    private static boolean manageDrawOverlaysForFlyme(Context context) {
        Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
        intent.setClassName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity");
        intent.putExtra("packageName", context.getPackageName());
        return startSafely(context, intent);
    }

    // 360
    private static boolean manageDrawOverlaysForQihu(Context context) {
        Intent intent = new Intent();
        intent.setClassName("com.android.settings", "com.android.settings.Settings$OverlaySettingsActivity");
        if (startSafely(context, intent)) {
            return true;
        }
        intent.setClassName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
        return startSafely(context, intent);
    }

    // 锤子
    private static boolean manageDrawOverlaysForSmartisan(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return false;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // 锤子 坚果|5.1.1|2.5.3
            Intent intent = new Intent("com.smartisanos.security.action.SWITCHED_PERMISSIONS_NEW");
            intent.setClassName("com.smartisanos.security", "com.smartisanos.security.SwitchedPermissions");
            intent.putExtra("index", 17); // 不同版本会不一样
            return startSafely(context, intent);
        } else {
            // 锤子 坚果|4.4.4|2.1.2
            Intent intent = new Intent("com.smartisanos.security.action.SWITCHED_PERMISSIONS");
            intent.setClassName("com.smartisanos.security", "com.smartisanos.security.SwitchedPermissions");
            intent.putExtra("permission", new String[]{Manifest.permission.SYSTEM_ALERT_WINDOW});

            //        Intent intent = new Intent("com.smartisanos.security.action.MAIN");
            //        intent.setClassName("com.smartisanos.security", "com.smartisanos.security.MainActivity");
            return startSafely(context, intent);
        }
    }
}

RomUI.java

package com.example.floatingwindow;

import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class RomUtil {
    private static final String TAG = "RomUtil";

    public static final String ROM_MIUI = "MIUI";
    public static final String ROM_EMUI = "EMUI";
    public static final String ROM_FLYME = "FLYME";
    public static final String ROM_OPPO = "OPPO";
    public static final String ROM_SMARTISAN = "SMARTISAN";

    public static final String ROM_VIVO = "VIVO";
    public static final String ROM_QIKU = "QIKU";

    public static final String ROM_LENOVO = "LENOVO";
    public static final String ROM_SAMSUNG = "SAMSUNG";

    private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
    private static final String KEY_VERSION_EMUI = "ro.build.version.emui";
    private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
    private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";
    private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";
    private static final String KEY_VERSION_GIONEE = "ro.gn.sv.version";
    private static final String KEY_VERSION_LENOVO = "ro.lenovo.lvp.version";
    private static final String KEY_VERSION_FLYME = "ro.build.display.id";


    private static final String KEY_EMUI_VERSION_CODE = "ro.build.hw_emui_api_level";

    private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    private static final String KEY_MIUI_HANDY_MODE_SF = "ro.miui.has_handy_mode_sf";
    private static final String KEY_MIUI_REAL_BLUR = "ro.miui.has_real_blur";

    private static final String KEY_FLYME_PUBLISHED = "ro.flyme.published";
    private static final String KEY_FLYME_FLYME = "ro.meizu.setupwizard.flyme";

    private static final String KEY_FLYME_ICON_FALG = "persist.sys.use.flyme.icon";
    private static final String KEY_FLYME_SETUP_FALG = "ro.meizu.setupwizard.flyme";
    private static final String KEY_FLYME_PUBLISH_FALG = "ro.flyme.published";

    private static final String KEY_VIVO_OS_NAME = "ro.vivo.os.name";
    private static final String KEY_VIVO_OS_VERSION = "ro.vivo.os.version";
    private static final String KEY_VIVO_ROM_VERSION = "ro.vivo.rom.version";

    public static boolean isEmui() {
        return check(ROM_EMUI);
    }

    public static boolean isMiui() {
        return check(ROM_MIUI);
    }

    public static boolean isVivo() {
        return check(ROM_VIVO);
    }

    public static boolean isOppo() {
        return check(ROM_OPPO);
    }

    public static boolean isFlyme() {
        return check(ROM_FLYME);
    }

    public static boolean isQiku() {
        return check(ROM_QIKU) || check("360");
    }

    public static boolean isSmartisan() {
        return check(ROM_SMARTISAN);
    }

    private static String sName;

    public static String getName() {
        if (sName == null) {
            check("");
        }
        return sName;
    }

    private static String sVersion;

    public static String getVersion() {
        if (sVersion == null) {
            check("");
        }
        return sVersion;
    }

    public static boolean check(String rom) {
        if (sName != null) {
            return sName.equals(rom);
        }

        if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {
            sName = ROM_MIUI;
        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {
            sName = ROM_EMUI;
        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {
            sName = ROM_OPPO;
        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {
            sName = ROM_VIVO;
        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {
            sName = ROM_SMARTISAN;
        } else {
            sVersion = Build.DISPLAY;
            if (sVersion.toUpperCase().contains(ROM_FLYME)) {
                sName = ROM_FLYME;
            } else {
                sVersion = Build.UNKNOWN;
                sName = Build.MANUFACTURER.toUpperCase();
            }
        }
        return sName.equals(rom);
    }

    public static String getProp(String name) {
        String line = null;
        BufferedReader input = null;
        try {
            Process p = Runtime.getRuntime().exec("getprop " + name);
            input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
            line = input.readLine();
            input.close();
        } catch (IOException ex) {
            Log.e(TAG, "Unable to read prop " + name, ex);
            return null;
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return line;
    }
}

 悬浮窗写好再把弹出框PopupWindow实现就OK了,应用列表可以使用RecyclerView实现。获取应用程序信息使用PackageManager。

popup_app.xml

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

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview_menu"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_gravity="center"/>

    <ImageView
        android:id="@+id/image_add_menu_item"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/add_fill"
        android:layout_gravity="center"/>

</LinearLayout>

RecyclerView的子布局

menu_recyclerview_item.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="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_menu_app_icon"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_gravity="center"/>
    <TextView
        android:id="@+id/textview_menu_app_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="15dp"
        android:textColor="@color/black"
        android:gravity="center"/>

</LinearLayout>

实体类ItemMenuAppEntity

ItemMenuAppEntity.java 

package com.example.floatingwindow;

import android.graphics.drawable.Drawable;

public class ItemMenuAppEntity {
    private String appName;
    private String appPackage;
    private String appPackageName;
    private Drawable appIcon;
    private boolean displayStatus;

    public ItemMenuAppEntity(){
        super();
    }

    public ItemMenuAppEntity(String appName,String appPackage,String appPackageName,Drawable appIcon,boolean displayStatus){
        super();
        this.appIcon = appIcon;
        this.appName = appName;
        this.appPackage = appPackage;
        this.appPackageName =appPackageName;
        this.displayStatus = displayStatus;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public String getAppPackage() {
        return appPackage;
    }

    public void setAppPackage(String appPackage) {
        this.appPackage = appPackage;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }

    public boolean isDisplayStatus() {
        return displayStatus;
    }

    public void setDisplayStatus(boolean displayStatus) {
        this.displayStatus = displayStatus;
    }

    public String getAppPackageName() {
        return appPackageName;
    }

    public void setAppPackageName(String appPackageName) {
        this.appPackageName = appPackageName;
    }
}

MenuAppRecyclerViewAdapter适配器

MenuAppRecyclerViewAdapter.java

package com.example.floatingwindow;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.widget.PopupWindow;

import java.util.List;

public class MenuAppRecyclerViewAdapter extends RecyclerView.Adapter<MenuAppRecyclerViewAdapter.ViewHolder> {

    private List<ItemMenuAppEntity> mItemMenuAppEntityList;
    private ComponentName mComponentName;
    private Intent mIntent;
    private Context mContext;
    private PopupWindow popupWindow;

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.menu_recyclerview_item,parent,false);
        ViewHolder viewHolder = new ViewHolder(view);
        viewHolder.imageIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position = viewHolder.getAdapterPosition();
                ItemMenuAppEntity mItemMenuAppEntity = mItemMenuAppEntityList.get(position);
                mComponentName = new ComponentName(mItemMenuAppEntity.getAppPackage(),mItemMenuAppEntity.getAppPackageName());
                mIntent = new Intent();
                mIntent.setComponent(mComponentName);
                mContext = view.getContext();
                mContext.startActivity(mIntent);
                popupWindow.dismiss();
            }
        });

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ItemMenuAppEntity itemMenuAppEntity = mItemMenuAppEntityList.get(position);
        holder.imageIcon.setBackground(itemMenuAppEntity.getAppIcon());
        holder.textViewName.setText(itemMenuAppEntity.getAppName());
    }

    @Override
    public int getItemCount() {
        return mItemMenuAppEntityList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder{

        ImageView imageIcon;
        TextView textViewName;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            imageIcon = (ImageView) itemView.findViewById(R.id.image_menu_app_icon);
            textViewName = (TextView) itemView.findViewById(R.id.textview_menu_app_name);
        }
    }

    public MenuAppRecyclerViewAdapter(List<ItemMenuAppEntity> mItemMenuAppEntityList,PopupWindow popupWindow){
        super();
        this.mItemMenuAppEntityList = mItemMenuAppEntityList;
        this.popupWindow = popupWindow;
    }

}

 PopupWindow.java

package com.example.floatingwindow;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class PopupWindow{
    private List<ItemMenuAppEntity> mItemMenuAppEntityList =  new ArrayList<>();
    private Context mContext;
    public void  popupWindow(Context context,View view) {
        mContext = context;
        View inflate = LayoutInflater.from(mContext).inflate(R.layout.popup_app,null);
        initItem();


        /**
         * 创建PopupWindow对象 视图对象, 宽, 高,缺一不可
         * 第一种:创建对象的时候直接加参数 PopupWindow popupWindow = new PopupWindow(inflate, 200, ViewGroup.LayoutParams.WRAP_CONTENT,true);
         * 第二种 通过setContentView,setHeight,setWidth 来设置
         * 宽高可设置固定值或者ViewGroup.LayoutParams.WRAP_CONTENT
         **/
        final android.widget.PopupWindow mPopupWindow = new android.widget.PopupWindow(inflate,ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mPopupWindow.setOutsideTouchable(true);//点击弹窗外面关闭弹窗
        mPopupWindow.setFocusable(true);//设置焦点
        mPopupWindow.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.corners_background));


        RecyclerView recyclerView = (RecyclerView) inflate.findViewById(R.id.recyclerview_menu);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
        recyclerView.setLayoutManager(linearLayoutManager);
        MenuAppRecyclerViewAdapter menuAppRecyclerViewAdapter = new MenuAppRecyclerViewAdapter(mItemMenuAppEntityList,mPopupWindow);
        recyclerView.setAdapter(menuAppRecyclerViewAdapter);
        /**
         * 获取PopupWindow中View的宽高
         */

        inflate.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
        int location[] = new int[2];
        view.getLocationOnScreen(location);

        /**
         * 显示popupwidow两种方式
         * 1.showAsDropDown出现在下方,三个参数:1绑定的控件2.x轴偏移量 3.y轴偏移量
         * 2.showAtLocation自定义位置 四个参数 1绑定的控件 2.出现的位置 3.x轴偏移量 4.y轴偏移量
         *
         **/
        mPopupWindow.showAtLocation(view, Gravity.NO_GRAVITY,location[0]-mPopupWindow.getWidth(),location[1]);

    }
/**
     * 通过PackageManage获取程序包名,程序名,图片等
     */
    public void initItem(){
        mItemMenuAppEntityList.clear();
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        PackageManager mPackageManager = mContext.getApplicationContext().getPackageManager();
        List<ResolveInfo> mResolveInfo = mPackageManager.queryIntentActivities(intent,PackageManager.GET_META_DATA);
        for (ResolveInfo resolveInfo : mResolveInfo){
            String appName = resolveInfo.loadLabel(mPackageManager).toString();
            String appPackage = resolveInfo.activityInfo.packageName;
            String appPackageName = resolveInfo.activityInfo.name;
            Drawable appIcon = resolveInfo.loadIcon(mPackageManager);
            ItemMenuAppEntity mItemMenuAppEntity = new ItemMenuAppEntity(appName,appPackage,appPackageName,appIcon,true);
            mItemMenuAppEntityList.add(mItemMenuAppEntity);
        }
    }
}

注意:与手势导航冲突未解决 ,测试时候关闭手势导航。获取应用程序信息需要添加权限

<uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />

我之后丰富一下功能就不在这更新了,可以查看我的有道笔记

有道云笔记https://note.youdao.com/s/UpbVjGNq 文章来源地址https://www.toymoban.com/news/detail-501896.html

到了这里,关于利用悬浮窗加PopupWindow实现从手机屏幕右边划出应用快捷切换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android PopupWindow+RecyclerView 实现二级联动筛选

    这篇文章主要的功能是利用 PopupWindow 和  RecyclerView 实现条件筛选包括二级联动筛选,主要是仿小红书里的筛选功能而写的一个 Demo 效果如下,代码通俗易懂,保姆级教程 这里我模拟实际接口返回的数据而准备的数据源,在工程目录下新建 assets 资源文件,在新建一个JsonDat

    2024年02月13日
    浏览(62)
  • 微信小程序实现手机屏幕左右旋转,页面元素左右移动,小程序加速计

    在做微信小程序的项目时,有一个需求是当用户左右旋转手机屏幕时,页面上特定的元素要随着用户的旋转动作左右移动。当将手机屏幕向左旋转时,人物向左移动;手机屏幕向右旋转时,人物向右移动。 这里主用到了微信小程序的加速计: 开始监听加速度数据, wx.startA

    2024年02月09日
    浏览(38)
  • SRS OBS利用RTMP协议实现音视频推拉流;WebRTC 屏幕直播分享工具

    参考:https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started 1)docker直接运行SRS服务: 运行起来后可以http://localhost:8080/ 看到服务基本信息: 2) OBS 推流 在设置里设置直播地址: 然后回到首页点击开始直播 3)点击http://localhost:8080/ 可以网页查看流视频 SRS低延迟启动(暂时测试下来延迟

    2024年04月13日
    浏览(40)
  • Spacedesk的安装使用以及常见问题解决(实现笔记本屏幕,手机屏,平板屏互相连接)

    提示:Spacedesk的安装使用(实现笔记本屏幕,手机屏,平板屏互相连接) 提示:Spacedesk的安装使用(实现笔记本屏幕,手机屏,平板屏互相连接) 提示:以下是本篇文章正文内容,下面案例可供参考 实现电脑分屏功能。 主机:必须下载软件spacedesk server (https://spacedesk.net/)

    2024年02月08日
    浏览(46)
  • android-使用PopupWindow实现随机排列的自定义密码键盘

    break; } else { b2 = true; } } if (b2) { data[i] = x; b = false; break; } } } return data; } keyboard_bg_big.xml ?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"? item android:state_pressed=“true” android:drawable=“@drawable/key11”/ item android:state_focused=“true” android:drawable=“@drawable/key12”/ item android:state_focused=“false” android:state_p

    2024年04月27日
    浏览(30)
  • 【iOS免越狱】利用IOS自动化web-driver-agent_appium-实现自动点击+滑动屏幕

    1.目标 在做饭、锻炼等无法腾出双手的场景中,想刷刷抖音 刷抖音的时候有太多的广告 如何解决痛点 抖音自动播放下一个视频  iOS系统高版本无法 越狱 安装插件 2.操作环境 MAC一台,安装 Xcode iPhone一台,16 系统以上最佳  3.流程 下载最新 web-driver-agent_appium xcode 打开  配置

    2024年02月08日
    浏览(32)
  • 在Gazebo中添加悬浮模型后,利用键盘控制其移动方法

    前段时间写了文章,通过修改sdf、urdf模型的方法,在Gazebo中添加悬浮模型方法 / Gazebo中模型如何不因重力下落:在Gazebo中添加悬浮模型方法 / Gazebo中模型如何不因重力下落:修改sdf、urdf模型_sagima_sdu的博客-CSDN博客 今天讲一下如何通过键盘来控制其移动:监听键盘输入并根据

    2024年02月12日
    浏览(23)
  • 苹果手机小圆点怎么设置?悬浮球设置,轻松学会

    很多小伙伴刚接触苹果手机,却发现自己的屏幕上面并没有“小圆点”,这是怎么回事呢?其实“小圆点”也被称为“悬浮球”,苹果手机购买后,是没有“悬浮球”的,这个功能是需要人们手动的去设置出来。那么苹果手机小圆点怎么设置? 如果您想设置苹果手机中的“悬

    2024年02月12日
    浏览(28)
  • 利用Api接口实现手机网络连接断开的监听

    在今天的移动互联网时代,手机已经成为了人们不可或缺的重要工具,而手机的联网状态也是我们经常需要关注的一个问题。我们需要保证手机网络处于正常的连接状态,但是有时候,由于种种原因,手机的网络可能会断开,这时我们需要及时发现,并进行相应的处理措施。

    2024年02月09日
    浏览(33)
  • Android 妙用TextView实现左边文字,右边图片

    原文: Android 妙用TextView实现左边文字,右边图片 - Stars-One的杂货小窝 有时候,需要文字在左边,右边有个箭头,我个人之前会有两种做法: 使用线性布局来实现 或者使用约束布局,一个左对齐,一个右对齐 这几天突然想到是否可以使用TextView的设置图标的方式实现,研究发现确实可以

    2024年02月17日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包