CoordinatorLayout
をBottomNavigationView
、AppBarLayout
、およびViewPager
とともに使用しようとしています。これが私のレイアウトです:
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:context=".MainActivity">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<Android.support.design.widget.BottomNavigationView
Android:id="@+id/navigation"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_gravity="bottom"
Android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="@menu/navigation"/>
</Android.support.design.widget.CoordinatorLayout>
問題は、CoordinatorLayout
がViewPager
を配置して画面の下部まで拡張するため、次のようにBottomNavigationView
によって下部が隠されていることです。
これは、CoordinatorLayout
自体がこれまで拡張されていなくても発生します。
BottomNavigationView
にapp:layout_insetEdge="bottom"
を追加し、ViewPager
にapp:layout_dodgeInsetEdges="bottom"
を追加しようとしましたが、これには別の問題があります:ViewPager
アップしますが、高さは同じであるため、トップが切り取られます。
他の2つの実験を試みました。まず、BottomNavigationView
からCoordinatorLayout
を削除し、垂直LinearLayout
の下に兄弟を作成してみました。次に、ViewPager
とBottomNavigationView
をLinearLayout
の下にまとめて、正しくレイアウトされることを期待しています。最初のケースでは、CoordinatorLayout
は依然として画面全体に対してViewPager
のサイズを変更し、その一部をBottomNavigationView
の後ろに隠すか、上部を切り落としました。 2番目の場合、ユーザーはBottomNavigationView
を表示するためにスクロールする必要があります。
レイアウトを正しくするにはどうすればよいですか?
追伸私が試したとき @ Anoop SSによって提案されたレイアウト (CoordinatorLayout
の下の兄弟としてBottomNavigationView
とRelativeLayout
を置く)、私は次のようになります(ViewPager
はBottomNavigationView
の後ろまで伸びています):
以前と同様に、CoordinatorView
自体はBottomNavigationView
の上部までしか拡張されていません。
私は別のアプローチを思いつきました(ただし、まだ戦闘テストされていません):
サブクラス化したAppBarLayout.ScrollingViewBehavior
は、BottomNavigationView
(存在する場合)の高さに基づいてコンテンツビューの下マージンを調整します。このようにして、何らかの理由でBottomNavigationView
の高さが変わった場合、(うまくいけば)将来の証拠になるはずです。
サブクラス(Kotlin):
class ScrollingViewWithBottomNavigationBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
// We add a bottom margin to avoid the bottom navigation bar
private var bottomMargin = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
return super.layoutDependsOn(parent, child, dependency) || dependency is BottomNavigationView
}
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
val result = super.onDependentViewChanged(parent, child, dependency)
if(dependency is BottomNavigationView && dependency.height != bottomMargin) {
bottomMargin = dependency.height
val layout = child.layoutParams as CoordinatorLayout.LayoutParams
layout.bottomMargin = bottomMargin
child.requestLayout()
return true
} else {
return result
}
}
}
次に、レイアウトXMLに次のように入力します。
app:layout_behavior=".ScrollingViewWithBottomNavigationBehavior"
の代わりに
app:layout_behavior="@string/appbar_scrolling_view_behavior"
基本的には、親としてRelativelayoutを作成し、BottomNavigationViewとCoordinatorLayoutを子として配置する必要があります。次に、BottomNavigationViewを下部に配置し、その上にCoordinatorLayoutを設定します。以下のコードをお試しください。私がそれ自体をここに書いたので、属性エラーが少ないかもしれません。とめちゃくちゃインデントをごめんなさい。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">
<Android.support.design.widget.CoordinatorLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_above="@+id/navigation"
>
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</Android.support.design.widget.CoordinatorLayout>
<Android.support.design.widget.BottomNavigationView
Android:id="@+id/navigation"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
Android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="@menu/navigation"/>
</RelativeLayout>
OPに非常に近いレイアウトと3ページのViewPagerで同様の問題がありましたが、appbar_scrolling_view_behaviorの影響を受けるのは2ページと3ページのみです。
行き止まりの可能な解決策(layout_dodgeInsetEdges、ウィンドウインセット、ViewPagerのページ測定サイズの変更を試みる、Android:clipChildren、fitSystemWindowsなど)を何時間も苦労して探した後、ついに以下に詳述する簡単な解決策を見つけました。
Vin Normanが説明したように、ViewPagerがBottomNavigationにオーバーラップするのは、ViewPagerに設定されたappbar_scrolling_view_behaviorが原因です。 AppBarLayoutは、全画面をappbar_scrolling_view_behaviorを持つ兄弟にします。それがどのように機能するかです。
特定のViewPagerページでのみこの動作が必要な場合は、ViewPagerのOnPageChangeListenerに適用して動作を動的に変更し、必要なパディングを追加/削除するよりも簡単な修正があります。
public class MyOnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
@Override
public void onPageSelected(int position) {
...
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) _viewPager.getLayoutParams();
if(position == 0) {
params.setBehavior(null);
params.setMargins(params.leftMargin, _appBarLayoutViewPagerMarginTopPx,
params.rightMargin, _appBarLayoutViewPagerMarginBottomPx);
} else {
params.setBehavior(_appBarLayoutViewPagerBehavior);
params.setMargins(params.leftMargin, 0, params.rightMargin, 0);
}
_viewPager.requestLayout();
}
}
位置0のページ(ViewPagerをToolbarの真下、BottomNavigationViewの上に拡張したいページ)の場合、動作を削除し、上部と下部のパディングをそれぞれ追加します。 R.attr.actionbarSizeのピクセル単位とNavigationBottomViewの高さ。通常は両方とも56dpです)
Appbar_scrolling_view_behaviorを必要とする他のすべてのページでは、関連するスクロール動作(_appBarLayoutViewPagerBehaviorに事前に保存されています)を復元し、上部と下部のパディングを削除します。
私はこのソリューションをテストしましたが、警告なしで問題なく動作しました。
これはapp:layout_behavior="@string/appbar_scrolling_view_behavior"
をViewPagerに追加します。この行を削除すると、CoordinatorLayoutコンテナーに適合していることがわかります(残念ながら、これは現在、ツールバーの下にあります)。
CoordinatorLayoutを単なるFrameLayoutとして扱うのに役立ち、いくつかの追加のトリックがありました。上記のapp:layout_behavior属性は、ツールバーがスクロールして見えるようにするために必要です...実際には、レイアウトは、折りたたみツールバー(あなたの場合、ViewPager)にリンクされたビューを正確にツールバーの高さが境界よりも大きい。上にスクロールすると、ビューが境界内の一番下に表示され、ツールバーが境界を超えて上に押し上げられます。下にスクロール、またはその逆。
さて、BottomNavigationViewに!私がしたように、BottomNavigationViewをずっと表示したい場合は、Anoopが言ったように、それをCoordinatorLayoutの外に移動します。 CoordinatorLayoutは、調整が必要なものだけに使用し、それ以外はすべて外で使用します。私はたまたま私の親ビューにConstraintLayoutを使用しました(RelativeLayoutまたはあなたのために機能するものなら何でも使用できます)。 ConstraintLayoutでは、次のようになります。
<Android.support.constraint.ConstraintLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true">
<Android.support.design.widget.CoordinatorLayout
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".MainActivity">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</Android.support.design.widget.CoordinatorLayout>
<Android.support.design.widget.BottomNavigationView
Android:id="@+id/navigation"
Android:layout_width="0dp"
Android:layout_height="wrap_content"
Android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/navigation" />
</Android.support.constraint.ConstraintLayout>
Android Studioのデザインビューでは、ViewPagerがコンテナーよりも大きく表示されます(おそらく下部ナビゲーションの背後にあるように見えます)が表示されます)。 ViewPagerのコンテンツの下部に表示されます(つまり、下部ナビゲーションの背後には表示されません)。デザインビューのこの癖は、前述のように、CoordinatorLayoutがツールバーを表示/非表示にする方法です。
まだ誰かがこの問題の解決策を探している場合:
問題の原因は、CoordinatorLayoutがapp:layout_scrollFlags="enterAlways|scroll"
設定のツールバーを持っているため、AppBarLayoutのサイズを正しく計算していないことです。スクロールするとツールバーが非表示になり、ViewPagerにすべての使用可能なスペースが残ると考えられますが、実際には、ツールバーが表示され、ViewPagerがNavigationBarの後ろに移動します。
これを解決する最も簡単な方法は、Android:minHeight="?attr/actionBarSize"
(または使用しているツールバーの高さ)をAppBarLayoutに追加することです。このようにして、CoordinatorLayoutは、ViewPagerのために残す必要があるスペースの量を適切に認識します。
Androidxを使用している場合は、これを試してください
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:context=".MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
Android:layout_above="@+id/bottomNavView">
<com.google.Android.material.appbar.AppBarLayout
Android:id="@+id/appBarLayout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.Android.material.appbar.AppBarLayout>
<FrameLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<fragment
Android:id="@+id/nav_Host_fragment"
Android:name="androidx.navigation.fragment.NavHostFragment"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.Android.material.bottomnavigation.BottomNavigationView
Android:id="@+id/bottomNavView"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
Android:background="?android:attr/windowBackground"
app:menu="@menu/bottom_nav" />
それでも誰かに問題がある場合:
上記のAnoop SSの答えで、RelativeLayout
をLinearLayout
で置き換えてみてください。また、layout_height
of CoordinatorLayout
to 0dp and set layout_weight
から1。
私はほとんど同じ問題を抱えていました... AdView
の代わりに静的BottomNavigationView
を下部に置きたかっただけです。 Anoop SSの提案を試してみると、最初はOPと同じ動作が得られました:ViewPager
がAdView
の後ろに拡張されました。しかし、私は私が提案したことを行い、すべてがうまくいきました。
Androidのレイアウトの動作がおかしいか、ドキュメントが不足しているか、知識が不足していることが原因である可能性があります。しかし、レイアウトを作成することはほとんどの場合面倒です。