日々是好日

プログラミングについてのあれこれ、ムダ知識など

HeaderView + DataBinding でハマった話

HeaderView に DataBinding でアニメーション実装しようとしたら意外とハマったのでメモ。

ハマりポイント

  • HeaderView は動的に生成しないとバインドされない
  • NavigationDrawer のapp:headerLayoutは使わない

正直これ↓見ていただければいいだけの話ではある( ˘ω˘)

stackoverflow.com

ハマった実装

xml で静的に HeaderView をセットしていました。

まずは HeaderView のレイアウト。

<layout xmlns:bind="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="viewmodel" type="MainViewModel"/>
    </data>

    <android.support.constraint.ConstraintLayout
            android:id="@+id/navigation_header_frame"
            bind:animate_background_color="@{viewmodel.headerColorTo}">

        <ImageView
                android:id="@+id/header_image"
        .../>

    </android.support.constraint.ConstraintLayout>
</layout>

次にMainActivity のレイアウト。

<layout xmlns:bind="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="viewmodel" type="MainViewModel"/>
    </data>

    <DrawerLayout ...>
        <ConstraintLayout ...>
        </ConstraintLayout>

        <!--Navigation Drawer-->
        <NavigationView
                android:id="@+id/nav_view"
                app:headerLayout="@layout/navigation_header"
        />

    </DrawerLayout>
</layout>

app:headerLayoutで HeaderView をセットしていましたが、これでは単に HeaderView が表示されるだけでデータバインドはされません。

一応 MainActivity#onCreateの実装。

class MainActivity : AppCompatActivity() {
    lateinit var binding: MainActBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        /* MainActivity の View を生成 */
        binding = 
            DataBindingUtil.setContentView<MainActBinding>(this, R.layout.main_act).also {
            it.viewmodel = obtainViewModel()
            it.setLifecycleOwner(this)
        }
    }
}

setContentViewで子のバインドも出来てると思い込んでしまった……。

解決した実装

app:headerLayout消した上で、MainActivity#onCreateに次のように実装します。

class MainActivity : AppCompatActivity() {
    lateinit var binding: MainActBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        /* MainActivity の View を生成 */
        binding = 
            DataBindingUtil.setContentView<MainActBinding>(this, R.layout.main_act).also {
            it.viewmodel = obtainViewModel()
            it.setLifecycleOwner(this)
        }

        /* HeaderView inflate */
        val _bind =
            NavigationHeaderBinding.inflate(layoutInflater, binding.navView, false).also {
                it.viewmodel = obtainViewModel()
                it.setLifecycleOwner(this)
            }

        /* HeaderView を NavigationDrawer にセット */
        binding.navView.addHeaderView(_bind.root)
    }
}

binding.navViewは MainActivity のレイアウトに置いてある NavigationDrawer です。念のため。

次は HeaderView にアニメーションを DataBinding 機構を介して実装した話書きます。