RecyclerView适配器类中的多个布局视图

时间:2017-03-20 06:21:09

标签: android xml layout android-recyclerview adapter

这是我取得的成就?每个部分中 3 不同的部分 10 不同的

以下是教程 link我正在关注以下是屏幕截图

enter image description here

尝试为每个部分显示different Views。的像:

对于第1节(layout_1.xml)

对于第2节(layout_2.xml)

对于第3节(layout_3.xml)

在每个中显示布局视图 <{1}} ...(第1,2,3节)

我可以知道我在代码中的错误,我错过了什么吗?

layout_1.xml

11 个答案:

答案 0 :(得分:8)

在内部适配器的getItemViewType

中使用此功能
        @Override
        public int getItemViewType(int position) {
            if (position == 0) {
                return 0;
            } else if(position == 1) {
                return 1;
            } else {
              return 2;
            }
        }

答案 1 :(得分:2)

根据recyclerview中的位置使用多个布局,你必须覆盖适配器内的getItemViewType(int position)方法: -

 @Override
    public int getItemViewType(int position) {
        if(position==0)
            return  0;
        else if(position==1)
            return  1;
        else
            return 2;
    }

答案 2 :(得分:1)

<强> FYI

  

RecyclerView还可用于扩充多种视图类型。

  • 创建不同的Holder对你来说最简单。
  • 创建不同的适配器是最佳解决方案

尝试

  @Override
        public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

            switch (i) {

                case 0:
                    View viewONE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false);
                    SingleItemRowHolder rowONE = new SingleItemRowHolder(viewONE);
                    return rowONE;

                case 1:
                    View viewTWO = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false);
                    SingleItemRowHolderTwo rowTWO = new SingleItemRowHolderTwo (viewTWO);
                    return rowTWO;

                case 2:
                    View viewTHREE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false);
                    SingleItemRowHolderThree rowTHREE = new SingleItemRowHolderThree(viewTHREE);
                    return rowTHREE;

            }

            return null;

        }

阅读 RecyclerView can also be used to inflate multiple view types

答案 3 :(得分:1)

正如已经提到的那样,为了getItemViewType类的RecyclerView.Adapter方法,因为如果您将在实现该方法时看到它,您将看到它只返回0时间。

    public int getItemViewType(int position) {
        return 0;
    }

此处调整适配器的代码,以解决您的问题。

public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> {
    private static final int ITEM_TYPE_ROW_1 = 0;
    private static final int ITEM_TYPE_ROW_2 = 1;
    private static final int ITEM_TYPE_ROW_3 = 2;

    private ArrayList<SingleItemModel> itemsList;
    private Context context;

    public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) {
        this.itemsList = itemsList;
        this.context = context;
    }

    @Override
    public int getItemViewType(int position) {
        switch (position) {
            case 0:
                return ITEM_TYPE_ROW_1;
            case 1:
                return ITEM_TYPE_ROW_2;
            case 2:
                return ITEM_TYPE_ROW_3;
        }
        throw new RuntimeException(String.format("unexpected position - %d", position));
    }

    @Override
    public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        switch (viewType) {
            case ITEM_TYPE_ROW_1:
                View viewOne = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false);
                return new SingleItemRowHolder(viewOne);
            case ITEM_TYPE_ROW_2:
                View viewTwo = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false);
                return new SingleItemRowHolder(viewTwo);
            case ITEM_TYPE_ROW_3:
                View viewThree = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false);
                return new SingleItemRowHolder(viewThree);
        }

        throw new RuntimeException(String.format("unexpected viewType - %d", viewType));
    }

    @Override
    public void onBindViewHolder(SingleItemRowHolder holder, int i) {
        SingleItemModel singleItem = itemsList.get(i);
        holder.tvTitle.setText(singleItem.getName());
    }

    @Override
    public int getItemCount() {
        return (null != itemsList ? itemsList.size() : 0);
    }

    class SingleItemRowHolder extends RecyclerView.ViewHolder {
        TextView tvTitle;
        ImageView itemImage;

        public SingleItemRowHolder(View view) {
            super(view);

            this.tvTitle = (TextView) view.findViewById(R.id.tvTitle);
            this.itemImage = (ImageView) view.findViewById(R.id.itemImage);

            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

}

答案 4 :(得分:1)

您可以通过更简单的方式完成此操作。在初始化适配器时传递任何flag

public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> {
    private ArrayList<SingleItemModel> itemsList;
    private Context context;
    private int view;

    public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, int layoutFlag) {
        this.itemsList = itemsList;
        this.context = context;
        switch(layoutFlag) {
           case 0:
               view = R.layout.layout_1;
               break;
           case 1:
               view = R.layout.layout_2;
               break;
           case 2:
               view = R.layout.layout_3;
               break;
        }
    }
...
...
...
}

