使用Android實現(xiàn)跨頁面懸浮窗效果
實現(xiàn)效果

在 Application#onCreate初始化
FloatingWindowManager
.getInstance(App.this).setImg(R.drawable.ic_test).setWidthHeight(280,280)
.setOnFloatingClickListener(new FloatingWindowManager.OnFloatingClickListener() {
@Override
public void onClick(FrameLayout floatingView) {
Toast.makeText(floatingView.getContext(), "測試點擊懸浮窗", Toast.LENGTH_SHORT).show();
}
});完整代碼
import android.app.Activity;
import android.app.Application;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import java.util.List;
/**
* https://blog.csdn.net/xiaoerbuyu1233/article/details/143595475
* <p>
* 跨頁面懸浮窗 Application#onCreate 初始化
* <p>
* FloatingWindowManager
* .getInstance(App.this).setImg(R.drawable.ic_test).setWidthHeight(280,280)
* .setOnFloatingClickListener(new FloatingWindowManager.OnFloatingClickListener() {
*
* @Override public void onClick(FrameLayout floatingView) {
* Toast.makeText(floatingView.getContext(), "測試點擊懸浮窗", Toast.LENGTH_SHORT).show();
* }
* });
*/
public class FloatingWindowManager {
private static FloatingWindowManager instance;
private final Context context;
private FrameLayout floatingView;
private ViewGroup rootView;
private OnFloatingClickListener listener;
private int width = 200, height = 200;
private Application.ActivityLifecycleCallbacks activityLifecycleCallbacks;
private FloatingWindowManager(Context context) {
this.context = context;
initFloatingView();
registerActivityLifecycleCallbacks();
}
public static synchronized FloatingWindowManager getInstance(Context context) {
if (instance == null) {
instance = new FloatingWindowManager(context);
}
return instance;
}
private void registerActivityLifecycleCallbacks() {
Application application = (Application) context.getApplicationContext();
activityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.d("FloatingWindowManager", "onActivityCreated: " + activity.getLocalClassName());
// 可以在這里附加懸浮窗口到新創(chuàng)建的 Activity
attachToActivity(activity);
}
@Override
public void onActivityStarted(Activity activity) {
Log.d("FloatingWindowManager", "onActivityStarted: " + activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.d("FloatingWindowManager", "onActivityResumed: " + activity.getLocalClassName());
attachToActivity(activity);
}
@Override
public void onActivityPaused(Activity activity) {
detachFromActivity();
Log.d("FloatingWindowManager", "onActivityPaused: " + activity.getLocalClassName());
}
@Override
public void onActivityStopped(Activity activity) {
Log.d("FloatingWindowManager", "onActivityStopped: " + activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.d("FloatingWindowManager", "onActivitySaveInstanceState: " + activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.d("FloatingWindowManager", "onActivityDestroyed: " + activity.getLocalClassName());
}
};
// 注冊 Activity 生命周期回調(diào)
application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
}
public FloatingWindowManager setImg(int icon) {
// 使用資源ID直接設(shè)置背景
if (floatingView != null) {
floatingView.setBackgroundResource(icon);
}
// // 獲取Drawable對象
// Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_test);
//
// // 設(shè)置背景
// if (drawable != null) {
// floatingView.setBackground(drawable);
// }
return this;
}
public FloatingWindowManager setWidthHeight(int width, int height) {
this.width = width;
this.height = height;
// 設(shè)置布局參數(shù)
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height); // 寬度和高度
layoutParams.gravity = Gravity.TOP | Gravity.START;
floatingView.setLayoutParams(layoutParams);
return this;
}
private void initFloatingView() {
// 初始化懸浮窗視圖
floatingView = new FrameLayout(context) {
@Override
public boolean performClick() {
if (super.performClick()) {
return true;
}
if (listener != null) {
floatingView.getHandler().post(() -> listener.onClick(floatingView));
}
return true;
}
};
floatingView.setOnTouchListener(new View.OnTouchListener() {
private int initialX, initialY;
private float startX, startY;
private static final int CLICK_DRAG_TOLERANCE = 40; // 點擊和拖動之間的容差距離
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = (int) (event.getRawX() - v.getX());
initialY = (int) (event.getRawY() - v.getY());
startX = event.getRawX();
startY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int newX = (int) (event.getRawX() - initialX);
int newY = (int) (event.getRawY() - initialY);
if (rootView != null) {
v.setX(newX);
v.setY(newY);
}
break;
case MotionEvent.ACTION_UP:
float endX = event.getRawX();
float endY = event.getRawY();
float distanceX = Math.abs(endX - startX);
float distanceY = Math.abs(endY - startY);
if (distanceX < CLICK_DRAG_TOLERANCE && distanceY < CLICK_DRAG_TOLERANCE) {
// 如果移動的距離小于容差,那么我們認為這是一個點擊
if (floatingView.performClick()) {
return true; // 點擊已被處理
}
} else {
// 如果移動的距離大于容差,那么我們認為這是一個拖動
snapToEdge();
}
break;
default:
break;
}
return true; // 消耗事件
}
});
// 設(shè)置布局參數(shù)
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height); // 寬度和高度
layoutParams.gravity = Gravity.TOP | Gravity.START;
floatingView.setLayoutParams(layoutParams);
}
public void attachToActivity(Activity activity) {
if (activity == null || floatingView == null) return;
rootView = (ViewGroup) activity.findViewById(android.R.id.content);
if (rootView != null && floatingView.getParent() == null) {
rootView.addView(floatingView);
}
}
public void detachFromActivity() {
if (rootView != null && floatingView != null && floatingView.getParent() != null) {
rootView.removeView(floatingView);
}
}
public void setOnFloatingClickListener(OnFloatingClickListener listener) {
this.listener = listener;
}
private void snapToEdge() {
// 實現(xiàn)貼邊功能
// 這里只是一個簡單的例子,你可以根據(jù)自己的需求調(diào)整貼邊的具體實現(xiàn)
int[] location = new int[2];
floatingView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
int screenWidth = rootView.getWidth();
int screenHeight = rootView.getHeight();
int halfScreenWidth = screenWidth / 4; // 假設(shè)屏幕寬度的3/4處作為貼邊判斷點
if (x < halfScreenWidth) {
floatingView.setX(0);
} else {
floatingView.setX(screenWidth - floatingView.getWidth());
}
}
public interface OnFloatingClickListener {
void onClick(FrameLayout floatingView);
}
/**
* 顯示一個列表對話框,用戶點擊列表項后會將該項內(nèi)容復制到剪貼板
*
* @param context 上下文
* @param items 列表項數(shù)據(jù)
*/
public static void showListDialogCopy(Context context, String title, List<String> items) {
// 創(chuàng)建一個AlertDialog.Builder對象
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// 設(shè)置對話框標題
builder.setTitle(title);
// 設(shè)置列表項
builder.setItems(items.toArray(new CharSequence[0]), (dialog, which) -> {
// 獲取用戶選擇的項
String selectedItem = items.get(which);
// 復制文本到剪貼板
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label", selectedItem);
clipboard.setPrimaryClip(clip);
// 可選: 提示用戶已成功復制
Toast.makeText(context, "已復制: " + selectedItem, Toast.LENGTH_SHORT).show();
// 關(guān)閉對話框
dialog.dismiss();
});
// 創(chuàng)建并顯示對話框
AlertDialog dialog = builder.create();
dialog.show();
}
}代碼很簡單不多解釋 無非是添加隱藏
到此這篇關(guān)于使用Android實現(xiàn)跨頁面懸浮窗效果的文章就介紹到這了,更多相關(guān)Android跨頁面懸浮窗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Flutter實現(xiàn)單選,復選和開關(guān)組件的示例代碼
在App開發(fā)過程中,選擇交互是非常常見的,今天主要介紹下關(guān)于選擇的三個組件的使用:開關(guān)、單選和復選,感興趣的小伙伴可以了解一下2022-04-04
Android開發(fā)學習筆記 Gallery和GridView淺析
這篇文章主要介紹了Android開發(fā)學習筆記 Gallery和GridView淺析,需要的朋友可以參考下2014-11-11
Android 自定義view實現(xiàn)TopBar效果
這篇文章主要為大家詳細介紹了Android 自定義view實現(xiàn)TopBar效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
Android開發(fā)之Picasso通過URL獲取用戶頭像的圓形顯示
這篇文章主要介紹了android開發(fā)之Picasso通過URL獲取用戶頭像的圓形顯示,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-06-06
Android利用ViewDragHelper輕松實現(xiàn)拼圖游戲的示例
本篇文章主要介紹了Android利用ViewDragHelper輕松實現(xiàn)拼圖游戲的示例,非常具有實用價值,需要的朋友可以參考下2017-11-11
android 選項卡(TabHost)如何放置在屏幕的底部
如何將TAB放置在屏幕的底端,有很多的新手都想實現(xiàn)這種效果,本文搜集整理了一些,感興趣的朋友可以參考下哦2013-01-01

