initializeViews()
初始化
把全部的按鈕都弄出來
// 主菜單按鈕ImageButton mainButton = floatingMenuView.findViewById(R.id.main_button);// 二級菜單按鈕subButtons = new ImageButton[3];subButtons[0] = floatingMenuView.findViewById(R.id.sub_button_1);subButtons[1] = floatingMenuView.findViewById(R.id.sub_button_2);subButtons[2] = floatingMenuView.findViewById(R.id.sub_button_3);// 三級菜單按鈕初始化thirdLevelButtons = new ImageButton[3][3];// 第一組三級按鈕 (從子按鈕1展開)thirdLevelButtons[0][0] = floatingMenuView.findViewById(R.id.third_level_1_1);thirdLevelButtons[0][1] = floatingMenuView.findViewById(R.id.third_level_1_2);thirdLevelButtons[0][2] = floatingMenuView.findViewById(R.id.third_level_1_3);// 第二組三級按鈕 (從子按鈕2展開)thirdLevelButtons[1][0] = floatingMenuView.findViewById(R.id.third_level_2_1);thirdLevelButtons[1][1] = floatingMenuView.findViewById(R.id.third_level_2_2);thirdLevelButtons[1][2] = floatingMenuView.findViewById(R.id.third_level_2_3);// 第三組三級按鈕 (從子按鈕3展開)thirdLevelButtons[2][0] = floatingMenuView.findViewById(R.id.third_level_3_1);thirdLevelButtons[2][1] = floatingMenuView.findViewById(R.id.third_level_3_2);thirdLevelButtons[2][2] = floatingMenuView.findViewById(R.id.third_level_3_3);
然后就用button.setVisibility(View.GONE);把全部二級菜單全部隱藏起來
for循環也把三級菜單隱藏起來
// 初始隱藏所有二級和三級菜單for (ImageButton button : subButtons) {button.setVisibility(View.GONE);}for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {thirdLevelButtons[i][j].setVisibility(View.GONE);}}
所有的按鈕都設置一下點擊監聽一下
// 設置主按鈕點擊事件mainButton.setOnClickListener(v -> toggleMainMenu());// 設置各個二級按鈕的點擊事件subButtons[0].setOnClickListener(v -> toggleThirdLevelMenu(0));subButtons[1].setOnClickListener(v -> toggleThirdLevelMenu(1));subButtons[2].setOnClickListener(v -> toggleThirdLevelMenu(2));// 設置三級按鈕點擊事件for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {final int groupIndex = i;final int buttonIndex = j;thirdLevelButtons[i][j].setOnClickListener(v -> {// 處理三級按鈕點擊Toast.makeText(this, "點擊了按鈕組" + (groupIndex + 1) + "的第" + (buttonIndex + 1) + "個按鈕", Toast.LENGTH_SHORT).show();});}}
在設置一下滑動監聽
setupDragListener(mainButton);
123
├── toggleMainMenu()
│ ├── 展開/收起二級菜單
│ └── 控制動畫
│
├── toggleThirdLevelMenu()
│ ├── 展開/收起三級菜單
│ └── 控制動畫
│
├── hideThirdLevelMenu()
│ └── 隱藏指定組的三級菜單
│
└── onDestroy()└── 移除懸浮窗視圖
123
完整代碼
FloatingMenuService.java
package com.example.testtest;import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.Toast;public class FloatingMenuService extends Service {private WindowManager windowManager;private View floatingMenuView;private WindowManager.LayoutParams params;private boolean isMenuExpanded = false;private ImageButton[] subButtons;private ImageButton[][] thirdLevelButtons;private boolean[] isThirdLevelExpanded = {false, false, false};private int initialX, initialY;private float initialTouchX, initialTouchY;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();// 初始化WindowManagerwindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);// 加載懸浮窗布局floatingMenuView = LayoutInflater.from(this).inflate(R.layout.floating_menu, null);// 設置窗口參數params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,getLayoutType(),WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,PixelFormat.TRANSLUCENT);params.gravity = Gravity.TOP | Gravity.START;params.x = 0;params.y = 100;// 添加視圖到窗口windowManager.addView(floatingMenuView, params);// 初始化視圖initializeViews();}private int getLayoutType() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {return WindowManager.LayoutParams.TYPE_PHONE;}}private void initializeViews() {// 主菜單按鈕ImageButton mainButton = floatingMenuView.findViewById(R.id.main_button);// 二級菜單按鈕subButtons = new ImageButton[3];subButtons[0] = floatingMenuView.findViewById(R.id.sub_button_1);subButtons[1] = floatingMenuView.findViewById(R.id.sub_button_2);subButtons[2] = floatingMenuView.findViewById(R.id.sub_button_3);// 三級菜單按鈕初始化thirdLevelButtons = new ImageButton[3][3];// 第一組三級按鈕 (從子按鈕1展開)thirdLevelButtons[0][0] = floatingMenuView.findViewById(R.id.third_level_1_1);thirdLevelButtons[0][1] = floatingMenuView.findViewById(R.id.third_level_1_2);thirdLevelButtons[0][2] = floatingMenuView.findViewById(R.id.third_level_1_3);// 第二組三級按鈕 (從子按鈕2展開)thirdLevelButtons[1][0] = floatingMenuView.findViewById(R.id.third_level_2_1);thirdLevelButtons[1][1] = floatingMenuView.findViewById(R.id.third_level_2_2);thirdLevelButtons[1][2] = floatingMenuView.findViewById(R.id.third_level_2_3);// 第三組三級按鈕 (從子按鈕3展開)thirdLevelButtons[2][0] = floatingMenuView.findViewById(R.id.third_level_3_1);thirdLevelButtons[2][1] = floatingMenuView.findViewById(R.id.third_level_3_2);thirdLevelButtons[2][2] = floatingMenuView.findViewById(R.id.third_level_3_3);// 初始隱藏所有二級和三級菜單for (ImageButton button : subButtons) {button.setVisibility(View.GONE);}for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {thirdLevelButtons[i][j].setVisibility(View.GONE);}}// 設置主按鈕點擊事件mainButton.setOnClickListener(v -> toggleMainMenu());// 設置各個二級按鈕的點擊事件subButtons[0].setOnClickListener(v -> toggleThirdLevelMenu(0));subButtons[1].setOnClickListener(v -> toggleThirdLevelMenu(1));subButtons[2].setOnClickListener(v -> toggleThirdLevelMenu(2));// 設置三級按鈕點擊事件for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {final int groupIndex = i;final int buttonIndex = j;thirdLevelButtons[i][j].setOnClickListener(v -> {// 處理三級按鈕點擊Toast.makeText(this, "點擊了按鈕組" + (groupIndex + 1) + "的第" + (buttonIndex + 1) + "個按鈕", Toast.LENGTH_SHORT).show();});}}// 設置拖動事件setupDragListener(mainButton);}private void toggleMainMenu() {isMenuExpanded = !isMenuExpanded;// 如果要收起主菜單,也要收起所有三級菜單if (!isMenuExpanded) {// 收起所有三級菜單for (int i = 0; i < isThirdLevelExpanded.length; i++) {if (isThirdLevelExpanded[i]) {hideThirdLevelMenu(i, true);}}}if (isMenuExpanded) {// 展開菜單for (int i = 0; i < subButtons.length; i++) {ImageButton button = subButtons[i];button.setVisibility(View.VISIBLE);// 加載動畫Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in);animation.setStartOffset(i * 100); // 設置延遲,實現順序展開效果button.startAnimation(animation);}} else {// 收起菜單for (int i = 0; i < subButtons.length; i++) {ImageButton button = subButtons[i];// 加載動畫Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);animation.setStartOffset((subButtons.length - 1 - i) * 100); // 設置延遲,實現順序收起效果button.startAnimation(animation);// 設置動畫結束監聽器final int index = i;animation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {subButtons[index].setVisibility(View.GONE);}@Overridepublic void onAnimationRepeat(Animation animation) {}});button.startAnimation(animation);}}}private void toggleThirdLevelMenu(int groupIndex) {isThirdLevelExpanded[groupIndex] = !isThirdLevelExpanded[groupIndex];// 收起其他三級菜單for (int i = 0; i < isThirdLevelExpanded.length; i++) {if (i != groupIndex && isThirdLevelExpanded[i]) {hideThirdLevelMenu(i, false);isThirdLevelExpanded[i] = false;}}if (isThirdLevelExpanded[groupIndex]) {// 展開對應的三級菜單for (int i = 0; i < 3; i++) {ImageButton button = thirdLevelButtons[groupIndex][i];button.setVisibility(View.VISIBLE);// 加載動畫Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in);animation.setStartOffset(i * 70); // 設置較短的延遲,三級菜單展開稍快button.startAnimation(animation);}} else {// 收起對應的三級菜單hideThirdLevelMenu(groupIndex, false);}}private void hideThirdLevelMenu(int groupIndex, boolean immediately) {for (int i = 0; i < 3; i++) {ImageButton button = thirdLevelButtons[groupIndex][i];if (immediately) {button.clearAnimation();button.setVisibility(View.GONE);continue;}// 加載動畫Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);animation.setStartOffset((3 - 1 - i) * 70); // 設置較短的延遲button.startAnimation(animation);// 設置動畫結束監聽器final int index = i;animation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {thirdLevelButtons[groupIndex][index].setVisibility(View.GONE);}@Overridepublic void onAnimationRepeat(Animation animation) {}});button.startAnimation(animation);}}private void setupDragListener(View view) {view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic 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(floatingMenuView, params);return true;case MotionEvent.ACTION_UP:// 如果移動距離很小,則視為點擊int xDiff = (int) (event.getRawX() - initialTouchX);int yDiff = (int) (event.getRawY() - initialTouchY);if (Math.abs(xDiff) < 5 && Math.abs(yDiff) < 5) {v.performClick();}return true;}return false;}});}@Overridepublic void onDestroy() {super.onDestroy();if (floatingMenuView != null && windowManager != null) {windowManager.removeView(floatingMenuView);}}
}
MainActivity.java
package com.example.testtest;import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private static final int OVERLAY_PERMISSION_CODE = 100;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button startButton = findViewById(R.id.start_floating_button);startButton.setOnClickListener(v -> checkOverlayPermission());}private void checkOverlayPermission() {// 檢查是否已有懸浮窗權限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {// 如果沒有權限,請求權限Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));// Android 12之前使用startActivityForResultif (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {startActivityForResult(intent, OVERLAY_PERMISSION_CODE);} else {// Android 12及以上使用ActivityResultLaunchertry {overlayPermissionLauncher.launch(intent);} catch (Exception e) {Toast.makeText(this, "打開權限設置頁面失敗", Toast.LENGTH_SHORT).show();}}} else {// 已有權限,啟動懸浮窗服務startFloatingMenuService();}}// 用于Android 12及以上版本的權限請求結果處理private final ActivityResultLauncher<Intent> overlayPermissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {// 檢查用戶是否授予了權限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {startFloatingMenuService();} else {Toast.makeText(this, "需要懸浮窗權限才能使用此功能", Toast.LENGTH_SHORT).show();}});@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);// 處理Android 12之前的權限請求結果if (requestCode == OVERLAY_PERMISSION_CODE) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {startFloatingMenuService();} else {Toast.makeText(this, "需要懸浮窗權限才能使用此功能", Toast.LENGTH_SHORT).show();}}}private void startFloatingMenuService() {Intent serviceIntent = new Intent(MainActivity.this, FloatingMenuService.class);startService(serviceIntent);// 可選:啟動服務后可以關閉Activity// finish();}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="16dp"tools:context=".MainActivity"><TextViewandroid:id="@+id/title_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_marginTop="50dp"android:text="懸浮窗菜單示例"android:textSize="24sp"android:textStyle="bold" /><TextViewandroid:id="@+id/description_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/title_text"android:layout_marginTop="20dp"android:gravity="center"android:text="點擊下方按鈕啟動帶有菜單功能的懸浮窗"android:textSize="16sp" /><Buttonandroid:id="@+id/start_floating_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:padding="12dp"android:text="啟動懸浮窗"android:textSize="18sp" /></RelativeLayout>
floating_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="16dp"><!-- 三級按鈕組1 (顯示在子按鈕1下方) --><ImageButtonandroid:id="@+id/third_level_1_3"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_1"android:layout_marginTop="8dp"android:layout_alignEnd="@+id/sub_button_1"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_1_3"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_1" /><ImageButtonandroid:id="@+id/third_level_1_2"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_1"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_1_3"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_1_2"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_2" /><ImageButtonandroid:id="@+id/third_level_1_1"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_1"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_1_2"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_1_1"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_3" /><!-- 三級按鈕組2 (顯示在子按鈕2下方) --><ImageButtonandroid:id="@+id/third_level_2_3"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_2"android:layout_marginTop="8dp"android:layout_alignEnd="@+id/sub_button_2"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_2_3"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_1" /><ImageButtonandroid:id="@+id/third_level_2_2"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_2"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_2_3"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_2_2"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_2" /><ImageButtonandroid:id="@+id/third_level_2_1"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_2"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_2_2"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_2_1"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_3" /><!-- 三級按鈕組3 (顯示在子按鈕3下方) --><ImageButtonandroid:id="@+id/third_level_3_3"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_3"android:layout_marginTop="8dp"android:layout_alignEnd="@+id/sub_button_3"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_3_3"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_1" /><ImageButtonandroid:id="@+id/third_level_3_2"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_3"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_3_3"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_3_2"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_2" /><ImageButtonandroid:id="@+id/third_level_3_1"android:layout_width="40dp"android:layout_height="40dp"android:layout_below="@+id/sub_button_3"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:layout_toStartOf="@+id/third_level_3_2"android:background="@drawable/circle_third_button_bg"android:contentDescription="@string/third_level_3_1"android:padding="8dp"android:visibility="gone"android:src="@drawable/ic_button_3" /><!-- 子按鈕3 --><ImageButtonandroid:id="@+id/sub_button_3"android:layout_width="48dp"android:layout_height="48dp"android:layout_marginEnd="16dp"android:layout_toStartOf="@+id/sub_button_2"android:background="@drawable/circle_button_bg"android:contentDescription="@string/sub_button_3"android:padding="8dp"android:src="@drawable/ic_button_3" /><!-- 子按鈕2 --><ImageButtonandroid:id="@+id/sub_button_2"android:layout_width="48dp"android:layout_height="48dp"android:layout_marginEnd="16dp"android:layout_toStartOf="@+id/sub_button_1"android:background="@drawable/circle_button_bg"android:contentDescription="@string/sub_button_2"android:padding="8dp"android:src="@drawable/ic_button_2" /><!-- 子按鈕1 --><ImageButtonandroid:id="@+id/sub_button_1"android:layout_width="48dp"android:layout_height="48dp"android:layout_marginEnd="16dp"android:layout_toStartOf="@+id/main_button"android:background="@drawable/circle_button_bg"android:contentDescription="@string/sub_button_1"android:padding="8dp"android:src="@drawable/ic_button_1" /><!-- 主按鈕 --><ImageButtonandroid:id="@+id/main_button"android:layout_width="56dp"android:layout_height="56dp"android:layout_alignParentEnd="true"android:background="@drawable/circle_main_button_bg"android:contentDescription="@string/main_button"android:padding="8dp"android:src="@drawable/ic_menu" /></RelativeLayout>
123
彈窗
1. 創建一個基本彈窗
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示").setMessage("確認刪除嗎?").setPositiveButton("確定", (dialog, which) -> {// 確定按鈕點擊邏輯Toast.makeText(this, "已刪除", Toast.LENGTH_SHORT).show();}).setNegativeButton("取消", null).show();
2. 自定義布局彈窗
AlertDialog.Builder builder = new AlertDialog.Builder(this);// 加載自定義布局
View customView = LayoutInflater.from(this).inflate(R.layout.custom_dialog, null);
builder.setView(customView);AlertDialog dialog = builder.create();
dialog.show();// 綁定自定義布局中的組件
Button btnSubmit = customView.findViewById(R.id.btn_submit);
btnSubmit.setOnClickListener(v -> {dialog.dismiss(); // 關閉彈窗
});
容器
- 場景??:當需要在一個彈窗中同時包含??輸入框、按鈕、標題??等多個組件時,容器可以將這些元素組織成一個整體。
- ??優勢??:模塊化的布局更易擴展和維護,例如后續新增一個按鈕只需添加到容器中
// 創建容器并添加多個子視圖
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(50, 30, 50, 10);TextView title = new TextView(context);
title.setText("用戶信息");
container.addView(title);EditText input = new EditText(context);
container.addView(input);Button submitBtn = new Button(context);
submitBtn.setText("提交");
container.addView(submitBtn);
設置監聽
// 創建容器并添加多個子視圖
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(50, 30, 50, 10); // 注意:建議使用 dp 單位(見下文注意事項)TextView title = new TextView(context);
title.setText("用戶信息");
container.addView(title);EditText input = new EditText(context);
container.addView(input);Button submitBtn = new Button(context);
submitBtn.setText("提交");// 設置點擊監聽
submitBtn.setOnClickListener(v -> {String text = input.getText().toString();if (!text.isEmpty()) {Toast.makeText(context, "提交內容:" + text, Toast.LENGTH_SHORT).show();} else {Toast.makeText(context, "請輸入內容", Toast.LENGTH_SHORT).show();}
});container.addView(submitBtn);
改進后的MainActivity.java
package com.example.testtest;import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private static final int OVERLAY_PERMISSION_CODE = 100;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button startButton = findViewById(R.id.start_floating_button);startButton.setOnClickListener(v -> checkOverlayPermission());}private void checkOverlayPermission() {// 檢查是否已有懸浮窗權限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {// 如果沒有權限,請求權限Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));// Android 12之前使用startActivityForResultif (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {startActivityForResult(intent, OVERLAY_PERMISSION_CODE);} else {// Android 12及以上使用ActivityResultLaunchertry {overlayPermissionLauncher.launch(intent);} catch (Exception e) {Toast.makeText(this, "打開權限設置頁面失敗", Toast.LENGTH_SHORT).show();}}} else {// 已有權限,啟動懸浮窗服務startFloatingMenuService();}}// 用于Android 12及以上版本的權限請求結果處理private final ActivityResultLauncher<Intent> overlayPermissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {// 檢查用戶是否授予了權限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {startFloatingMenuService();} else {Toast.makeText(this, "需要懸浮窗權限才能使用此功能", Toast.LENGTH_SHORT).show();}});@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);// 處理Android 12之前的權限請求結果if (requestCode == OVERLAY_PERMISSION_CODE) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {startFloatingMenuService();} else {Toast.makeText(this, "需要懸浮窗權限才能使用此功能", Toast.LENGTH_SHORT).show();}}}private void startFloatingMenuService() {Intent serviceIntent = new Intent(MainActivity.this, FloatingMenuService.class);startService(serviceIntent);// 可選:啟動服務后可以關閉Activity// finish();}
}