私のアプリには、セクションごとに異なるフラグメントをホストする1つのアクティビティがあります。私は最近、fitSystemWindows
をtrue
に設定してステータスバーを半透明にしました。これにより、アプリの背景色に設定されます。これは、次のように、色が一致するツールバーがあるフラグメントの場合は問題ありません。
ただし、フラグメントの1つに写真と半透明のツールバーがあるため、背景色ではなく、写真がステータスバーのスペースも占めるようにしたいと思います。
その解決策は、そのフラグメントに対してのみfitSystemWindows
をfalse
に設定し、手動で半透明ツールバーにパディングを追加することだと思います。これをプログラムで実行しても効果がないようですが、何が問題でしょうか?
これが私の主な活動レイアウトです:
<RelativeLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/main_parent_view"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical"
Android:fitsSystemWindows="true">
<!-- Container for various fragment layouts, including nav drawer and tool bar -->
</RelativeLayout>
そして、私のフラグメントのonCreateView()内から:
RelativeLayout daddyLayout = (RelativeLayout)getActivity().findViewById(R.id.main_parent_view);
daddyLayout.setFitsSystemWindows(false);
daddyLayout.invalidate();
これは次のように効果がないようです:
main_parent_view
でfitSystemWindows
をfalseに設定すると、ステータスバーのパディングがなくなり、機能しますが、明らかにすべてのフラグメントに影響しますです。
同じ問題を見た。アプリで、アクティビティ宣言からfitSystemWindowsを削除し、フラグメントにpaddingTopを追加することで解決しました。明らかに理想的なソリューションではありませんが、機能しているようです。
さて、あなたはそこでジレンマの状況にあります。なぜなら、一方ではインセットを適用する必要があるため(Toolbar
は正しく埋め込まれる必要があるため)、他方ではしない必要があるためですインセットを適用します(ステータスバーの下にImageView
を描画するため)。
その場合のためにフレームワークによって提供される素晴らしいAPIがあることがわかります:
ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> {
((ViewGroup.MarginLayoutParams) v.getLayoutParams()).topMargin =
insets.getSystemWindowInsetTop();
return insets.consumeSystemWindowInsets();
});
ルートレイアウトにAndroid:fitsSystemWindows="true"
、適切なインセットがToolbar
ではなくImageView
onlyに適用されるようになりました。
しかし、問題があります。
問題は、ルートレイアウトがRelativeLayout
であり、インセットに関する情報を子にディスパッチしないことです。また、兄弟レイアウト(LinearLayout
、FrameLayout
)も行いません。
ルートレイアウトとして「マテリアリッシュ」レイアウト(CoordinatorLayout
、DrawerLayout
)のいずれかがあった場合、子はそれらのウィンドウインセットにディスパッチされます。
もう1つのオプションは、RelativeLayout
をサブクラス化し、WindowInsets
を手動で子にディスパッチすることです。
@TargetApi(Build.VERSION_CODES.KitKat_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++)
getChildAt(index).dispatchApplyWindowInsets(insets); // let children know about WindowInsets
return insets;
}
あなたは この答え を見て、あなたが持っているのとまったく同じ要件の詳細な説明を見ることができます。
この質問は4.4で解決しました
if(test){
Log.d(TAG, "fit true ");
relativeLayout.setFitsSystemWindows(true);
relativeLayout.requestFitSystemWindows();
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}else {
Log.d(TAG, "fit false");
relativeLayout.setFitsSystemWindows(false);
relativeLayout.requestFitSystemWindows();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
CoordinatorLayout
をアクティビティルートビューとして使用すると、setFitsSystemWindows(boolean)
が機能します。
これは、この ブログ投稿 で説明されているように、DrawerLayout
とCoordinatorLayout
の両方にfitsSystemWindows
がどのように適用されるかについて異なるルールがあるためです-どちらも使用します子ビューを挿入するだけでなく、各子でdispatchApplyWindowInsets()
を呼び出し、fitsSystemWindows="true"
プロパティへのアクセスを許可します。
これは、FrameLayout
などのレイアウトのデフォルトの動作との違いです。fitsSystemWindows="true"
を使用すると、すべてのインセットが消費され、子ビューに通知せずに盲目的にパディングが適用されます(これは、ブログ投稿)。