使用此view进行布局参考。您只需要确定在设置适配器时要充气的布局。

答案 5 :(得分:0)

您需要覆盖方法

int getItemViewType (int position)

它接收行号,你需要返回行的“类型”,即1 2或3。

然后将结果传递给onCreateViewHolder。

答案 6 :(得分:0)

例如,如果要显示此视图列表:

TYPE1 TYPE2 3型 TYPE1 TYPE2 TYPE3

然后应该做的工作:

public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> {
    private static final int ITEM_TYPE_ROW_1 = 0;
    private static final int ITEM_TYPE_ROW_2 = 1;
    private static final int ITEM_TYPE_ROW_3 = 2;

    private ArrayList<SingleItemModel> itemsList;
    private Context context;
    private ArrayList<Integer> viewTypes = new ArrayList<>();

    public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) {
        this.itemsList = itemsList;
        this.context = context;

        viewTypes.add(ITEM_TYPE_ROW_1);
        viewTypes.add(ITEM_TYPE_ROW_2);
        viewTypes.add(ITEM_TYPE_ROW_3);
        viewTypes.add(ITEM_TYPE_ROW_1);
        viewTypes.add(ITEM_TYPE_ROW_2);
        viewTypes.add(ITEM_TYPE_ROW_3);

    }

    @Override
    public int getItemViewType(int position) {
       return viewTypes.get(position);            
    }

    @Override
    public int getItemCount() {
        return viewTypes.size();
    }


    .......
    ........

如果要添加/删除行,则可以在 viewTypes 数组中插入/删除viewTypes,然后调用RecyclerView notifyItemInserted或notifyItemRemoved方法,列表将使用新订单和类型进行更新观点。

答案 7 :(得分:0)

只需在您的片段中使用框架布局,并将此片段添加到您的framelayout中,这将添加您想要的内容。所以它也很容易处理。希望这会对你有所帮助

答案 8 :(得分:0)

是的,你需要覆盖getItemViewType(int position)方法,这有助于在recyclerview中膨胀不同的视图。

我发布的示例代码可能对您有帮助。

public class TransactionHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int TYPE_HEADER = 1;
private final int TYPE_CHILD = 2;
private final Context mContext;
private final List<TransactionResultEntity> mTransactionList;


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    switch (viewType) {
        case TYPE_HEADER:
            View headerView = LayoutInflater.from(mContext)
                    .inflate(R.layout.row_transaction_header, parent, false);
            return new ParentTypeDataObjectHolder(headerView);
        case TYPE_CHILD:
            View childView = LayoutInflater.from(mContext)
                    .inflate(R.layout.row_transaction_child, parent, false);
            return new ChildTypeDataObjectHolder(childView);
    }
    return null;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    switch (holder.getItemViewType()) {
        case TYPE_HEADER:
            ParentTypeDataObjectHolder parentTypeDataObjectHolder = (ParentTypeDataObjectHolder) holder;
            parentTypeDataObjectHolder.headerYearMonthTv.setText(mTransactionList.get(holder.getAdapterPosition()).getRowLabel());
            break;

        case TYPE_CHILD:
            ChildTypeDataObjectHolder childTypeDataObjectHolder = (ChildTypeDataObjectHolder) holder;
           childTypeDataObjectHolder.txnAmountTv.setText(mTransactionList.get(holder.getAdapterPosition()).getTransactionAmount());
            break;
    }
}


@Override
public int getItemCount() {
    return mTransactionList.size();
}

@Override
public int getItemViewType(int position) {
    if (mTransactionList.get(position).getDataType() == TYPE_HEADER)
        return TYPE_HEADER;
    else
        return TYPE_CHILD;
}

class ParentTypeDataObjectHolder extends RecyclerView.ViewHolder {

    private final TextView headerYearMonthTv;

    public ParentTypeDataObjectHolder(View itemView) {
        super(itemView);
        headerYearMonthTv = (TextView) itemView.findViewById(R.id.row_transaction_header_tv);
    }
}

class ChildTypeDataObjectHolder extends RecyclerView.ViewHolder {
    TextView txnAmountTv;

    public ChildTypeDataObjectHolder(View itemView) {
        super(itemView);
        txnAmountTv = (TextView) itemView.findViewById(R.id.transaction_child_txn_amount_tv);
                }
}

}

答案 9 :(得分:0)

您需要做的只是覆盖适配器中的方法getItemViewType()

