当用户登录我的应用并在MainActivity
收到他们的个人资料信息(姓名,头像等)时,我想通过用户参数填充导航视图标题中的某些字段数据绑定。我已尝试过the docs中提出的方法,但可能仅限于<include />
?
activity_main.xml中
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.example.app.models.User" />
</data>
<android.support.v4.widget.DrawerLayout
// layout params... >
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView xmlns:bind="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"
bind:user="@{user}" />
</android.support.v4.widget.DrawerLayout>
</layout>
nav_header_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.example.app.models.User" />
</data>
<LinearLayout
// layout params... >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@{user.name}"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</LinearLayout>
</layout>
MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(User.getInstance());
// other stuff...
}
我收到2个错误:
如果我删除它构建的bind:user
行,但它当然不起作用。有什么方法可以让这种事情发挥作用吗?
答案 0 :(得分:0)
您需要以编程方式添加导航视图以启用绑定。
NavHeaderHomeBinding _bind = DataBindingUtil.inflate(getLayoutInflater(), R.layout.nav_header_main, binding
.navView, false);
binding.navView.addHeaderView(_bind);
您的xml:删除headerLayout
<android.support.design.widget.NavigationView xmlns:bind="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/activity_main_drawer"
bind:user="@{user}" />
这应该有用。
答案 1 :(得分:0)
这对我有用:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
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">
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"/>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
nav_header_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout_nav_view_header">
<data>
<variable
name="user"
type="com.myapp.model.UserSettings"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round"
android:contentDescription="@string/nav_header_desc"
android:id="@+id/imageView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@{user.name}"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle"
android:id="@+id/textView"/>
</LinearLayout>
</layout>
然后在活动的onCreate中:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewHeader = nav_view.getHeaderView(0)
val navViewHeaderBinding : NavHeaderMainBinding = NavHeaderMainBinding.bind(viewHeader)
navViewHeaderBinding.user = UserSettings(null, null, "John Doe", "Android Developer", null)
}
答案 2 :(得分:0)
ksinghit的答案对我不起作用。由于某种原因,当我尝试通过XML绑定用户变量时,Gradle无法构建。
但是根据他的回答,我能够删除id_transaction !== null ? id_transaction : ' - '
info_data !== null ? info_data.value1 : ' - '
bio_data.digital[0] !== undefined ? bio_data.digital[0].name] : '-'
行并以编程方式设置变量:
bind:user
使用Kotlin对其他任何人进行观察:添加Header View时,您必须传递视图根目录,而不传递NavHeaderHomeBinding本身:
_bind.user = user
答案 3 :(得分:0)
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/activity_navigation_drawer"
android:theme="@style/NavigationDrawerStyle">
<include layout="@layout/nav_header_navigation"
app:user= "@{user}"/>
</com.google.android.material.navigation.NavigationView>
答案 4 :(得分:0)
@AndroidDev 的答案基本上对我有用,对我来说似乎是最干净的。 但我尝试将 viewModel 设置为数据绑定变量并在导航头视图中访问其 LiveData 实例和方法:
nav_header_main.xml:
<layout 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">
<data>
<variable
name="viewModel"
type="com.example.MainActivityViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="176dp"
android:background="?attr/colorPrimary">
<Button
android:id="@+id/login_logout_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.handleLoginLogoutButton()}"
android:text='@{viewModel.user == null ? "Login" : "Logoff"}'
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textAppearance="@style/textstyle_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text='Abmelden' />
<TextView
android:id="@+id/account_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@{viewModel.user.email}"
android:textAppearance="@style/textstyle_body1"
android:textColor="@color/white"
android:visibility="@{viewModel.userCredentialsVisibility}"
app:layout_constraintBottom_toTopOf="@+id/login_logout_button"
app:layout_constraintStart_toStartOf="parent"
tools:text="kuku@gmail.com"
tools:visibility="visible" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
这起初不起作用,因为 viewModel-LiveData-changes 没有传播到生成的 NavHeaderMainBinding 实例。
我很头疼,我确实在我的 ViewModel 中实现了 Observable 接口,如官方数据绑定文档中所述:https://developer.android.com/topic/libraries/data-binding/architecture#observable-viewmodel
但这并没有解决这个特定问题。 然后我想起了 databinding-docs 提到在生成的 Binding-class 上设置 LifeCycleOwner。我为 NavHeaderMainBinding 做了这个,现在它正在工作:
MainActivity.kt:
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// ...
// this has to be in onPostCreate to avoid a IllegalStateException
// while using FragmentContainerView as NavHost in MainActivity (activity_main.xml)
navController = findNavController(R.id.nav_host_fragment)
val navigationView = findViewById<NavigationView>(R.id.nav_view)
navigationView.setupWithNavController(navController)
// we have to bind the viewModel manually to the header-view
// since NavigationView does not support databinding by itself
val headerView = navigationView.getHeaderView(0)
val headerViewBinding = NavHeaderMainBinding.bind(headerView)
headerViewBinding.viewModel = mainActivityViewModel
// this new line is important to get notifications about livedata-changes!!!
headerViewBinding.lifecycleOwner = this
// ...
}
现在完美运行!