web-dev-qa-db-ja.com

CoordinatorLayoutコンテンツの子がBottomNavigationViewと重複しています

CoordinatorLayoutBottomNavigationViewAppBarLayout、および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>

問題は、CoordinatorLayoutViewPagerを配置して画面の下部まで拡張するため、次のようにBottomNavigationViewによって下部が隠されていることです。

bounds of ViewPager

これは、CoordinatorLayout自体がこれまで拡張されていなくても発生します。

bounds of CoordinatorLayout

BottomNavigationViewapp:layout_insetEdge="bottom"を追加し、ViewPagerapp:layout_dodgeInsetEdges="bottom"を追加しようとしましたが、これには別の問題があります:ViewPagerアップしますが、高さは同じであるため、トップが切り取られます。

shifted ViewPager bounds

他の2つの実験を試みました。まず、BottomNavigationViewからCoordinatorLayoutを削除し、垂直LinearLayoutの下に兄弟を作成してみました。次に、ViewPagerBottomNavigationViewLinearLayoutの下にまとめて、正しくレイアウトされることを期待しています。最初のケースでは、CoordinatorLayoutは依然として画面全体に対してViewPagerのサイズを変更し、その一部をBottomNavigationViewの後ろに隠すか、上部を切り落としました。 2番目の場合、ユーザーはBottomNavigationViewを表示するためにスクロールする必要があります。

レイアウトを正しくするにはどうすればよいですか?

追伸私が試したとき @ Anoop SSによって提案されたレイアウトCoordinatorLayoutの下の兄弟としてBottomNavigationViewRelativeLayoutを置く)、私は次のようになります(ViewPagerBottomNavigationViewの後ろまで伸びています):

result of Anoop's layout

以前と同様に、CoordinatorView自体はBottomNavigationViewの上部までしか拡張されていません。

13
Ted Hopp

私は別のアプローチを思いつきました(ただし、まだ戦闘テストされていません):

サブクラス化した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"
3
James

基本的には、親として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>
2
Anoop S S

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に事前に保存されています)を復元し、上部と下部のパディングを削除します。

私はこのソリューションをテストしましたが、警告なしで問題なく動作しました。

1
b0b

これは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がツールバーを表示/非表示にする方法です。

0
Vin Norman

まだ誰かがこの問題の解決策を探している場合:

問題の原因は、CoordinatorLayoutがapp:layout_scrollFlags="enterAlways|scroll"設定のツールバーを持っているため、AppBarLayoutのサイズを正しく計算していないことです。スクロールするとツールバーが非表示になり、ViewPagerにすべての使用可能なスペースが残ると考えられますが、実際には、ツールバーが表示され、ViewPagerがNavigationBarの後ろに移動します。

これを解決する最も簡単な方法は、Android:minHeight="?attr/actionBarSize"(または使用しているツールバーの高さ)をAppBarLayoutに追加することです。このようにして、CoordinatorLayoutは、ViewPagerのために残す必要があるスペースの量を適切に認識します。

0
MarkoR

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" />
0
Jimale Abdi

それでも誰かに問題がある場合:

上記のAnoop SSの答えで、RelativeLayoutLinearLayoutで置き換えてみてください。また、layout_height of CoordinatorLayout to 0dp and set layout_weightから1。

私はほとんど同じ問題を抱えていました... AdViewの代わりに静的BottomNavigationViewを下部に置きたかっただけです。 Anoop SSの提案を試してみると、最初はOPと同じ動作が得られました:ViewPagerAdViewの後ろに拡張されました。しかし、私は私が提案したことを行い、すべてがうまくいきました。

Androidのレイアウトの動作がおかしいか、ドキュメントが不足しているか、知識が不足していることが原因である可能性があります。しかし、レイアウトを作成することはほとんどの場合面倒です。

0