你可以把它写成:

 @Override
    public int getItemViewType(int position) {
        if (position < 0) {
            return 0;
        } else if(position < 20) {
            return 1;
        } else {
          return 2;
        }
    }

如果您的itemsList ArrayList包含第1部分的前10项,第2部分的下10项和第3部分的最后10项,则上述逻辑有效。

如果不是这种情况,那么您的sectionNumber类中可以有一个整数字段SingleItemModel,它指定该模型所属的部分编号。现在,您可以将方法getItemViewType()修改为

@Override
public int getItemViewType(int position) {
    SingleItemModel singleItemModel = itemsList.get(position);
    if (singleItemModel.getSection() == 1) {
        return 0;
    } else if(singleItemModel.getSection() == 2) {
        return 1;
    } else {
      return 2;
    }
}

答案 10 :(得分:0)

好吧,如果我做对了,你想制作第二个适配器,提供行列表的变量,变量,所以它支持不同的布局,不是基于它的位置,而是基于主适配器的一些数据(一个提供部分)。因此,重写getItemViewType将不起作用,因为节数据包含在主适配器中,它甚至没有到达那里。所以,最好,最干净的课程是使用...... 抽象。忘记多个视图。使用一个,然后绑定自定义视图。自定义视图将提供特定的布局文件,并将设置其中包含的控件。持有者将完成它的目的:通过重用视图来保存ram。这方面的优点是,你可以拥有一个干净的层次结构,它可以在时间上增加复杂性,而不是一个很难维护的大型胖适配器。这就是:

由于这里有很多代码可以放在这里,我采用了你的示例项目并进行了修改,以提供我理解你想要做的事情。这是:

https://github.com/fcopardo/exampleCustomViewsInHolder/tree/master

亮点:

public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> {

    private ArrayList<SingleItemModel> itemsList;
    private Context context;
    private String section;

    public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, String sectionName) {
        this.itemsList = itemsList;
        this.context = context;
        this.section = sectionName;
    }

    @Override
    public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        return new SingleItemRowHolder(RowFactory.getRow(context, section));
    }

    @Override
    public void onBindViewHolder(SingleItemRowHolder holder, int i) {
        holder.setData(itemsList.get(i));
    }

    @Override
    public int getItemCount() {
        return (null != itemsList ? itemsList.size() : 0);
    }

    public class SingleItemRowHolder extends RecyclerView.ViewHolder {

        protected AbstractRowElement rowElement;

        public SingleItemRowHolder(AbstractRowElement view) {
            super(view);
            this.rowElement = view;
        }

        public void setData(SingleItemModel singleItemModel){
            rowElement.setItem(singleItemModel);
        }

    }



}

这是可变布局适配器。如您所见,它只使用一个ViewHolder和一个工厂来提供您需要的视图实例。

public class RowFactory {

    public static AbstractRowElement getRow(Context context, String name){
        switch (name){
            case "Section 1": return new FullRowElement(context);
            case "Section 2": return new TextRowElement(context);
            case "Section 3": return new ImageRowElement(context);
            default:
                Log.e("inflate", name);
                return new FullRowElement(context);
        }
    }
}

这提供了自定义视图,每个视图使用不同的布局,但基于节标题使用相同的数据集。

public abstract class AbstractRowElement extends CardView{

    protected int layout = 0;
    protected SingleItemModel singleItemModel;

    public AbstractRowElement(Context context) {
        super(context);
        inflateBaseLayout();
    }

    public AbstractRowElement(Context context, AttributeSet attrs) {
        super(context, attrs);
        inflateBaseLayout();
    }

    public AbstractRowElement(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        inflateBaseLayout();
    }

    protected void inflateBaseLayout() {
        this.setContainer();
        if(this.layout != 0) {
            LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            inflater.inflate(layout, this, true);
            this.inflateComponents();
        }
    }

    protected abstract void setContainer();
    protected abstract void inflateComponents();

    public void setItem(SingleItemModel itemModel){
        this.singleItemModel = itemModel;
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), singleItemModel.getName()+"\n"+singleItemModel.getDescription(), Toast.LENGTH_SHORT).show();
            }
        });
        setData(singleItemModel);
    }
    public abstract void setData(SingleItemModel itemModel);

}

最后,这是适配器的基本视图类。子类定义要使用的布局文件,并将所需数据放入控件中。其余的很简单。

完全可以在没有自定义视图的情况下进行此操作。你可以做类似的事情:

int layoutFile = getLayoutForSection(section);
View v = LayoutInflater.from(viewGroup.getContext()).inflate(layoutFile, null);

但是,由于我不知道您打算创建的视图有多复杂,因此最好将事物分开。玩得开心!