ListView to RecyclerView Migration for CustomView

后端 未结 1 976
天命终不由人
天命终不由人 2020-12-18 14:46

I see a need in my project to move from ListView to RecyclerView. I am facing some design issue.

In my current ListView implementation I am using CustomView instead

相关标签:
1条回答
  • 2020-12-18 15:43

    It's pretty straight-forward to translate your ListView adapter to a RecyclerView.Adapter - I've written skeletons for both implementations below:

    private static class MyRecyclerViewAdapter extends RecyclerView.Adapter<CustomViewHolder> {
    
        @Override
        public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            CustomView view = createNewCustomView();
            return new CustomViewHolder(view);
        }
    
        private CustomView createNewCustomView() {
            // whatever you need to do to create - I would suggest create from XML rather new'ing up directly
            return null;
        }
    
        @Override
        public void onBindViewHolder(CustomViewHolder holder, int position) {
            // bind the data
            DataModel dataModel = getModelForPosition(position);
            holder.getCustomView().showView(dataModel, position);
        }
    
        private DataModel getModelForPosition(int position) {
            // TODO: however you did getModelForPosition(int)
            return null;
        }
    
        @Override
        public int getItemCount() {
            // TODO: same as getCount()
            return 0;
        }
    
    }
    
    private static class CustomViewHolder extends RecyclerView.ViewHolder {
    
        public CustomViewHolder(CustomView itemView) {
            super(itemView);
        }
    
        CustomView getCustomView() {
            return ((CustomView) itemView);
        }
    
    }
    
    private static class MyListViewAdapter extends BaseAdapter {
    
        @Override
        public int getCount() {
            // TODO: return correct list size
            return 0;
        }
    
        @Override
        public DataModel getItem(int position) {
            // TODO: however you did getModelForPosition(int)
            return null;
        }
    
        @Override
        public long getItemId(int position) {
            // however you do
            return 0;
        }
    
        @Override
        public View getView(int position, View containerRow, ViewGroup parent) {
            CustomView customView = ((CustomView) containerRow);
            if (customView == null) {
                customView = createNewCustomView();
            }
    
            // could just use getItem(int) here
            DataModel dataModel = getModelForPosition(position);
    
            // would it ever be null? if so, you'll have a blank list item
            if (dataModel != null) {
                customView.showView(dataModel.getSingleDcyde(), position);
            }
            return customView;
        }
    
        private CustomView createNewCustomView() {
            // whatever you need to do to create - I would suggest create from XML rather new'ing up directly
            return null;
        }
    
        private DataModel getModelForPosition(int position) {
            return getItem(position);
        }
    
    }
    
    private static class DataModel {
    
        Object getSingleDcyde() {
            // whatever this is
            return null;
        }
    
    }
    
    private static class CustomView extends View {
    
        public CustomView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public void showView(Object singleDcyde, int position) {
            // bind
        }
    
    }
    

    What is the best way to keep design in sync with RecyclerView philosophy.

    The philosophy behind RecyclerView is separation of concerns; the RecyclerView is responsible only for managing view recycling, the LayoutManager will decide how views are measured and positioned, the ViewHolder is an attempt to force the ViewHolder pattern (an approach to avoid multiple unnecessary calls to findViewById()), and the RecyclerView.Adapter is the glue that hooks your data up.

    You're now forced to use the ViewHolder class. The idea is do all your findViewById() calls only once per inflated layout (whether or not this call is slow enough to bother doing is debated), e.g.:

    private static final class CustomViewHolder extends RecyclerView.ViewHolder {
    
        private final TextView titleTextView;
        private final ImageView avatarImageView;
    
        public CustomViewHolder newInstance(CustomView itemView) {
            return new CustomViewHolder(
                    itemView,
                    ((TextView) itemView.findViewById(R.id.title_text_view)),
                    ((ImageView) itemView.findViewById(R.id.avatar_image_view))
            );
        }
    
        private CustomViewHolder(CustomView itemView, TextView titleTextView, ImageView avatarImageView) {
            super(itemView);
            this.titleTextView = titleTextView;
            this.avatarImageView = avatarImageView;
        }
    
        public void setTitle(String title) {
            titleTextView.setText(title);
        }
    
        public void setAvatar(Drawable avatar) {
            avatarImageView.setImageDrawable(avatar);
        }
    
    }
    

    Actually, since you're using a custom View, it's very likely (I hope), that you're already avoiding multiple calls to findViewById(int) by using the HolderView pattern. In which case you can rebel against the tyranny of mandated ViewHolder usage by treating it as necessary evil:

    private static final class CustomViewHolder extends RecyclerView.ViewHolder {
    
        public CustomViewHolder(CustomView itemView) {
            super(itemView);
        }
    
    }
    
    ...
    ...
    
    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {
        Foo foo = getFoo(position);
        ((CustomView) holder.itemView).myCustomBindMethod(foo);
    }
    
    0 讨论(0)
提交回复
热议问题