隐藏statusBar时如何强制windowSoftInputMode adjustResize
How to force windowSoftInputMode adjustResize when statusBar is hidden
我一直在努力让它发挥作用。只要我保持状态栏可见,应用程序就会调整大小。根据此 post 这是一个 android 错误,但问题已关闭但未解决。
从我读到的所有内容来看,使用 Insets 应该可以解决问题,但我无法将其付诸实践。不确定是否应该走这条路。
在此之后 我将以下代码添加到 OnCreate。
ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView().getRootView(), new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
return insets.consumeSystemWindowInsets();
}
});
抛出异常:
java.lang.ClassCastException: android.view.WindowManager$LayoutParams
cannot be cast to android.view.ViewGroup$MarginLayoutParams
post 继续,但我被困在这里并且怀疑我是否走对了路。
下面是我正在使用的测试代码,如果有人想尝试的话。
在通过向 AppTheme 添加 <item name="android:windowFullscreen">true</item>
删除状态栏之前,效果很好。
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
activity_mail.xml:
<!-- this control should be position static -->
<TextView
android:layout_height="50dp"
android:layout_width="fill_parent"
android:background="@color/colorPrimaryDark"
android:text="static window at top"
android:gravity="center"
/>
<!-- the resizable view -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:transcriptMode="normal">
</android.support.v7.widget.RecyclerView>
<!-- use this EditText box to call softKeyboard-->
<android.support.v7.widget.AppCompatEditText
android:id="@+id/cv_bottom_bar_edit"
style="@style/Widget.AppCompat.AutoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="18sp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
/>
row.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F06060"
android:layout_margin="30dp"
android:padding="5dp"
android:textSize="25sp"
android:gravity="center"
>
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.my_list);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
String[] myDataset = new String[]{"1", "2", "3","4","5","6","7","8","9"};
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
更新:
我将 windowFullscreen 属性从清单移到了 AppTheme,因为 Android 没有从清单中读取它。
注意这一行:
((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();//what's the parent of "view"
按照getLayoutParams的说法,你应该知道"view"的父级是什么,比如父级是FrameLayout
,那么就这样做:
((FrameLayout.LayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
如果parent是relativelayout或者linearlayout,也像上面那样切换到definite type。
编辑:试试这个:
((WindowManager.LayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
public class AndroidBug5497Workaround extends AppCompatActivity {
// For more information, see https://issuetracker.google.com/issues/36911528
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
private ViewGroup contentContainer;
private ViewTreeObserver viewTreeObserver;
private Rect contentAreaOfWindowBounds = new Rect();
private LinearLayout.LayoutParams rootViewLayout; //-->change to the view root control type of your view.
private int usableHeightPrevious = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
contentContainer = findViewById(android.R.id.content);
rootViewLayout = (LinearLayout.LayoutParams) contentContainer.getLayoutParams();
}
@Override
protected void onPause() {
super.onPause();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeOnGlobalLayoutListener(listener);
}
}
@Override
protected void onResume() {
super.onResume();
if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
viewTreeObserver = contentContainer.getViewTreeObserver();
}
viewTreeObserver.addOnGlobalLayoutListener(listener);
}
@Override
protected void onDestroy() {
super.onDestroy();
contentContainer = null;
viewTreeObserver = null;
}
ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow;
contentContainer.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
contentContainer.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
};
}
从 github 的 facebook/react-native 问题中获得。稍微简化了一个常见的 activity。来自 api 21 的纵向和横向效果很好,但它没有比这更多的测试。小心使用。
我一直在努力让它发挥作用。只要我保持状态栏可见,应用程序就会调整大小。根据此 post 这是一个 android 错误,但问题已关闭但未解决。
从我读到的所有内容来看,使用 Insets 应该可以解决问题,但我无法将其付诸实践。不确定是否应该走这条路。
在此之后
ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView().getRootView(), new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
return insets.consumeSystemWindowInsets();
}
});
抛出异常:
java.lang.ClassCastException: android.view.WindowManager$LayoutParams cannot be cast to android.view.ViewGroup$MarginLayoutParams
post 继续,但我被困在这里并且怀疑我是否走对了路。
下面是我正在使用的测试代码,如果有人想尝试的话。
在通过向 AppTheme 添加 <item name="android:windowFullscreen">true</item>
删除状态栏之前,效果很好。
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
activity_mail.xml:
<!-- this control should be position static -->
<TextView
android:layout_height="50dp"
android:layout_width="fill_parent"
android:background="@color/colorPrimaryDark"
android:text="static window at top"
android:gravity="center"
/>
<!-- the resizable view -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:transcriptMode="normal">
</android.support.v7.widget.RecyclerView>
<!-- use this EditText box to call softKeyboard-->
<android.support.v7.widget.AppCompatEditText
android:id="@+id/cv_bottom_bar_edit"
style="@style/Widget.AppCompat.AutoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="18sp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
/>
row.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F06060"
android:layout_margin="30dp"
android:padding="5dp"
android:textSize="25sp"
android:gravity="center"
>
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.my_list);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
String[] myDataset = new String[]{"1", "2", "3","4","5","6","7","8","9"};
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
更新: 我将 windowFullscreen 属性从清单移到了 AppTheme,因为 Android 没有从清单中读取它。
注意这一行:
((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();//what's the parent of "view"
按照getLayoutParams的说法,你应该知道"view"的父级是什么,比如父级是FrameLayout
,那么就这样做:
((FrameLayout.LayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
如果parent是relativelayout或者linearlayout,也像上面那样切换到definite type。
编辑:试试这个:
((WindowManager.LayoutParams) view.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
public class AndroidBug5497Workaround extends AppCompatActivity {
// For more information, see https://issuetracker.google.com/issues/36911528
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
private ViewGroup contentContainer;
private ViewTreeObserver viewTreeObserver;
private Rect contentAreaOfWindowBounds = new Rect();
private LinearLayout.LayoutParams rootViewLayout; //-->change to the view root control type of your view.
private int usableHeightPrevious = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
contentContainer = findViewById(android.R.id.content);
rootViewLayout = (LinearLayout.LayoutParams) contentContainer.getLayoutParams();
}
@Override
protected void onPause() {
super.onPause();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeOnGlobalLayoutListener(listener);
}
}
@Override
protected void onResume() {
super.onResume();
if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
viewTreeObserver = contentContainer.getViewTreeObserver();
}
viewTreeObserver.addOnGlobalLayoutListener(listener);
}
@Override
protected void onDestroy() {
super.onDestroy();
contentContainer = null;
viewTreeObserver = null;
}
ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow;
contentContainer.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
contentContainer.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
};
}
从 github 的 facebook/react-native 问题中获得。稍微简化了一个常见的 activity。来自 api 21 的纵向和横向效果很好,但它没有比这更多的测试。小心使用。