【问题标题】:ViewBinding - how to get binding for included layouts?ViewBinding - 如何获得包含布局的绑定?
【发布时间】:2019-11-06 12:23:38
【问题描述】:

在使用 ViewBinding 时,我遇到了一些没有记录的案例。

首先:如何获取包含的通用视图布局部分的绑定,主绑定只能看到主布局中的项目?

第二:如何获取包含的合并类型布局部分的绑定,再次主绑定只能看到主布局中的项目?

【问题讨论】:

  • 另一种简单的方法是使用数据绑定库。然后用 标记包装您的 XML 布局,这样如果您使用该库,则会自动生成将布局中的视图与您的数据对象绑定所需的类。老实说,我认为这是要走的路。按照指南here
  • 嗨,我写了一篇博文,完整地解释了视图绑定以及通过合并处理包含的标签和包含布局结帐????Androidbites|ViewBinding
  • 顺便说一句,如果有人想知道如何使用视图绑定来设置 appbar 徽标,只需将biding 对象用作:binding.toolbar。 setLogo(R.drawable.bar_logo);. 'binding' 和 'bar_logo' 根据您的需要进行更改。

标签: android android-viewbinding


【解决方案1】:

如果发生:

  1. 包含通用布局(不是合并节点),我们需要为包含的部分分配 ID,这样在绑定中我们将可以访问包含的子部分
<include
    android:id="@+id/your_id"
    layout="@layout/some_layout" />

在你的活动代码中这样写:

private lateinit var exampleBinding: ActivityExampleBinding  //activity_example.xml layout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    exampleBinding = ActivityExampleBinding.inflate(layoutInflater)
    setContentView(exampleBinding.root)
    //we will be able to access included layouts view like this
    val includedView: View = exampleBinding.yourId.idOfIncludedView
//[...]
}
  1. 在外部布局中包含合并块。我们无法为其添加 ID,因为合并块不是视图。 假设我们有这样的永恒合并布局(merge_layout.xm):
<?xml version="1.0" encoding="utf-8"?>
<merge 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"
    tools:showIn="@layout/activity_example">

    <TextView
        android:id="@+id/some_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World" />
</merge>

要正确绑定这样的合并布局,我们需要:

在您的活动代码中:

private lateinit var exampleBinding: ActivityExampleBinding  //activity_example.xml layout
private lateinit var mergeBinding: MergeLayoutBinding  //merge_layout.xml layout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    exampleBinding = ActivityExampleBinding.inflate(layoutInflater)
    //we need to bind the root layout with our binder for external layout
    mergeBinding = MergeLayoutBinding.bind(exampleBinding.root)
    setContentView(exampleBinding.root)
    //we will be able to access included in merge layout views like this
    val mergedView: View = mergeBinding.someView
//[...]
}

【讨论】:

  • 必须在包含合并视图的文件中添加layout 标签
  • 我正在尝试在片段而不是活动中执行此操作,但它不起作用。我已将 global_header 设置为我的包含项的 id,实际上 android studio 中的自动完成功能非常好,并且自动完成 viewBindings.globalHeader,因此它是为绑定生成的,但在运行时它会崩溃:“java.lang.NullPointerException: Missing required查看 ID:com.daon.ps.daonsonboard:id/global_header"
  • @FranMarzoa 你确定你在 Fragments onCreateView 中完成了所有需要的操作吗?喜欢:val binding = FrgamentSomethingSomething.inflate(layoutInflater) 和 return binding.root
  • @FranMarzoa 还请记住,binding.globalHeader 不会返回视图 - 它将是 GlobalHeaderBinding(或任何您调用的带有布局的文件),您将在其中找到所有包含的视图。
  • 它在扩展布局时崩溃了,我什至没有机会访问它。无论如何,我在这里找到了一个解决方案和一个很好的解释:stackoverflow.com/a/52343338/1160360
【解决方案2】:

您的第一个问题,即使用 ViewBinding 处理包含的布局可以很容易地解决。

这是一个示例 ma​​in_fragment.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view_main"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

</LinearLayout>

而MainFragment.java可以是这样的

public class MeaningFragment extends Fragment {

