效果如上图所示
安卓小白记录学习过程。一起交流学习。有问题请多多指出。话不多说进入正题。
一、思路
首先明确需求,我们需要做一个右划弹出一个快捷切换应用的弹窗。
悬浮窗可以在其他应用上层显示出来,那么我们可以设置一个透明的悬浮窗让它显示在其他应用上层,然后通过这个悬浮窗只需要写一个滑动的监听事件。满足条件去弹出一个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://www.toymoban.com/news/detail-501896.html
有道云笔记https://note.youdao.com/s/UpbVjGNq 文章来源地址https://www.toymoban.com/news/detail-501896.html
到了这里,关于利用悬浮窗加PopupWindow实现从手机屏幕右边划出应用快捷切换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!