隐藏状态栏时如何强制windowSoftInputMode调整大小

Posted

技术标签:

【中文标题】隐藏状态栏时如何强制windowSoftInputMode调整大小【英文标题】:How to force windowSoftInputMode adjustResize when statusBar is hidden 【发布时间】:2019-02-22 23:58:02 【问题描述】:

我一直在努力让它发挥作用。只要我保持状态栏可见,该应用程序就可以很好地调整大小。根据这个post 这是一个android bug,但问题已关闭但未解决。

从我读到的所有内容来看,玩 Insets 应该可以解决问题,但我无法让它发挥作用。不知道是否应该走这条路。

在post 之后,我将以下代码添加到 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 无法转换为 android.view.ViewGroup$MarginLayoutParams

帖子还在继续,但我被困在这里,怀疑我是否走对了路。

如果有人想尝试,请查看我正在使用的测试代码。 在通过将<item name="android:windowFullscreen">true</item> 添加到 AppTheme 来删除状态栏之前运行良好。

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_
        android:layout_
        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_
    android:layout_
    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_
    android:layout_
    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_
    android:layout_
    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 没有从清单中读取它。

【问题讨论】:

【参考方案1】:
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;
        
    
;

从facebook/react-native github 上的问题中获得。稍微简化了一个常见的活动。从 api 21 开始适用于纵向和横向,但它的测试并没有比这更多。小心使用。

【讨论】:

【参考方案2】:

注意这一行:

((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin =
            insets.getSystemWindowInsetTop();//what's the parent of "view"

按照getLayoutParams的说法,你应该知道“view”的父级是什么,例如,如果父级是FrameLayout,那么这样做:

((FrameLayout.LayoutParams) view.getLayoutParams()).topMargin =
                insets.getSystemWindowInsetTop();

如果父级是relativelayout或linearlayout,也像上面一样切换到确定类型。

已编辑:试试这个:

((WindowManager.LayoutParams) view.getLayoutParams()).topMargin =
                    insets.getSystemWindowInsetTop();

【讨论】:

我都试过了。投射到活动顶部控件 LinearLayout.MarginLayoutParams 仍然会引发错误。 WindowManager 没有属性 MarginLayoutParams。我可能会处理错误的观点。

以上是关于隐藏状态栏时如何强制windowSoftInputMode调整大小的主要内容,如果未能解决你的问题,请参考以下文章

iOS 7隐藏导航栏时如何更改状态栏的颜色?

在iOS 7中隐藏导航栏时,如何更改状态栏的颜色?

隐藏导航栏时的假状态栏颜色

隐藏导航栏时隐藏状态栏 - SWIFT iOS8

隐藏状态栏时 UIView 不会调整大小

隐藏状态栏时,iOS 11 搜索栏没有顶部填充