RecyclerView.ViewHolders中的Android DataBinding具有不同的布局

时间:2016-07-02 15:32:36

标签: android android-viewholder android-databinding

我试图在新项目中使用机器人数据绑定功能,到目前为止对此非常满意。

但现在我在recyclerviews视图中遇到了一个问题。

我的视图使用不同的布局(基于创建时的视图类型)

public MediaViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
     switch(viewType){
          case HEADER: 
             int layout = R.layout.item_media_header;
             break;
          case DEFAULT: 
             int layout = R.layout.item_media_default;
             break;
          case SMALL: 
             int layout = R.layout.item_media_small;
             break;
     }
     View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
     return new MediaViewHolder(v);
}

所以这3个布局中的所有布局都有相同的视图,只是以不同的方式排列。因此,模型与视图的绑定是相同的。

无论如何,基于android创建的那些布局

  • ItemMediaHeaderBinding
  • ItemMediaDefaultBinding
  • ItemMediaSmallBinding

这很糟糕,因为它会强制我创建3个不同的ViewHolder类,或通过检查使用哪个布局来实例化正确的绑定类。

这种情况有最好的做法吗?是否有可能只为这三个绑定类创建一个超类,例如" ItemMediaBinding"。

提前致谢。

3 个答案:

答案 0 :(得分:3)

所以,我最终做的是创建BaseViewHolder.class,创建扩展此ViewHolder的其他BaseViewHolder类,以便我的RecyclerView.Adapter看起来仍然干净,因为我最终得到的结果是ViewHolder

public class BaseVH extends RecyclerView.ViewHolder {
    private ViewDataBinding mBinding;

    public BaseVH(ViewDataBinding mBinding) {
        super(mBinding.getRoot());
        this.mBinding = mBinding;
    }

    public void displayPost(final NewsItem post) {
        PostItemViewModel vm = new PostItemViewModel();
        vm.getPost().set(post);
        mBinding.setVariable(BR.viewModel, vm);
    }
}

public class TextPostVH extends BaseVH {
    private final PostTextBinding mBinding;

    public TextPostVH(final PostTextBinding binding) {
        super(binding);
        mBinding = binding;
    }

    //Have a method like this in the BaseVH.class
    @Override
    public void displayPost(final NewsItem post) {
        if (mBinding.getViewModel() == null) {
            mBinding.setViewModel(new PostItemViewModel());
        }
        mBinding.getViewModel().getPost().set(post);
    }
}

因此,您只需拨打onBindViewHolder

即可
@Override
public void onBindViewHolder(final BaseVH holder, final int position) {
    //only a ViewHolder containing ads has to be filtered, the others work with displayPost()
    if (holder instanceof AdVH){
        holder.displayPost(mPosts.get(position));
        ((AdVH) holder).displayAd();
    } else {
        holder.displayPost(mPosts.get(position));
    }
}

您可以在Binding class names标记中的layouts中指定data

 <data class="PostTextBinding" />

但我不认为你可以在不同的布局中使用相同的类名。您可以在GitHub找到我的(样本)项目。

解释了另一种解决方案here on Github。他们创造了一个(真的)普遍的RecyclerView.Adapter,但我发现这......对我来说有点太多了。

答案 1 :(得分:1)

@Amylinn是对的,这真的适合你,你可以让它更容易:

// Only one ViewHolder at all
public class BaseVH extends RecyclerView.ViewHolder {
    private ViewDataBinding mBinding;

    public BaseVH(ViewDataBinding mBinding) {
        super(mBinding.getRoot());
        this.mBinding = mBinding;
    }
    public ViewDataBinding() {
        return mBinding;
    }
}

onBindViewHolder

@Override
public void onBindViewHolder(final BaseVH holder, final int position) {
   // Just use "model" as name in any layouts
   holder.getBunding().setVariable(BR.model, mPosts.get(position));
}

但是您仍然需要在onCreateViewHolder

中创建具有不同布局的视图持有者

或者如果你喜欢使用委托,你可以看一下这种方法 - https://github.com/drstranges/DataBinding_For_RecyclerView

答案 2 :(得分:0)

我写了一个库:带有DataBinding的UniqueAdapter

UniqueAdapter

只需使用方法:

public abstract boolean setVariable(int variableId, Object value);

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if(holder instanceof UniqueViewHolder) {
        ItemModel item = getItem(position);
        UniqueViewHolder vh = ((UniqueViewHolder) holder);
        vh.dataBinding.setVariable(com.github.captain_miao.uniqueadapter.library.BR.viewModel, item);
        if (mPresenter != null) {
            vh.dataBinding.setVariable(com.github.captain_miao.uniqueadapter.library.BR.presenter, mPresenter);
        }
        vh.dataBinding.executePendingBindings();
    }
}