How to use the same RecyclerView Adapter for different layouts

后端 未结 4 2092
逝去的感伤
逝去的感伤 2021-02-09 06:48

I am developing an application which heavily relies on the usage of RecyclerView.

I really need to know how to use the same RecyclerView for different item layouts. An e

相关标签:
4条回答
  • I came across similar situation and here is the model i followed.

    First of all, Fragment layout file.

    fragment layout file is not going to change for all 3 fragments(basically it is similar to list fragment), so I created a template file for list fragment.

    list_fragment_template.xml
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </FrameLayout>
    

    Now fragment code :

    In my case all the 3 fragments do almost same stuff (get recycler view, get adapter, recycler view decoration and some more operations etc).

    Created an AbstrctFragment which extends fragment and overrided onCreate onAttach onDestroy etc. Since only type of data recyclerview consumes and adapters to push data to recycelrview would change for each of the fragment, create an abstract function to getAdapter and templatize data. Each of the three fragments will be derived from this AbstractFragment.

        public abstract class AbstractFragment<E> extends Fragment {
    
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
    
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.template_list_fragment, container, false);
    
    
                mRecyclerView = (RecyclerView) view.findViewById(R.id.list);
    
                // get adapter to show item list
                // and fetch data.
                mRecyclerAdapter = getAdapter();
                mRecyclerView.setAdapter(mRecyclerAdapter);
    
                // show it as vertical list
                mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
                // add seperator between list items.
                mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
    
    return view;
        }
    

    ... onAttach onDetach and whatever common memberfunctions and member variables that comes for each fragment.

    Now RecyclerView layout files. Since all of them are different in layout, obviously they must be different.

    RecyclerViewAdapters : Again here common code would be to member declarations, CreateViewHolder (here only layout name changes rest all code is same) and any other function which all of these adapters would share. (something like filtering list items).

    similar to how we did for fragments, you can keep this in AbstractRecyclerViewAdapter and make bindViewholder etc as abstract functions and have 3 different recyclerAdapters which would derive from this AbstractRecyclerViewAdapter..

    0 讨论(0)
  • 2021-02-09 07:12
    //To setViewType maybe is a solution for you.Sample below:  
    private static final int TYPE_DESC = 0;
    private static final int TYPE_IMAGE = TYPE_DESC + 1;
    private static final int TYPE_THREE_TEXT = TYPE_IMAGE + 1;
    public int getItemViewType(int position) {
        int type = super.getItemViewType(position);
        try
        {
            type = Integer.parseInt(data.get(position).get("type"));
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return type;
    }
    
    public int getViewTypeCount() {
        return 3;
    }
    public View getView(int position, View convertView, ViewGroup parent) {
        int type = TYPE_DESC;
        try
        {
            type = Integer.parseInt(data.get(position).get("type"));
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        ViewHolder holder = null;
        if (convertView == null)
        {
            System.out.println("getView::convertView is null");
            holder = new ViewHolder();
            switch (type)
            {
                case TYPE_DESC:
                    convertView = View.inflate(getBaseContext(),
                            R.layout.listitem_1, null);
                    break;
                case TYPE_IMAGE:
                    convertView = View.inflate(getBaseContext(),
                            R.layout.listitem_2, null);
                    break;
                case TYPE_THREE_TEXT:
                    convertView = View.inflate(getBaseContext(),
                            R.layout.listitem_3, null);
                    break;
            }
            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }
        //TODO
        return convertView;
    }
    
    0 讨论(0)
  • 2021-02-09 07:18

    Since the recyclerview item in xml doesn't depend on the kind of items that you will inflating in it, you can go ahead and use the same recycler view layout file for the three fragments.

    As for the adapters, your lists seem to be homogeneous (i.e., single kind of view item). Its best that you use 3 different adapters for each case. You can customise the constructor, add custom helper methods for each kind of adapter as per your convenience.

    Now if you have a heterogeneous list, you will have to override getItemViewType() in your adapter and use this appropriately in onCreateViewHolder() and onBindViewHolder()

    Hope this helps! :)

    0 讨论(0)
  • 2021-02-09 07:32

    its too late but, might be helpful for someone needy developer Your adapter should look like this, also you can add header and footer using this sample

    public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> {
    
    // Declaring Variable to Understand which View is being worked on
    // IF the view under inflation and population is header or Item
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;
    private static final int TYPE_FOOTER = 2;
    
    private Activity mContext;
    private ArrayList<DataModel> _mItems;
    private int mLayout;
    private String mProductHeadingTitle="Heading";
    private String mProductHeadingSubTitle="SubHeading";
    private String loadingText="LOADING";
    private int visibility= View.VISIBLE;
    
    public interface SampleAdapterInterface {
         void itemClicked(int position);
    }
    
    SampleAdapterInterface mCallBack;
    
    public SampleAdapter(Activity context, ArrayList<DataModel> items, int item_layout) {
        if (_mItems != null) {
            _mItems.clear();
        }
        this.mContext = context;
        this._mItems = items;
        this.mLayout = item_layout;
        mCallBack = (SampleAdapterInterface) context;
    }
    
    @Override
    public int getItemCount() {
        return _mItems.size()+2; // +2 for header and footer
    }
    
    @Override
    public int getItemViewType(int position) {
    
        if (position==0)
            return TYPE_HEADER;
        else if(position==(_mItems.size()+1))
            return TYPE_FOOTER;
    
        return TYPE_ITEM;
    }
    
    public void setHeaderData(String title,String subTitle)
    {
        this.mProductHeadingTitle=title;
        this.mProductHeadingSubTitle=subTitle;
    
        Log.d("LOG", "ProductHeadingTitle: " + mProductHeadingTitle);
        Log.d("LOG", "ProductHeadingSubTitle: " + mProductHeadingSubTitle);
    
        notifyDataSetChanged();
    }
    
    public void setFooterData(String loadingText,int visibility)
    {
        this.loadingText=loadingText;
        this.visibility=visibility;
    
        Log.d("LOG", "LoadingText: " + loadingText);
        Log.d("LOG", "Visibility: " + visibility);
    
        notifyDataSetChanged();
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    
    
        if (viewType == TYPE_HEADER)
        {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_layout,parent,false);
    
            ViewHolder vhHeader = new ViewHolder(view,viewType);
    
            return vhHeader;
        }
        else if (viewType == TYPE_ITEM)
        {
            View view = LayoutInflater.from(parent.getContext()).inflate(mLayout,parent,false);
    
            //Creating ViewHolder and passing the object of type view
            ViewHolder vhItem = new ViewHolder(view,viewType);
    
            return vhItem;
        }
        else if (viewType == TYPE_FOOTER)
        {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footer_lyout,parent,false);
    
            ViewHolder vhFooter = new ViewHolder(view,viewType);
    
            return vhFooter;
        }
        return null;
    }
    
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int pos) {
    
    
        if(viewHolder.Holderid ==0)
        {
            // header view
            Log.d("LOG", "in header binder");
            viewHolder.mProductCatalogTitle.setText(mProductHeadingTitle);
            viewHolder.mProductCatalogSubTitle.setText(mProductHeadingSubTitle);
        }
        else if(viewHolder.Holderid==1)
        {
            final int position=pos-1; // -1 to substract header number
            // your code
        }
        else if(viewHolder.Holderid==2)
        {
            // footer
            Log.d("LOG", "in footer binder");
            viewHolder.mProgressBar.setVisibility(visibility);
            viewHolder.mLoading.setText(loadingText);
        }
    
    
    }
    
    class ViewHolder extends RecyclerView.ViewHolder {
    
        int Holderid;
    
        // header
        TextView mProductCatalogTitle;
        TextView mProductCatalogSubTitle;
    
        //list
        // item type variable declaration
    
        // footer
        ProgressBar mProgressBar;
        TextView mLoading;
    
        public ViewHolder(View itemView, int viewType) {
            super(itemView);
            // Here we set the appropriate view in accordance with the the view type as passed when the holder object is created
            if(viewType == TYPE_HEADER)
            {
                Holderid = 0;
                mProductCatalogTitle = (TextView) itemView.findViewById(R.id.tv_title);
                mProductCatalogSubTitle = (TextView) itemView.findViewById(R.id.tv_subtitle);
            }
            else if(viewType == TYPE_ITEM)
            {
                Holderid = 1;
                itemView.setClickable(true);
                itemView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mCallBack.itemClicked(getAdapterPosition()-1);
                    }
                });
                // initialize the view holder
            }
    
            else if(viewType == TYPE_FOOTER)
            {
                Holderid = 2;
                mLoading = (TextView) itemView.findViewById(R.id.tv_loading);
                mProgressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
            }
        }
    }
    

    in your activity

    // Adding to adapter as gridview when grid button clicked
    private void setProductGridAdapter() {
        mListViewTab.setVisibility(View.VISIBLE);
        mGridViewTab.setVisibility(View.INVISIBLE);
    
        mSampleAdapter = new SampleAdapter(YourActicity.this,
                yourlist,R.layout.item_product_grid);
        mRecyclerView.setAdapter(mSampleAdapter);
    
        mRecyclerView.setHasFixedSize(true);
    
        final GridLayoutManager layoutManager = new GridLayoutManager(getActivity(),
                2,                              //number of columns
                LinearLayoutManager.VERTICAL,   // orientation
                false);                         //reverse layout
        mRecyclerView.setLayoutManager(layoutManager);
    
        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
    
                // to show header and footer in full row
                if(position==0 || position==(yourlist.size()+1))
                    return layoutManager.getSpanCount();
                else
                    return 1;
            }
        });
    
        mRecyclerView.scrollToPosition(AppController.currentPosition);
    
        mSampleAdapter.notifyDataSetChanged();
    
        // Scroll listener for RecyclerView to call load more products
        mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
                int visibleItemCount = layoutManager.getChildCount();
                int totalItemCount = layoutManager.getItemCount();
                int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
    
                int lastInScreen = firstVisibleItem + visibleItemCount;
                if ((lastInScreen >= totalItemCount) && !isLoading) {
                    //last item
                    // do something after last item like load more code or 
                    // show No more items string
                    mSampleAdapter.setFooterData("NO More Items",View.INVISIBLE);
                }
                AppController.currentPosition = firstVisibleItem;
            }
        });
    
    }
    
    // Adding to adapter as listview when list button clicked
    private void setProductListAdapter() {
        mListViewTab.setVisibility(View.INVISIBLE);
        mGridViewTab.setVisibility(View.VISIBLE);
    
        mSampleAdapter = new SampleAdapter(YourActicity.this, yourlist,R.layout.item_product_list);
        mRecyclerView.setAdapter(mSampleAdapter);
    
        mRecyclerView.setHasFixedSize(true);
    
        final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(),
                LinearLayoutManager.VERTICAL,   // orientation
                false);                         //reverse layout
        mRecyclerView.setLayoutManager(layoutManager);
    
        mRecyclerView.scrollToPosition(AppController.currentPosition);
        mSampleAdapter.notifyDataSetChanged();
    
        // Scroll listener for RecyclerView to call load more products
        mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
                int visibleItemCount = layoutManager.getChildCount();
                int totalItemCount = layoutManager.getItemCount();
                int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
    
                int lastInScreen = firstVisibleItem + visibleItemCount;
                if ((lastInScreen >= totalItemCount) && !isLoading) {
                    //last item
                    // do something after last item like load more code or 
                    // show No more items string
                    mSampleAdapter.setFooterData("NO MOre Items",View.INVISIBLE);
                }
                AppController.currentPosition = firstVisibleItem;
            }
        });
    }
    

    and your activity must implement SampleAdapterInterface in activity to get callback from adapter. Call those methods when toggling button from grid to list and vice versa

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