Android Studio實(shí)現(xiàn)自定義全局懸浮按鈕的示例代碼
一、基礎(chǔ)實(shí)現(xiàn)方案
1. 使用 WindowManager 實(shí)現(xiàn)全局懸浮窗
這是最靈活的實(shí)現(xiàn)方式,可以在任何界面顯示懸浮按鈕:
public class FloatingButtonService extends Service {
private WindowManager windowManager;
private View floatingButton;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 創(chuàng)建懸浮按鈕視圖
floatingButton = LayoutInflater.from(this).inflate(R.layout.floating_button, null);
// 設(shè)置按鈕點(diǎn)擊事件
floatingButton.findViewById(R.id.float_button).setOnClickListener(v -> {
// 處理點(diǎn)擊事件
Toast.makeText(this, "懸浮按鈕被點(diǎn)擊", Toast.LENGTH_SHORT).show();
});
// 設(shè)置窗口參數(shù)
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
// 設(shè)置初始位置
params.gravity = Gravity.TOP | Gravity.START;
params.x = 0;
params.y = 100;
// 獲取WindowManager并添加視圖
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(floatingButton, params);
// 添加拖拽功能
addDragFeature();
}
private void addDragFeature() {
floatingButton.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = params.x;
initialY = params.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_MOVE:
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(floatingButton, params);
return true;
}
return false;
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
if (floatingButton != null) {
windowManager.removeView(floatingButton);
}
}
}
2. 布局文件 (res/layout/floating_button.xml)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/float_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/circle_background"
android:src="@drawable/ic_float_button"
android:elevation="8dp"
android:layout_margin="16dp" />
</FrameLayout>
3. 圓形背景 (res/drawable/circle_background.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorPrimary" />
</shape>
4. 啟動(dòng)服務(wù)
// 在需要顯示懸浮按鈕的地方啟動(dòng)服務(wù) startService(new Intent(context, FloatingButtonService.class)); // 停止服務(wù) stopService(new Intent(context, FloatingButtonService.class));
二、權(quán)限處理
1. AndroidManifest.xml 中添加權(quán)限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
2. 檢查并請(qǐng)求權(quán)限
// 檢查懸浮窗權(quán)限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ);
} else {
// 已經(jīng)有權(quán)限,啟動(dòng)服務(wù)
startService(new Intent(this, FloatingButtonService.class));
}
} else {
// 6.0以下直接啟動(dòng)
startService(new Intent(this, FloatingButtonService.class));
}
三、高級(jí)功能擴(kuò)展
1. 添加動(dòng)畫(huà)效果
// 在按鈕點(diǎn)擊時(shí)添加動(dòng)畫(huà)
floatingButton.setOnClickListener(v -> {
// 縮放動(dòng)畫(huà)
ObjectAnimator scaleX = ObjectAnimator.ofFloat(v, "scaleX", 1f, 0.8f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(v, "scaleY", 1f, 0.8f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY);
animatorSet.setDuration(200);
animatorSet.start();
// 執(zhí)行點(diǎn)擊操作
performButtonAction();
});
2. 自動(dòng)吸附邊緣
private void autoAttachToEdge() {
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int buttonWidth = floatingButton.getWidth();
if (params.x < screenWidth / 2 - buttonWidth / 2) {
// 吸附到左邊
params.x = 0;
} else {
// 吸附到右邊
params.x = screenWidth - buttonWidth;
}
windowManager.updateViewLayout(floatingButton, params);
}
3. 顯示/隱藏動(dòng)畫(huà)
public void hideButton() {
floatingButton.animate()
.translationY(floatingButton.getHeight())
.setDuration(300)
.start();
}
public void showButton() {
floatingButton.animate()
.translationY(0)
.setDuration(300)
.start();
}
四、優(yōu)化建議
性能優(yōu)化:
- 使用輕量級(jí)的視圖層級(jí)
- 避免頻繁調(diào)用
updateViewLayout - 使用硬件加速
內(nèi)存管理:
- 在不需要時(shí)及時(shí)移除懸浮窗
- 在低內(nèi)存時(shí)自動(dòng)隱藏
用戶體驗(yàn):
- 添加適當(dāng)?shù)挠|摸反饋
- 考慮屏幕旋轉(zhuǎn)時(shí)的位置調(diào)整
- 提供設(shè)置選項(xiàng)讓用戶自定義位置和行為
兼容性處理:
- 處理不同 Android 版本的權(quán)限差異
- 適配各種屏幕尺寸和密度
- 考慮全面屏和劉海屏的適配
五、替代方案
1. 使用 CoordinatorLayout + FloatingActionButton
如果只需要在應(yīng)用內(nèi)顯示懸浮按鈕,可以使用 Material Design 組件:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 其他內(nèi)容 -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_add" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2. 使用第三方庫(kù)
一些流行的懸浮按鈕庫(kù):
六、常見(jiàn)問(wèn)題解決
權(quán)限問(wèn)題:
- 確保已正確請(qǐng)求
SYSTEM_ALERT_WINDOW權(quán)限 - 在 Android 6.0+ 上需要?jiǎng)討B(tài)請(qǐng)求權(quán)限
- 某些廠商 ROM 可能需要額外的白名單設(shè)置
- 確保已正確請(qǐng)求
位置不正確:
- 檢查
WindowManager.LayoutParams的 gravity 設(shè)置 - 考慮狀態(tài)欄和導(dǎo)航欄的高度
- 在屏幕旋轉(zhuǎn)時(shí)更新位置
- 檢查
點(diǎn)擊穿透:
- 設(shè)置
FLAG_NOT_FOCUSABLE可能導(dǎo)致點(diǎn)擊事件穿透 - 可以通過(guò)在
onTouch中返回true來(lái)攔截事件
- 設(shè)置
內(nèi)存泄漏:
- 確保在服務(wù)銷(xiāo)毀時(shí)移除視圖
- 避免在視圖中持有 Activity 引用
以上就是Android Studio實(shí)現(xiàn)自定義全局懸浮按鈕的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Android Studio懸浮按鈕的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android第三方文件選擇器aFileChooser使用方法詳解
這篇文章主要介紹了Android第三方文件選擇器aFileChooser的使用方法詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Android Java調(diào)用自己C++類(lèi)庫(kù)的實(shí)例講解
今天小編就為大家分享一篇關(guān)于Android Java調(diào)用自己C++類(lèi)庫(kù)的實(shí)例講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02
Android基于Aidl的跨進(jìn)程間雙向通信管理中心
這篇文章主要為大家詳細(xì)介紹了Android基于Aidl的跨進(jìn)程間雙向通信管理中心,類(lèi)似于聊天室,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
android中okhttp實(shí)現(xiàn)斷點(diǎn)上傳示例
本篇文章主要介紹了android中okhttp實(shí)現(xiàn)斷點(diǎn)上傳示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
Android防止按鈕過(guò)快點(diǎn)擊造成多次事件的解決方法
這篇文章主要介紹了Android防止按鈕過(guò)快點(diǎn)擊造成多次事件的解決方法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Android自定義View實(shí)現(xiàn)風(fēng)車(chē)效果
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)風(fēng)車(chē)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
解析android res 運(yùn)行錯(cuò)誤的問(wèn)題
本篇文章是對(duì)android中res運(yùn)行錯(cuò)誤的問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06