    private MainFragmentBinding binding;
    private ToolbarBinding toolbarBinding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

        binding = MainFragmentBinding.inflate(inflater, container, false);
        toolbarBinding = binding.toolbar;

        return binding.getRoot();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        toolbarBinding = null;
        binding = null;
    }
}

现在,您有两个绑定。其中一个是默认的,下一个来自包含的布局。

【讨论】:

  • 非常简单的答案并使用新的语法——所有这些都适用于我在onCreate() 中具有类似语法的非片段活动。谢谢。 (只是在使用DrawerLayout 时有点麻烦)
  • 我得到一个运行时 NPE,它说缺少 ID 为 blah 的必需视图。
  • @Asim 也许如果您将包含的布局从合并更改为某个视图组
  • 你救了我的命
【解决方案3】:

如果你想绑定包含的布局,那么,

对于活动

YourMainLayoutBinding mainLayoutBinding = MainLayoutBinding.inflate(getLayoutInflater);

View view = mainLayoutBinding.getRoot();

YourIncludedLayoutBinding includedLayoutBinding = YourIncludedLayoutBinding.bind(View);

片段

YourMainLayoutBinding mainLayoutBinding = MainLayoutBinding.inflate(inflater,container,false);

View view = mainLayoutBinding.getRoot();

YourIncludedLayoutBinding includedLayoutBinding = YourIncludedLayoutBinding.bind(View);

确定如果你的主布局绑定父根是 LinearLayout 那么, includeLayoutBinding 父布局也是线性布局

【讨论】:

  • 不需要显式绑定包含的布局,如果你为其指定一个id,它会自动完成:&lt;include android:id="@+id/myToolbar" layout="@layout/toolbar" /&gt;。之后,mainLayoutBinding.myToolbar 字段将包含一个嵌套绑定。
  • @DmitryK 实际上是需要的,否则 Android Studio 北极狐会报错Cannot access class 'x'. Check your module classpath for missing or conflicting dependencies
【解决方案4】:

假设我在activity_main.xml 文件中包含如下布局:

<include
    android:id="@+id/ll_layout1"
    layout="@layout/layout1"
    android:visibility="gone" />

假设我想改变它的可见性。我可以这样做:

activityMainBinding.llLayout1.root.visibility = View.VISIBLE

【讨论】:

  • root功能不可用,可以用rootView代替,我觉得一样
  • @bobbyI。它是 Kotlin,所以我们使用属性语法,因此,只是 root。在java中,你可以使用getRoot()来实现同样的效果。
【解决方案5】:

按照步骤:-

  1. private val binding : FragmentBinding viewBinding(FragmentBinding::bind)

  2. 确保在“onViewCreated(view: View, savedInstanceState: Bundle?)”中执行以下操作

     val binding2 = binding.root.include_layout_id
    

例如val binding2 = binding.root.tool_bar_layout

现在在此处访问您的包含布局和视图。例如

binding2.textView.text = "your text"

【讨论】:

    【解决方案6】:

    在包含布局中,您必须创建一个容器布局并将 id 放在这里。

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/example"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent">
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【讨论】:

      【解决方案7】:

      使用数据绑定库。然后用 &lt;layout&gt; 标签包装你的 XML 布局

      activity_main.xml

      <?xml version="1.0" encoding="utf-8"?>
      <layout>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
      
          ... 
      
          <include 
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />
          
          ...
      
      </LinearLayout>
      </layout>
      

      toolbar.xml

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
      
          <ImageView 
              android:id="@+id/ivImage"
              ... />
      
          <TextView 
              android:id="@+id/tvTitle"
              ... />
      
      
      </LinearLayout>
      

      MainActivity.kt

      private lateinit var binding: ActivityMainBinding  
      
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
      
          // Access include layout views
          binding.toolbar.rootView.ivImage.setImageResource(R.drawable.ic_back_arrow)
          binding.toolbar.rootView.tvTitle.text = getString(R.string.home)
         
          ...
      }
      

      【讨论】:

      • 问题是关于 ViewBinding 而不是 DataBinding
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-16
      • 2021-07-01
      • 2011-08-03
      • 1970-01-01
      • 2017-01-19
      相关资源
      最近更新 更多