【问题标题】:Android Data Binding - how to use ViewStub with data bindingAndroid 数据绑定 - 如何将 ViewStub 与数据绑定一起使用
【发布时间】:2016-04-15 06:07:43
【问题描述】:

是否可以将 viewStubs 与 dataBinding 一起使用? ViewStubProxy 可以帮忙吗?

我的存根当前看起来像这样:

    <ViewStub
  android:id="@+id/stub_import"
  android:inflatedId="@+id/panel_import"

  android:layout="@layout/progress_overlay"

  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="@{myobject.bottom ? bottom:top}" />

但是当我对 viewStub 进行膨胀时,这个布局会被替换,那么 ViewStubs 如何与 android dataBinding 一起使用?

这是我从docs看到的:

视图存根

ViewStub 与普通 View 略有不同。他们开始 不可见,并且当它们变得可见或被明确告知时 膨胀,他们通过膨胀另一个来替换布局中的自己 布局。

因为 ViewStub 基本上从 View 层次结构中消失了, 绑定对象中的视图也必须消失以允许 收藏。因为视图是最终的,所以 ViewStubProxy 对象需要 ViewStub 的位置,使开发人员可以访问 ViewStub 当它存在并且还可以访问膨胀的视图层次结构时 ViewStub 已膨胀。

当膨胀另一个布局时,必须为 新版面。因此,ViewStubProxy 必须监听 ViewStub 的 ViewStub.OnInflateListener 并建立当时的绑定。 由于只能存在一个,ViewStubProxy 允许开发人员 在其上设置一个 OnInflateListener ,它将在建立后调用 绑定。

