diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index e3b1a28..3dee57c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -27,7 +27,10 @@
-
+
diff --git a/android/app/src/main/java/com/hyzq/boss/BossWindowInsets.java b/android/app/src/main/java/com/hyzq/boss/BossWindowInsets.java
index 8076ef1..9f87348 100644
--- a/android/app/src/main/java/com/hyzq/boss/BossWindowInsets.java
+++ b/android/app/src/main/java/com/hyzq/boss/BossWindowInsets.java
@@ -49,4 +49,45 @@ public final class BossWindowInsets {
}
});
}
+
+ public static void applyKeyboardAvoidingInset(View view) {
+ if (view == null) {
+ return;
+ }
+ final int initialLeft = view.getPaddingLeft();
+ final int initialTop = view.getPaddingTop();
+ final int initialRight = view.getPaddingRight();
+ final int initialBottom = view.getPaddingBottom();
+
+ ViewCompat.setOnApplyWindowInsetsListener(view, (target, insets) -> {
+ Insets navigationInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars());
+ Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
+ int bottomInset = Math.max(navigationInsets.bottom, imeInsets.bottom);
+ target.setPadding(
+ initialLeft,
+ initialTop,
+ initialRight,
+ initialBottom + bottomInset
+ );
+ return insets;
+ });
+
+ if (ViewCompat.isAttachedToWindow(view)) {
+ ViewCompat.requestApplyInsets(view);
+ return;
+ }
+
+ view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ v.removeOnAttachStateChangeListener(this);
+ ViewCompat.requestApplyInsets(v);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // no-op
+ }
+ });
+ }
}
diff --git a/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java b/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java
index 4d827a5..9a56e2d 100644
--- a/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java
+++ b/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java
@@ -178,6 +178,9 @@ public class ProjectDetailActivity extends BossScreenActivity {
uri -> onAttachmentPicked(uri, "file")
);
+ BossWindowInsets.applyKeyboardAvoidingInset(composerRow);
+ BossWindowInsets.applyKeyboardAvoidingInset(multiSelectActionsLayout);
+
updateProjectHeader(initialProjectName == null ? "项目详情" : initialProjectName, "正在同步项目详情...");
if (composerAttachmentButton != null) {
composerAttachmentButton.setOnClickListener(v -> showAttachmentEntrySheet());
diff --git a/android/app/src/test/java/com/hyzq/boss/BossWindowInsetsTest.java b/android/app/src/test/java/com/hyzq/boss/BossWindowInsetsTest.java
index ef22d38..c646842 100644
--- a/android/app/src/test/java/com/hyzq/boss/BossWindowInsetsTest.java
+++ b/android/app/src/test/java/com/hyzq/boss/BossWindowInsetsTest.java
@@ -35,4 +35,25 @@ public class BossWindowInsetsTest {
assertEquals(20, view.getPaddingBottom());
assertEquals(insets, applied);
}
+
+ @Test
+ public void applyKeyboardAvoidingInset_addsImeInsetToBottomPadding() {
+ View view = new View(RuntimeEnvironment.getApplication());
+ view.setPadding(10, 12, 14, 16);
+
+ BossWindowInsets.applyKeyboardAvoidingInset(view);
+
+ WindowInsetsCompat insets = new WindowInsetsCompat.Builder()
+ .setInsets(WindowInsetsCompat.Type.navigationBars(), Insets.of(0, 0, 0, 24))
+ .setInsets(WindowInsetsCompat.Type.ime(), Insets.of(0, 0, 0, 180))
+ .build();
+
+ WindowInsetsCompat applied = androidx.core.view.ViewCompat.dispatchApplyWindowInsets(view, insets);
+
+ assertEquals(10, view.getPaddingLeft());
+ assertEquals(12, view.getPaddingTop());
+ assertEquals(14, view.getPaddingRight());
+ assertEquals(196, view.getPaddingBottom());
+ assertEquals(insets, applied);
+ }
}