Implement multiple ViewHolder types in RecycleView adapter

后端 未结 9 1669
迷失自我
迷失自我 2020-12-13 16:34

It\'s maybe a discussion not a question.

Normal way to implement multiple types

As you know, if we want to implement multiple types in RecyclerView

相关标签:
9条回答
  • 2020-12-13 17:01

    Here you can use Dynamic method dispatch. Below i share my idea. //Activity Code

    public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        ArrayList<Object> dataList = new ArrayList<>();
        dataList.add("Apple");
        dataList.add("Orange");
        dataList.add("Cherry");
        dataList.add("Papaya");
        dataList.add("Grapes");
        dataList.add(100);
        dataList.add(200);
        dataList.add(300);
        dataList.add(400);
        ViewAdapter viewAdapter = new ViewAdapter(dataList);
        recyclerView.setAdapter(viewAdapter);
    
    }
    

    }

    //Adapter code

    public class ViewAdapter extends RecyclerView.Adapter<BaseViewHolder> {
    private ArrayList<Object> dataList;
    public ViewAdapter(ArrayList<Object> dataList) {
        this.dataList = dataList;
    }
    
    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        BaseViewHolder baseViewHolder;
    
        if(viewType == 0) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_one,parent,false);
            baseViewHolder  = new ViewHolderOne(view);
        }else  {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_two,parent,false);
            baseViewHolder  = new ViewHolderSecond(view);
        }
        return baseViewHolder;
    }
    
    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        holder.bindData(dataList.get(position));
    }
    
    @Override
    public int getItemViewType(int position) {
        Object obj = dataList.get(position);
        int type = 0;
        if(obj instanceof Integer) {
            type = 0;
        }else if(obj instanceof String) {
            type = 1;
        }
        return type;
    }
    
    @Override
    public int getItemCount() {
        return dataList != null ? dataList.size() : 0;
    }
    

    }

    //Base View Holder Code.

    public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {
    public BaseViewHolder(View itemView) {
        super(itemView);
    }
    
    public abstract void bindData(T data);
    

    }

    //View Holder One Source Code.

    public class ViewHolderOne extends BaseViewHolder<Integer> {
    
    private TextView txtView;
    public ViewHolderOne(View itemView) {
        super(itemView);
        txtView = itemView.findViewById(R.id.txt_number);
    }
    
    @Override
    public void bindData(Integer data) {
        txtView.setText("Number:" + data);
    }
    

    }

    //View Holder Two

    public class ViewHolderSecond extends BaseViewHolder<String> {
    
    private TextView textView;
    public ViewHolderSecond(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.txt_string);
    }
    
    @Override
    public void bindData(String data) {
        textView.setText("Text:" + data);
    }
    

    }

    For project Source: enter link description here

    0 讨论(0)
  • 2020-12-13 17:03

    It might not be the answer you're expecting but here is an example using Epoxy, which really makes your life easier:

    First you define your models:

    @EpoxyModelClass(layout = R.layout.header_view_model)
    public abstract class HeaderViewModel extends EpoxyModel<TextView> {
    
        @EpoxyAttribute
        String title;
    
        @Override
        public void bind(TextView view) {
            super.bind(view);
            view.setText(title);
        }
    
    }
    
    @EpoxyModelClass(layout = R.layout.drink_view_model)
    public abstract class DrinkViewModel extends EpoxyModel<View> {
    
        @EpoxyAttribute
        Drink drink;
    
        @EpoxyAttribute
        Presenter presenter;
    
        @Override
        public void bind(View view) {
            super.bind(view);
    
            final TextView title = view.findViewById(R.id.title);
            final TextView description = view.findViewById(R.id.description);
    
            title.setText(drink.getTitle());
            description.setText(drink.getDescription());
            view.setOnClickListener(v -> presenter.drinkClicked(drink));
        }
    
        @Override
        public void unbind(View view) {
            view.setOnClickListener(null);
            super.unbind(view);
        }
    
    }
    
    @EpoxyModelClass(layout = R.layout.food_view_model)
    public abstract class FoodViewModel extends EpoxyModel<View> {
    
        @EpoxyAttribute
        Food food;
    
        @EpoxyAttribute
        Presenter presenter;
    
        @Override
        public void bind(View view) {
            super.bind(view);
    
            final TextView title = view.findViewById(R.id.title);
            final TextView description = view.findViewById(R.id.description);
            final TextView calories = view.findViewById(R.id.calories);
    
            title.setText(food.getTitle());
            description.setText(food.getDescription());
            calories.setText(food.getCalories());
            view.setOnClickListener(v -> presenter.foodClicked(food));
        }
    
        @Override
        public void unbind(View view) {
            view.setOnClickListener(null);
            super.unbind(view);
        }
    
    }
    

    Then you define your Controller:

    public class DrinkAndFoodController extends Typed2EpoxyController<List<Drink>, List<Food>> {
    
        @AutoModel
        HeaderViewModel_ drinkTitle;
    
        @AutoModel
        HeaderViewModel_ foodTitle;
    
        private final Presenter mPresenter;
    
        public DrinkAndFoodController(Presenter presenter) {
            mPresenter = presenter;
        }
    
        @Override
        protected void buildModels(List<Drink> drinks, List<Food> foods) {
            if (!drinks.isEmpty()) {
                drinkTitle
                        .title("Drinks")
                        .addTo(this);
                for (Drink drink : drinks) {
                    new DrinkViewModel_()
                            .id(drink.getId())
                            .drink(drink)
                            .presenter(mPresenter)
                            .addTo(this);
                }
            }
    
            if (!foods.isEmpty()) {
                foodTitle
                        .title("Foods")
                        .addTo(this);
                for (Food food : foods) {
                    new FoodViewModel_()
                            .id(food.getId())
                            .food(food)
                            .presenter(mPresenter)
                            .addTo(this);
                }
            }
        }
    }
    

    Initialize your Controller:

    DrinkAndFodController mController = new DrinkAndFoodController(mPresenter);
    mController.setSpanCount(1);
    
    final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 1);
    layoutManager.setSpanSizeLookup(mController.getSpanSizeLookup());
    mRecyclerView.setLayoutManager(layoutManager);
    mRecyclerView.setAdapter(mController.getAdapter());
    

    And finally you can add your data as easily as this:

    final List<Drink> drinks = mManager.getDrinks();
    final List<Food> foods = mManager.getFoods();
    mController.setData(drinks, foods);
    

    You'll have a list thats looks like:

    Drinks
    Drink 1
    Drink 2
    Drink 3
    ...
    Foods
    Food1
    Food2
    Food3
    Food4
    ...
    

    For more informations you can check the wiki.

    0 讨论(0)
  • 2020-12-13 17:04

    Second one is buggy because when ViewHolders get recycled it produces unexpected behavior. I considered changing visibility during binding but it isn't performant enough for large amount of Views. Recycler inside RecyclerView stores ViewHolders per type so first way is more performant.

    0 讨论(0)
提交回复
热议问题