【问题讨论】:

    标签: android data-binding viewstub


    【解决方案1】:

    只需按照文档中的说明设置监听器即可:

    mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
        @Override
        public void onInflate(ViewStub stub, View inflated) {
            ViewStubBinding binding = DataBindingUtil.bind(inflated);
            binding.setModel(model);
        }
    });
    
    
    
    public void inflateViewStub(View view) {
        if (!mBinding.viewStub.isInflated()) {
            mBinding.viewStub.getViewStub().inflate();
        }
    }
    

    【讨论】:

    • 请注意,ViewStubBinding 不是一个类,它是视图存根的绑定类。我花了一段时间才弄明白。希望此评论对其他人有所帮助。
    • 无法解析符号“ViewStubBinding”。有什么解决办法吗?
    • @Jatin ViewStubBinding 是一个生成的类。如果您的 xml 名称是 jatin_activity,它将是 JatingActivityBinding
    【解决方案2】:

    声明你的 xml 命名空间,并通过它传递变量。这也适用于&lt;include&gt;,顺便说一句。这是一个例子:

    main_layout.xml:

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:my-namespace="http://schemas.android.com/apk/res-auto">
        <data>
            <variable name="myData" type="com.example.SomeModel" />
        </data>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
            <ViewStub
                android:id="@+id/view_stub"
                android:inflatedId="@+id/view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout="@layout/another_layout"
                my-namespace:data="@{myData}"
                />
    
        </RelativeLayout>
    </layout>
    

    another_layout.xml:

    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- No need to declare my-namespace here -->
        <data>
            <variable name="data" type="com.example.SomeModel" />
        </data>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{data.someValue}" />
    
        </RelativeLayout>
    </layout>
    

    所以现在您只需调用inflate(),布局就会包含数据。 您可以检查生成的绑定类来验证这一点。它甚至具有类型安全性,因此您不能将任何其他类型传递给 data

    【讨论】:

    • 当我使用my-namespace:data 时出现错误,因为绑定编译器找不到data,但如果我将其更改为my-namespace:viewModel,它就可以工作。
    • 很好的答案!不知道你能做到。是的,您需要使用目标 xml 文件中的变量名称。 “viewModel”、“item”、“data”无论您要设置什么
    • 无需访问视图直接调用inflate()。只需绑定ViewStub 的可见性:当它转到VISIBLE 时,它会膨胀。
    • 双向数据绑定怎么样。它是如何工作的?
    【解决方案3】:

    仅详细说明@andrew-classen's accepted answer above,并包括@user9113597's answer

    在包含存根的布局中(例如 my_fragment.xml)

        <data class="MyDataBinding">
            ...
        </data>
    
        ...
        <ViewStub 
            android:id="@+id/stub_import"
            ... />
    

    在您的活动或片段中(下面的示例使用片段):

    MyDataBinding mBinding;
    MyViewModel mViewModel;
    
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
        @Nullable Bundle savedInstanceState)
    {
        mBinding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false); 
        mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() 
        {
            @Override
            public void onInflate(ViewStub stub, View inflated)
            {
                ViewDataBinding dataBinding = DataBindingUtil.bind(inflated);
                binding.setVariable(BR.mViewModel, mViewModel));
            }
        });
    }
    
    public void inflateViewStub(View view) {
    if (!mBinding.viewStub.isInflated()) {
        mBinding.viewStub.getViewStub().inflate();
    }
    

    }

    在您的存根布局中:

    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
    
            <variable
                name="mViewModel"
                type="com.example.myapp.MyViewModel" />
        </data>
        ...
    

    【讨论】:

      【解决方案4】:

      我这样做的另一种方法是使用 ViewStubProxy。 ViewStubProxy 的文档/源代码很好。

      当您创建新的 ViewStubProxy 时,请在构造函数中传入您的 ViewStub。然后ViewStubProxy.setContainingBinding(&lt;pass in your root layout binding&gt;)。如果你不这样做,你会得到空值。

      然后,不要设置 ViewStub.setOnInflateListener(ViewStubProxy 会在内部为您设置一个),而是设置 ViewStubProxy.setOnInflateListener 来设置您的绑定变量和 LifecycleOwner。

      示例代码:

         private void setBindings(){
            //usual outside layout binding steps
            binding = (MeasurementsLayoutBinding) getBinding();
            binding.setViewModel(viewModel());
            binding.setLifecycleOwner(this);
      
            //cartSideStubView is the root layout stubview
            cartViewStubProxy = new ViewStubProxy(cartSideStubView);
            cartViewStubProxy.setContainingBinding(binding);
      
            cartViewStubProxy.setOnInflateListener(((viewStub, view) -> {
      
               cartViewStubProxy.getBinding().setVariable(BR.viewModel, viewModel());
               cartViewStubProxy.getBinding().setLifecycleOwner(this);
      
              //after inflation you can find your viewstub views
      
               cartHitchToFixedAxleInputField = view.findViewById(R.id.cart_hitch_to_fixed_axle_input_field);       
      
      
            }));
      
         }
      

      【讨论】:

        【解决方案5】:

        设置监听器以在viewStub成功膨胀后访问膨胀布局

        mBinding.viewStub.setOnInflateListener(new OnInflateListener() {
          @Override
          public void onInflate(ViewStub stub, View inflated) {
            ViewStubBinding binding = DataBindingUtil.bind(inflated); //call after succesful inflating of viewStub
          // set data here 
          }
        });
        

        然后膨胀你的viewStub

        mBinding.viewStub.getViewStub().inflate();
        

        【讨论】:

          【解决方案6】:

          我也遇到过这类问题, 终于我找到了一个解决方案,而且效果很好。

          ViewStub 持有布局,,,

          <?xml version="1.0" encoding="utf-8"?>
          <layout xmlns:android="http://schemas.android.com/apk/res/android">
          
              <data class="MBinding">
          
                  <variable
                      name="mmmmm"
                      type="com.vvv.bbb.fragments.MFragment" />
          
              </data> 
            --------------------
            --------------------
             <ViewStub
               android:id="@+id/stub_import"
               -------------------
               -------------------
                  <ViewStub/>
            --------------------
            --------------------
          <layout/>
          

          ViewStub 里面的布局是,,,

          <?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">
          
              <data class="MViewStubLayoutBinding">
          
                  <variable
                      name="mmmmm"
                      type="com.vvv.bbb.fragments.MFragment" />
          
              </data>
            ----------------
            ----------------
            ----------------
          

          类里面的代码是,,,

          public Class KKKKKK() {
           -----------------
          MBinding mBinding;
          MViewStubLayoutBinding mviewStubLayoutBinding;
          
           -----------------------------  
           -----------------------------
          
          mBinding.stubImport.getViewStub().setLayoutResource(R.layout.progress_overlay);
          
             mBinding.stubImport.setOnInflateListener(new ViewStub.OnInflateListener() {
                      @Override
                      public void onInflate(ViewStub viewStub, View view) {
                          mviewStubLayoutBinding=DataBindingUtil.bind(view);
                      }
                  });
          
                  autoCheckBinding.vsAutoDetailsOne.getViewStub().inflate();
          

          【讨论】:

            【解决方案7】:

            如果您正在使用 ViewModels,那么您还需要为膨胀视图设置 生命周期所有者,请记住在片段/活动视图期间设置您为 mBinding 变量设置的相同所有者。

            mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
                @Override
                public void onInflate(ViewStub stub, View inflated) {
                    ViewStubBinding binding = DataBindingUtil.bind(inflated);
                    binding.setModel(model);
                    binding.setLifeCycleOwner(this) // setLifeCycleOwner
                }
            });
            
            
            
            public void inflateViewStub(View view) {
                if (!mBinding.viewStub.isInflated()) {
                    mBinding.viewStub.getViewStub().inflate();
                }
            }
            

            希望这对某人有所帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-05-10
              • 2019-08-22
              • 2020-01-11
              • 1970-01-01
              • 2018-05-23
              • 2021-05-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多