如何将数据绑定到标题?

33

我有一个主活动,并在操作栏中指定了侧边导航抽屉,如下所示(请注意,为了简洁起见,省略了大量代码)在default_screen.xml中:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="190dp"
    android:background="@drawable/honeycomb"
    android:orientation="vertical"
    >
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        app:headerLayout="@layout/header"
        app:menu="@menu/drawer"
        />

布局/头部如下所示(出于简洁起见,省略了很多行):

<data>
    <variable name="user" type="oose2017.place2b.ClientUser"/>
</data>
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{user.displayName}"
        android:textSize="14sp"
        android:textColor="#FFF"
        android:textStyle="bold"
        android:gravity="left"
        android:paddingBottom="4dp"
        android:id="@+id/username"
        android:layout_above="@+id/email"
        android:layout_alignLeft="@+id/profile_image"
        android:layout_alignStart="@+id/profile_image" />
</RelativeLayout>

我在主活动中实例化我的默认屏幕,如下所示:

  setContentView(R.layout.default_screen);

如何将数据绑定到标题?我尝试了几个不成功的方法,主要包括:

DefaultScreenBinding binding = DataBindingUtil.setContentView(R.layout.default_screen);

哪种方法不起作用。我该怎么做?

7个回答

52

有效的解决方案如下,在MainActivity的OnCreate方法中添加标题视图:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        NavHeaderMainBinding _bind = DataBindingUtil.inflate(getLayoutInflater(), R.layout.nav_header_main, binding
                .navView, false);
        binding.navView.addHeaderView(_bind.getRoot());
        _bind.setUser(Session.getUserProfile());
}

注意: 重要的一行是binding.navView.addHeaderView(_bind.getRoot()); 从xml中删除app:headerLayout="@layout/nav_header_main"并进行编程添加。

12
重要的一行是 binding.navView.addHeaderView(_bind.getRoot());从xml中删除 app:headerLayout="@layout/nav_header_main" 并像上面那样以编程方式添加。 - Pushan

42

如果一个视图是父级绑定的子级,那么您可以将任何视图与其父级绑定。就像这里一样:导航视图头是导航视图的子级,因此要绑定导航视图头与导航视图需要这样做。

Main screen 的 default_screen 绑定:

DefaultScreenBinding binding = DataBindingUtil.setContentView(R.layout.default_screen);

用于头部布局包括绑定的内容如下:

HeaderBinding headerBinding = HeaderBinding.bind(binding.navigationView.getHeaderView(0));

binding.navigationView.getHeaderView(0)将会给出您想要绑定的导航视图的标题视图。

现在,您可以使用headerBinding引用标题布局。希望这样更容易理解且有所帮助。


11

使用ViewBinding

// navView is NavigationView
val viewHeader = binding.navView.getHeaderView(0) 

// nav_header.xml is headerLayout
val navViewHeaderBinding : NavHeaderBinding = NavHeaderBinding.bind(viewHeader)

// title is Children of nav_header
navViewHeaderBinding.title.text = "Your Text" 

3
谢谢,它有效了。 - Deepak

4
我的解决方案如下:
    <android.support.design.widget.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/navigation"
        app:menu="@menu/activity_drawer_drawer">


        <include
            layout="@layout/nav_header_drawer"
            bind:thisDevice="@{thisDevice}" />

为了使用数据绑定,我们不能使用原始的headLayout,所以我们使用一个“包含的布局”。这样,我们的标题可以通过数据绑定正常显示。但是,没有标题布局的菜单将重叠。因此,我们添加一个空的headLayout,其与我们真实布局具有相同的大小,以使菜单正常显示。
详细说明可以在我的博客文章中找到。
工作示例可以在这里找到。
如果我没有表达清楚,请告诉我。

3

我不确定这是否是最佳方法,但这是适用于我的情况的方法。

我为 NavigationView 创建了一个自定义视图(扩展了该类),然后在自定义视图构造函数中使用 DataBindingUtil.inflate 设置我的数据绑定变量,并将该视图作为标题添加到 NavigationView.addHeaderView 中。当然,这意味着在xml中,我必须将 NavigationView 替换为我的自定义视图,并且不在自定义视图中指定 app:headerLayout 属性。请参见下面的自定义视图示例(请注意,我使用Dagger2来注入我的数据绑定变量)。

public class MyNavigationView extends NavigationView {
    @Inject
    MyViewModel myViewModel;

    public MyNavigationView(Context context) {
        super(context);
        initialize();
    }

    public MyNavigationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public MyNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    private void initialize() {
        // NOTE: A private method that "injects" your view model dependency (ex: Using Dagger2)
        inject();

        NavHeaderHomeBinding binding = DataBindingUtil.inflate(LayoutInflater.from(getContext()),
                R.layout.nav_header_home,
                null,
                false);
        binding.setHomeNavDrawerViewModel(myViewModel);
        addHeaderView(binding.getRoot());
    }
}

3

似乎没有直接的方法来为NavigationView进行数据绑定,因此我不得不以某种黑客方式来实现它:

首先,为了使用bind,我们不能直接使用headerLayout,而是要用一个包含布局来替换它。

<android.support.design.widget.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_drawer"  
    app:menu="@menu/drawer">

<android.support.design.widget.NavigationView
    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/drawer">

    <include layout="@layout/nav_header_drawer"
    bind:thisDevice="@{thisDevice}" />
</android.support.design.widget.NavigationView>

新加入的视图位于菜单顶部,因此它将正常显示。但是由于其上方没有标题,部分菜单项将向上移动并被新添加的视图覆盖(尽管这些项目仍然可以接收触摸事件),所以我们可以添加一个标题。
<android.support.design.widget.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/navigation"
    app:menu="@menu/activity_drawer_drawer">


    <include
    layout="@layout/nav_header_drawer"
    bind:thisDevice="@{thisDevice}" />
</android.support.design.widget.NavigationView>

导航布局是一个空布局,具有与实际导航头抽屉相同的高度和宽度。因此,菜单和实际布局都可以正常显示。当然,使用数据绑定需要Java代码:

ActivityDrawerBinding binding = DataBindingUtil.setContentView(this,  R.layout.activity_drawer);
binding.setThisDevice(Device.now);

布局文件在这里。 可在此处找到工作示例。

参考:http://tonyz93.blogspot.com.br/2016/08/learn-data-binding-of-android.html#navigationview-data-binding


1
这是最好的方法,我已经实现了这种方式,而且它运行得非常完美。 - Thalis Vilela

2
在Kotlin中
<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" />

布局/头部在哪里

<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/nav_user_image"
android:layout_width="@dimen/nav_image_size"
android:layout_height="@dimen/nav_image_size"
android:layout_marginStart="@dimen/nav_content_margin_StartEnd"
android:layout_marginEnd="@dimen/nav_content_margin_StartEnd"
app:civ_border_color="@android:color/white"
app:civ_border_width="@dimen/nav_image_circular_border_width"
android:contentDescription="@string/image_contentDescription"
android:src="@drawable/ic_user_place_holder" />

使用viewBinding

val viewHeader = binding?.navView?.getHeaderView(0)
val headerBinding = viewHeader?.let { NavHeaderMainBinding.bind(it) }

headerBinding?.tvUsername?.text = user.name

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接