බහුවිධ දර්ශන වර්ගයකින් ප්‍රතිචක්‍රීකරණ දර්ශනය නිර්මාණය කරන්නේ කෙසේද?


888

Https://developer.android.com/preview/material/ui-widgets.html වෙතින්

අප නිර්මාණය කරන විට එය ඇඩැප්ටරය සමඟ බැඳී RecyclerView.Adapterඇති බව සඳහන් ViewHolderකළ යුතුය .

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private String[] mDataset;

    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mTextView;
        public ViewHolder(TextView v) {
            super(v);
            mTextView = v;
        }
    }

    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.some_layout, parent, false);

        //findViewById...

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.mTextView.setText(mDataset[position]);
    }

    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

ඉතින්, RecyclerViewබහු දර්ශන වර්ග සමඟ නිර්මාණය කළ හැකිද?


5
ඇන්ටන්ගේ පිළිතුරට ඉහළින්, මගේ පිළිතුර මෙතැනින් බලන්න: stackoverflow.com/questions/25914003/…
ticofab

ඔබට ප්‍රයෝජනවත් වන මෙම සබැඳිය පරීක්ෂා කරන්න stackoverflow.com/a/39972276/3946958
රවීන්ද්‍ර කුෂ්වා

1
හොඳ නිබන්ධනය මෙහි: guide.codepath.com/android/…
ජීන් බෝ

මෙම ලින්ක් එක පරීක්ෂා කරන්න එය ක්රියාත්මක කළ හැකිය stackoverflow.com/questions/39971350/... ප්රශ්නය මට කියන්න වඩා කරුණාකර පවතී නම්
රවීන්ද්ර Kushwaha

එය ක්‍රියාත්මක කිරීම සඳහා වූ මහා පුස්තකාලය github.com/vivchar/RendererRecyclerViewAdapter
Vitaly

Answers:


1296

ඔව්, හැකි ය. GetItemViewType () ක්‍රියාත්මක කර viewTypeපරාමිතිය ගැන සැලකිලිමත් වන්න onCreateViewHolder().

එබැවින් ඔබ මෙවැනි දෙයක් කරයි:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    class ViewHolder0 extends RecyclerView.ViewHolder {
        ...
        public ViewHolder0(View itemView){
        ...
        }
    }

    class ViewHolder2 extends RecyclerView.ViewHolder {
        ...
        public ViewHolder2(View itemView){
        ...
    }

    @Override
    public int getItemViewType(int position) {
        // Just as an example, return 0 or 2 depending on position
        // Note that unlike in ListView adapters, types don't have to be contiguous
        return position % 2 * 2;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case 0: return new ViewHolder0(...);
             case 2: return new ViewHolder2(...);
             ...
         }
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
        switch (holder.getItemViewType()) {
            case 0:
                ViewHolder0 viewHolder0 = (ViewHolder0)holder;
                ...
                break;

            case 2:
                ViewHolder2 viewHolder2 = (ViewHolder2)holder;
                ...
                break;
        }
    }
}

3
එක් ප්‍රතිචක්‍රීකරණ දර්ශනයක ඇත්තේ එක් ViewHolder එකක් පමණක් බැවින් එය මගේ අදහසයි.
පොන්ගට්

48
එවිට ඔබ සාමාන්‍ය වර්ගයේ අරමුණ පරාජය කරන බව සිතන ඔන්බින්ඩ්වීව්හෝල්ඩර් () ක්‍රමයට නරඹන්නන්ගේ වර්ගය දැමිය යුතුය. මාර්ගය වන විට, ඔබගේ පිළිතුරට ස්තූතියි.
පොන්ගට්

32
ඔබට BaseHolder එකක් සාදා එය අවශ්‍ය සියලුම වර්ග සඳහා දිගු කළ හැකිය. ඉන්පසු වියුක්ත සෙට් ඩේටා එක් කරන්න, එය ක්‍රියාත්මක කරන්නන් තුළ අභිබවා යනු ඇත (ඉක්මවා යයි?) මේ ආකාරයෙන් ඔබ භාෂාවේ ආකාරයේ වෙනස්කම් හැසිරවීමට ඉඩ දෙයි. එය ක්‍රියාත්මක වන්නේ ඔබ සතුව සියලුම දත්ත අයිතමයන් අර්ථ නිරූපණය කළ හැකි තනි දත්ත කට්ටලයක් තිබේ නම් පමණි.
ඩාරියස් එල්

2
විවිධ පිරිසැලසුම් ගොනුව ගැන කුමක් කිව හැකිද? මට පිරිසැලසුම වෙනස් කිරීමට අවශ්‍යයි optionMenuItem. එය කෙසේ විය හැකිද? @AntonSavin
Pratik භූතානි

6
ඔබේ ප්‍රතිචක්‍රීකරණ දර්ශන ඇඩැප්ටරයේ ඔබේ දර්ශන හෝල්ඩර්ස් ස්ථිතික විය යුතුය
සමර්

90

දර්ශන වර්ග සඳහා පිරිසැලසුම් කිහිපයක් පමණක් නම් සහ බන්ධන තර්කනය සරල නම්, ඇන්ටන්ගේ විසඳුම අනුගමනය කරන්න.
නමුත් ඔබට සංකීර්ණ පිරිසැලසුම් සහ බන්ධන තර්කනය කළමනාකරණය කිරීමට අවශ්‍ය නම් කේතය අවුල් සහගත වනු ඇත.

සංකීර්ණ දර්ශන වර්ග හැසිරවීමට අවශ්‍ය අයෙකුට පහත විසඳුම ප්‍රයෝජනවත් වනු ඇතැයි මම විශ්වාස කරමි.

මූලික දත්ත බින්ඩර් පන්තිය

abstract public class DataBinder<T extends RecyclerView.ViewHolder> {

    private DataBindAdapter mDataBindAdapter;

    public DataBinder(DataBindAdapter dataBindAdapter) {
        mDataBindAdapter = dataBindAdapter;
    }

    abstract public T newViewHolder(ViewGroup parent);

    abstract public void bindViewHolder(T holder, int position);

    abstract public int getItemCount();

......

}

මෙම පන්තියේ නිර්වචනය කිරීමට අවශ්‍ය කාර්යයන් තනි දර්ශන වර්ගය නිර්මාණය කිරීමේදී ඇඩැප්ටර පන්තියට සමාන වේ.
එක් එක් දර්ශන වර්ගය සඳහා, මෙම දත්ත බින්ඩරය දිගු කිරීමෙන් පන්තිය සාදන්න.

නියැදි ඩේටාබයින්ඩර් පන්තිය

public class Sample1Binder extends DataBinder<Sample1Binder.ViewHolder> {

    private List<String> mDataSet = new ArrayList();

    public Sample1Binder(DataBindAdapter dataBindAdapter) {
        super(dataBindAdapter);
    }

    @Override
    public ViewHolder newViewHolder(ViewGroup parent) {
        View view = LayoutInflater.from(parent.getContext()).inflate(
            R.layout.layout_sample1, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void bindViewHolder(ViewHolder holder, int position) {
        String title = mDataSet.get(position);
        holder.mTitleText.setText(title);
    }

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

    public void setDataSet(List<String> dataSet) {
        mDataSet.addAll(dataSet);
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        TextView mTitleText;

        public ViewHolder(View view) {
            super(view);
            mTitleText = (TextView) view.findViewById(R.id.title_type1);
        }
    }
}

ඩේටාබයින්ඩර් පන්ති කළමනාකරණය කිරීම සඳහා, ඇඩැප්ටර පන්තිය සාදන්න.

මූලික DataBindAdapter පන්තිය

abstract public class DataBindAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return getDataBinder(viewType).newViewHolder(parent);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        int binderPosition = getBinderPosition(position);
        getDataBinder(viewHolder.getItemViewType()).bindViewHolder(viewHolder, binderPosition);
    }

    @Override
    public abstract int getItemCount();

    @Override
    public abstract int getItemViewType(int position);

    public abstract <T extends DataBinder> T getDataBinder(int viewType);

    public abstract int getPosition(DataBinder binder, int binderPosition);

    public abstract int getBinderPosition(int position);

......

}

මෙම මූලික පංතිය දීර් by කිරීමෙන් පන්තිය සාදන්න, ඉන්පසු ඩේටාබයින්ඩර් පන්ති ක්ෂණිකව ක්‍රියාත්මක කර වියුක්ත ක්‍රම ඉක්මවා යන්න

  1. getItemCount DataBinders
    හි මුළු අයිතම ගණන ආපසු එවන්න

  2. getItemViewType
    ඇඩැප්ටරයේ පිහිටීම සහ දර්ශන වර්ගය අතර සිතියම්කරණ තර්කනය නිර්වචනය කරන්න.

  3. getDataBinder
    දර්ශන වර්ගය මත පදනම්ව ඩේටාබයින්ඩර් උදාහරණය නැවත ලබා දෙන්න

  4. getPosition
    නිශ්චිත ඩේටාබයින්ඩරයේ ස්ථානයේ සිට ඇඩැප්ටර ස්ථානයට පරිවර්තන තර්කනය අර්ථ දක්වන්න

  5. getBinderPosition
    ඇඩැප්ටර ස්ථානයේ සිට ඩේටාබයින්ඩර් හි ස්ථානයට පරිවර්තන තර්කනය අර්ථ දක්වන්න

මෙම විසඳුම ප්‍රයෝජනවත් වනු ඇතැයි අපි බලාපොරොත්තු වෙමු.
මම වඩාත් සවිස්තරාත්මක විසඳුම් සහ සාම්පල GitHub හි තැබුවෙමි, එබැවින් කරුණාකර ඔබට අවශ්‍ය නම් පහත සබැඳිය බලන්න.
https://github.com/yqritc/RecyclerView-MultipleViewTypesAdapter


4
ඔබගේ කේතය නිසා මම තරමක් ව්‍යාකූල වී සිටිමි, සමහර විට ඔබට මට උදව් කළ හැකිය, මගේ අදහස් ලැයිස්තුවේ ඇති තනතුරු අනුව නොව ඔවුන්ගේ දෘෂ්ටි කෝණයෙන් අර්ථ දැක්වීමට මා කැමති නැත. එය පෙනෙන්නේ ඔබේ කේතයේ අදහස් ඔවුන්ගේ ස්ථාන මත පදනම්ව තීරණය වන බවයි. එබැවින් 1 වන ස්ථානයේ නම්, දර්ශනය 1 දර්ශනය වේ, 3 වන ස්ථානය, 3 වන දර්ශනය දර්ශනය වන අතර අනෙක් සියල්ල ස්ථාන 2 හි දර්ශනය පෙන්වයි. මගේ අදහස් ස්ථාන මත නොව දර්ශන වර්ග මත පදනම් කිරීමට මට අවශ්‍ය නැත - එබැවින් දර්ශන වර්ගය රූප බව මා සඳහන් කරන්නේ නම්, එය රූපය පෙන්විය යුතුය. මට එය කළ හැක්කේ කෙසේද?
සයිමන්

කණගාටුයි, මට ඔබේ ප්‍රශ්නය සම්පූර්ණයෙන් වටහා ගත නොහැකි විය ..., නමුත් පිහිටීම සහ දෘෂ්ටි කෝණය බැඳීම සඳහා ඔබ කොතැනක හෝ තර්කනය ලිවිය යුතුය.
yqritc

1
මෙම කේතය ව්‍යාකූල නොවේ, මෙය ප්‍රතිචක්‍රීකරණ ඇඩැප්ටර රටාවකි, මෙය ප්‍රශ්නයේ නිවැරදි පිළිතුර මෙන් බැහැර කළ යුතුය. Qyqritc හි සබැඳිය අනුගමනය කරන්න, සොයා ගැනීමට මඳ වේලාවක් ගත කරන්න, ඔබට විවිධ වර්ගයේ පිරිසැලසුම් සහිත ප්‍රතිචක්‍රීකරණ දර්ශනය සඳහා පරිපූර්ණ රටාවක් ඇත.
ස්ටොයිකෝ ඇන්ඩ්‍රීව්

අළුත්, මෙහි public class DataBinder<T extends RecyclerView.ViewHolder>යමෙකුට හැඳින්විය හැකි දේ මට පැවසිය හැකිද <T someClass>, එබැවින් මට එම පදය ලැබුණහොත් ගූගල් කළ හැකිය. ද මම කියනවා, abstract public class DataBinder<T extends RecyclerView.ViewHolder>මෙම පන්තිය ආකාරයේ වන බවත් එසේ බව අදහස් ViewHolder, ඒ නිසා ප්රතිඵලය මෙම පන්තිය විහිදී ඇති සෑම පන්ති වර්ගයේ වනු ඇත viewHolderයන අදහස බව ද?
rgv

1
බහු අවයවිකතාව පිළිබඳ මගේ දැනුම නැවත නැවුම් කර ගැනීමට ඔබ මාව යොමු කළා .... ජාවා නරක නැහැ
පෝල් ඔකෙක්

40

පහත දැක්වෙන්නේ ව්‍යාජ කේතයක් නොවන අතර මම එය පරීක්ෂා කර ඇති අතර එය මට වැඩ කර ඇත.

මගේ ප්‍රතිචක්‍රීකරණ දර්ශනයේ ශීර්ෂ දර්ශනයක් නිර්මාණය කිරීමට අවශ්‍ය වූ අතර පසුව පරිශීලකයාට ක්ලික් කළ හැකි ශීර්ෂයට පහළින් පින්තූර ලැයිස්තුවක් ප්‍රදර්ශනය කිරීමට මට අවශ්‍ය විය.

මම මගේ කේතයේ ස්විච කිහිපයක් භාවිතා කළෙමි, මෙය කිරීමට වඩාත්ම කාර්යක්ෂම ක්‍රමය එය දැයි නොදනිමි, එබැවින් ඔබේ අදහස් දැක්වීමට නිදහස් වන්න:

   public class ViewHolder extends RecyclerView.ViewHolder{

        //These are the general elements in the RecyclerView
        public TextView place;
        public ImageView pics;

        //This is the Header on the Recycler (viewType = 0)
        public TextView name, description;

        //This constructor would switch what to findViewBy according to the type of viewType
        public ViewHolder(View v, int viewType) {
            super(v);
            if (viewType == 0) {
                name = (TextView) v.findViewById(R.id.name);
                decsription = (TextView) v.findViewById(R.id.description);
            } else if (viewType == 1) {
                place = (TextView) v.findViewById(R.id.place);
                pics = (ImageView) v.findViewById(R.id.pics);
            }
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent,
                                         int viewType)
    {
        View v;
        ViewHolder vh;
        // create a new view
        switch (viewType) {
            case 0: //This would be the header view in my Recycler
                v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerview_welcome, parent, false);
                vh = new ViewHolder(v,viewType);
                return  vh;
            default: //This would be the normal list with the pictures of the places in the world
                v = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.recyclerview_picture, parent, false);
                vh = new ViewHolder(v, viewType);
                v.setOnClickListener(new View.OnClickListener(){

                    @Override
                    public void onClick(View v) {
                        Intent intent = new Intent(mContext, nextActivity.class);
                        intent.putExtra("ListNo",mRecyclerView.getChildPosition(v));
                        mContext.startActivity(intent);
                    }
                });
                return vh;
        }
    }

    //Overriden so that I can display custom rows in the recyclerview
    @Override
    public int getItemViewType(int position) {
        int viewType = 1; //Default is 1
        if (position == 0) viewType = 0; //if zero, it will be a header view
        return viewType;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //position == 0 means its the info header view on the Recycler
        if (position == 0) {
            holder.name.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext,"name clicked", Toast.LENGTH_SHORT).show();
                }
            });
            holder.description.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext,"description clicked", Toast.LENGTH_SHORT).show();
                }
            });
            //this means it is beyond the headerview now as it is no longer 0. For testing purposes, I'm alternating between two pics for now
        } else if (position > 0) {
           holder.place.setText(mDataset[position]);
            if (position % 2 == 0) {
               holder.pics.setImageDrawable(mContext.getResources().getDrawable(R.drawable.pic1));
            }
            if (position % 2 == 1) {
                holder.pics.setImageDrawable(mContext.getResources().getDrawable(R.drawable.pic2));
            }

        }
    }

මෙය කදිමයි, මට ගතික ස්ථානවල බහු ශීර්ෂයන් අවශ්‍ය නම් කුමක් කළ යුතුද? වර්ග නිර්වචනය කරන ශීර්ෂයන් සහිත අයිතම ලැයිස්තුවක් කියන්න. ඔබේ විසඳුමට විශේෂ ශීර්ෂයන් කලින් තීරණය කළ int ස්ථානවල තිබිය යුතු බව පෙනේ.
බාසිනේටර්

22

ඔව්, හැකි ය.

සාමාන්‍ය දර්ශන දරන්නෙකු ලියන්න:

    public abstract class GenericViewHolder extends RecyclerView.ViewHolder
{
    public GenericViewHolder(View itemView) {
        super(itemView);
    }

    public abstract  void setDataOnView(int position);
}

ඉන්පසු ඔබේ දර්ශන දරන්නන් නිර්මාණය කර ඔවුන්ව GenericViewHolder දිගු කරන්න. උදාහරණයක් ලෙස, මෙය:

     public class SectionViewHolder extends GenericViewHolder{
    public final View mView;
    public final TextView dividerTxtV;

    public SectionViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
        dividerTxtV = (TextView) mView.findViewById(R.id.dividerTxtV);
    }

    @Override
    public void setDataOnView(int position) {
        try {
            String title= sections.get(position);
            if(title!= null)
                this.dividerTxtV.setText(title);
        }catch (Exception e){
            new CustomError("Error!"+e.getMessage(), null, false, null, e);
        }
    }
}

එවිට RecyclerView.Adapter පන්තිය මේ වගේ වනු ඇත:

public class MyClassRecyclerViewAdapter extends RecyclerView.Adapter<MyClassRecyclerViewAdapter.GenericViewHolder> {

@Override
public int getItemViewType(int position) {
     // depends on your problem
     switch (position) {
         case : return VIEW_TYPE1;
         case : return VIEW_TYPE2;
         ...
     }
}

    @Override
   public GenericViewHolder onCreateViewHolder(ViewGroup parent, int viewType)  {
    View view;
    if(viewType == VIEW_TYPE1){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout1, parent, false);
        return new SectionViewHolder(view);
    }else if( viewType == VIEW_TYPE2){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout2, parent, false);
        return new OtherViewHolder(view);
    }
    // Cont. other view holders ...
    return null;
   }

@Override
public void onBindViewHolder(GenericViewHolder holder, int position) {
    holder.setDataOnView(position);
}

1
ක්‍රියාකාරකමකදී භාවිතා කරන්නේ කෙසේද? වර්ගය ක්‍රමවේදය හරහා සම්මත කළ යුතුද?
skm

1
ක්‍රියාකාරකමේදී මෙම ඇඩැප්ටරය භාවිතා කරන්නේ කෙසේද? ලැයිස්තුවේ ඇති වර්ගය
කුමක්දැයි

20

විවිධ පිරිසැලසුම් සඳහා විවිධ ViewHolder සාදන්න

රූප විස්තරය මෙහි ඇතුළත් කරන්න
ප්‍රතිචක්‍රීකරණ දර්ශනයට ඔබට අවශ්‍ය ඕනෑම නරඹන්නන් සංඛ්‍යාවක් සිටිය හැකි නමුත් වඩා හොඳ කියවීමේ හැකියාව සඳහා ViewHolders දෙකක් සමඟ එකක් නිර්මාණය කරන්නේ කෙසේදැයි බැලීමට ඉඩ දෙයි.

එය සරල පියවර තුනකින් කළ හැකිය

  1. අභිබවා යන්න public int getItemViewType(int position)
  2. In ViewType මත පදනම්ව විවිධ ViewHolders නැවත ලබා දෙන්න onCreateViewHolder() ක්‍රමය
  3. අයිතමය දර්ශන ටයිප් onBindViewHolder()ක්‍රමය මත පදනම්ව ජනගහනය බලන්න

මෙන්න කුඩා කේත ස්නිපටයක්

public class YourListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

   private static final int LAYOUT_ONE= 0;
   private static final int LAYOUT_TWO= 1;

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

   @Override
   public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

      View view =null;
      RecyclerView.ViewHolder viewHolder = null;

      if(viewType==LAYOUT_ONE)
      {
          view = LayoutInflater.from(parent.getContext()).inflate(R.layout.one,parent,false);
          viewHolder = new ViewHolderOne(view);
      }
      else
      {
          view = LayoutInflater.from(parent.getContext()).inflate(R.layout.two,parent,false);
          viewHolder= new ViewHolderTwo(view);
      }

      return viewHolder;
   }

   @Override
   public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

      if(holder.getItemViewType()== LAYOUT_ONE)
      {
            // Typecast Viewholder 
            // Set Viewholder properties 
            // Add any click listener if any 
      }
      else {

        ViewHolderOne vaultItemHolder = (ViewHolderOne) holder;
        vaultItemHolder.name.setText(displayText);
        vaultItemHolder.name.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
            .......
           }
         });

       }

   }

  //****************  VIEW HOLDER 1 ******************//

   public class ViewHolderOne extends RecyclerView.ViewHolder {

      public TextView name;

      public ViewHolderOne(View itemView) {
         super(itemView);
         name = (TextView)itemView.findViewById(R.id.displayName);
     }
   }


   //****************  VIEW HOLDER 2 ******************//

   public class ViewHolderTwo extends RecyclerView.ViewHolder{

      public ViewHolderTwo(View itemView) {
         super(itemView);

        ..... Do something
      }
   }
}

getItemViewType (int position) යතුරයි

මගේ මතය අනුව, මේ ආකාරයේ ප්‍රතිචක්‍රීකරණ දර්ශනයක් නිර්මාණය කිරීමේ ආරම්භක ලක්ෂ්‍යය මෙම ක්‍රමවේදය පිළිබඳ දැනුමයි. මෙම ක්‍රමය අභිබවා යාමට විකල්පයක් බැවින් එය පෙරනිමියෙන් ප්‍රතිචක්‍රීකරණ දර්ශන පන්තියේ නොපෙනෙන අතර එමඟින් බොහෝ සංවර්ධකයින් (මා ද ඇතුළුව) ආරම්භ කළ යුත්තේ කොතැනින්දැයි කල්පනා කරයි. මෙම ක්‍රමය පවතින බව ඔබ දැනගත් පසු, එවැනි ප්‍රතිචක්‍රීකරණ දර්ශනයක් නිර්මාණය කිරීම කේක් එකක් වනු ඇත.

මගේ අදහස ඔප්පු කිරීමට එක් උදාහරණයක් බලමු. ඔබට විකල්ප ස්ථාන දෙකක පිරිසැලසුමක් පෙන්වීමට අවශ්‍ය නම් මෙය කරන්න

@Override
public int getItemViewType(int position)
{
   if(position%2==0)       // Even position 
     return LAYOUT_ONE;
   else                   // Odd position 
     return LAYOUT_TWO;
}

අදාළ සබැඳි:

මා මෙය ක්‍රියාත්මක කළ ව්‍යාපෘතිය බලන්න


15

ඔව්, හැකි ය. ඔබේ ඇඩැප්ටරයේ getItemViewType පිරිසැලසුම මේ ආකාරයට ....

  public class MultiViewTypeAdapter extends RecyclerView.Adapter {

        private ArrayList<Model>dataSet;
        Context mContext;
        int total_types;
        MediaPlayer mPlayer;
        private boolean fabStateVolume = false;

        public static class TextTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            CardView cardView;

            public TextTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.cardView = (CardView) itemView.findViewById(R.id.card_view);
            }
        }

        public static class ImageTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            ImageView image;

            public ImageTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.image = (ImageView) itemView.findViewById(R.id.background);
            }
        }

        public static class AudioTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            FloatingActionButton fab;

            public AudioTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.fab = (FloatingActionButton) itemView.findViewById(R.id.fab);
            }
        }

        public MultiViewTypeAdapter(ArrayList<Model>data, Context context) {
            this.dataSet = data;
            this.mContext = context;
            total_types = dataSet.size();
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

            View view;
            switch (viewType) {
                case Model.TEXT_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_type, parent, false);
                    return new TextTypeViewHolder(view);
                case Model.IMAGE_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_type, parent, false);
                    return new ImageTypeViewHolder(view);
                case Model.AUDIO_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.audio_type, parent, false);
                    return new AudioTypeViewHolder(view);
            }
            return null;
        }

        @Override
        public int getItemViewType(int position) {

            switch (dataSet.get(position).type) {
                case 0:
                    return Model.TEXT_TYPE;
                case 1:
                    return Model.IMAGE_TYPE;
                case 2:
                    return Model.AUDIO_TYPE;
                default:
                    return -1;
            }
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int listPosition) {

            Model object = dataSet.get(listPosition);
            if (object != null) {
                switch (object.type) {
                    case Model.TEXT_TYPE:
                        ((TextTypeViewHolder) holder).txtType.setText(object.text);

                        break;
                    case Model.IMAGE_TYPE:
                        ((ImageTypeViewHolder) holder).txtType.setText(object.text);
                        ((ImageTypeViewHolder) holder).image.setImageResource(object.data);
                        break;
                    case Model.AUDIO_TYPE:

                        ((AudioTypeViewHolder) holder).txtType.setText(object.text);

                }
            }
        }

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

යොමු සබැඳිය සඳහා: https://www.journaldev.com/12372/android-recyclerview-example


මෙම ස්නිපටය අනුකරණය කිරීම සඳහා මම මගේ කේතය නැවත ආකෘතිකරණය කළ අතර එය දැන් හොඳින් ක්‍රියාත්මක වේ. මට තිබූ ගැටළුව වූයේ වත්මන් පිටුවෙන් ඔබ්බට ස්වයිප් කිරීමෙන් එය බිඳ වැටීමයි. තව දුරටත් බිඳ වැටෙන්න එපා! විශිෂ්ට ආකෘතිය ,. ඔබට ස්තුතියි . හොඳට කලා.
user462990

මම මෙය දකින තුරු දින ගණනක් ප්‍රයෝජනවත් කිසිවක් සොයාගත නොහැකි විය, ස්තූතියි!
ඉටේ බ්‍රහ්

7

ඇන්ටන්ගේ විසඳුම අනුගමනය කරමින්, ViewHolderවිවිධ වර්ගයේ පිරිසැලසුම් ඇති / හසුරුවන / පවරන මෙය ඉදිරිපත් කරන්න. ප්‍රතිචක්‍රීකරණ දසුන ViewHolderදත්ත රෝල් කරන ආකාරයේ නොවන විට නව පිරිසැලසුම ප්‍රතිස්ථාපනය කිරීම සාර්ථක වේදැයි විශ්වාස නැත.

එබැවින් මූලික වශයෙන්, onCreateViewHolder(ViewGroup parent, int viewType)හැඳින්වෙන්නේ නව දර්ශන පිරිසැලසුම අවශ්‍ය වූ විට පමණි;

getItemViewType(int position)සඳහා කැඳවනු ලැබේ viewType;

onBindViewHolder(ViewHolder holder, int position)දර්ශනය ප්‍රතිචක්‍රීකරණය කිරීමේදී සැමවිටම හැඳින්වේ (නව දත්ත ගෙන එනු ලබන අතර එය ප්‍රදර්ශනය කිරීමට උත්සාහ කරන්න ViewHolder).

එබැවින් onBindViewHolderඑය හැඳින්වූ විට නිවැරදි දර්ශන පිරිසැලසුම තබා යාවත්කාලීන කළ ViewHolderයුතුය.

ඒ සඳහා දර්ශන පිරිසැලසුම ප්‍රතිස්ථාපනය කිරීමේ ක්‍රමය නිවැරදි ද? ViewHolder ගෙන ඒම , නැතහොත් කිසියම් ගැටළුවක් තිබේද? ඕනෑම අදහසක් අගය කරන්න!

public int getItemViewType(int position) {
    TypedData data = mDataSource.get(position);
    return data.type;
}

public ViewHolder onCreateViewHolder(ViewGroup parent, 
    int viewType) {
    return ViewHolder.makeViewHolder(parent, viewType);
}

public void onBindViewHolder(ViewHolder holder, 
    int position) {
    TypedData data = mDataSource.get(position);
    holder.updateData(data);
}

///
public static class ViewHolder extends 
    RecyclerView.ViewHolder {

    ViewGroup mParentViewGroup;
    View mCurrentViewThisViewHolderIsFor;
    int mDataType;

    public TypeOneViewHolder mTypeOneViewHolder;
    public TypeTwoViewHolder mTypeTwoViewHolder;

    static ViewHolder makeViewHolder(ViewGroup vwGrp, 
        int dataType) {
        View v = getLayoutView(vwGrp, dataType);
        return new ViewHolder(vwGrp, v, viewType);
    }

    static View getLayoutView(ViewGroup vwGrp, 
        int dataType) {
        int layoutId = getLayoutId(dataType);
        return LayoutInflater.from(vwGrp.getContext())
                             .inflate(layoutId, null);
    }

    static int getLayoutId(int dataType) {
        if (dataType == TYPE_ONE) {
            return R.layout.type_one_layout;
        } else if (dataType == TYPE_TWO) {
            return R.layout.type_two_layout;
        }
    }

    public ViewHolder(ViewGroup vwGrp, View v, 
        int dataType) {
        super(v);
        mDataType = dataType;
        mParentViewGroup = vwGrp;
        mCurrentViewThisViewHolderIsFor = v;

        if (data.type == TYPE_ONE) {
            mTypeOneViewHolder = new TypeOneViewHolder(v);
        } else if (data.type == TYPE_TWO) {
            mTypeTwoViewHolder = new TypeTwoViewHolder(v);
        }
    }

    public void updateData(TypeData data) {
        mDataType = data.type;
        if (data.type == TYPE_ONE) {
            mTypeTwoViewHolder = null;
            if (mTypeOneViewHolder == null) {
                View newView = getLayoutView(mParentViewGroup,
                               data.type);

                /**
                 *  how to replace new view with 
                    the view in the parent 
                    view container ???
                 */
                replaceView(mCurrentViewThisViewHolderIsFor, 
                            newView);
                mCurrentViewThisViewHolderIsFor = newView;

                mTypeOneViewHolder = 
                    new TypeOneViewHolder(newView);
            }
            mTypeOneViewHolder.updateDataTypeOne(data);

        } else if (data.type == TYPE_TWO){
            mTypeOneViewHolder = null;
            if (mTypeTwoViewHolder == null) {
                View newView = getLayoutView(mParentViewGroup, 
                               data.type);

                /**
                 *  how to replace new view with 
                    the view in the parent view 
                    container ???
                 */
                replaceView(mCurrentViewThisViewHolderIsFor, 
                            newView);
                mCurrentViewThisViewHolderIsFor = newView;

                mTypeTwoViewHolder = 
                    new TypeTwoViewHolder(newView);
            }
            mTypeTwoViewHolder.updateDataTypeOne(data);
        }
    }
}

public static void replaceView(View currentView, 
    View newView) {
    ViewGroup parent = (ViewGroup)currentView.getParent();
    if(parent == null) {
        return;
    }
    final int index = parent.indexOfChild(currentView);
    parent.removeView(currentView);
    parent.addView(newView, index);
}

සංස්කරණය කරන්න: දර්ශනය රඳවා තබා ගැනීමට ViewHolder හි සාමාජික mItemViewType ඇත

සංස්කරණය කරන්න: onBindViewHolder (ViewHolder holder, int position) හි ඇති ආකාරයට පෙනේ. වර්ගය දත්ත [පිහිටුම] වර්ගයට නොගැලපේ. OnBindViewHolder () හි ඇති ViewHolder එක ලබා ගන්නේ කෙසේදැයි යමෙක් වැඩි යමක් දන්නවාද?

සංස්කරණය කරන්න: ප්‍රතිචක්‍රීකරණය ViewHolderවර්ගය අනුව තෝරාගෙන ඇති බව පෙනේ , එබැවින් එහි රණශූරයෙක් නැත.

සංස්කරණය කරන්න: http://wiresareobsolete.com/2014/09/building-a-recyclerview-layoutmanager-part-1/ මෙම ප්‍රශ්නයට පිළිතුරු සපයයි.

එයට ප්‍රතිචක්‍රීකරණය ලැබෙන්නේ ViewHolder:

holder = getRecycledViewPool().getRecycledView(mAdapter.getItemViewType(offsetPosition));

ViewHolderනිවැරදි වර්ගයේ ප්‍රතිචක්‍රීකරණය සොයාගත නොහැකි නම් නව එකක් සාදන්න .

public ViewHolder getRecycledView(int viewType) {
        final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
        if (scrapHeap != null && !scrapHeap.isEmpty()) {
            final int index = scrapHeap.size() - 1;
            final ViewHolder scrap = scrapHeap.get(index);
            scrapHeap.remove(index);
            return scrap;
        }
        return null;
    }

View getViewForPosition(int position, boolean dryRun) {
    ......

    if (holder == null) {
            final int offsetPosition = mAdapterHelper.findPositionOffset(position);
            if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
                        + "position " + position + "(offset:" + offsetPosition + ")."
                        + "state:" + mState.getItemCount());
            }

            final int type = mAdapter.getItemViewType(offsetPosition);
            // 2) Find from scrap via stable ids, if exists
            if (mAdapter.hasStableIds()) {
                holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
                if (holder != null) {
                    // update position
                    holder.mPosition = offsetPosition;
                    fromScrap = true;
                }
            }
            if (holder == null && mViewCacheExtension != null) {
                // We are NOT sending the offsetPosition because LayoutManager does not
                // know it.
                final View view = mViewCacheExtension
                        .getViewForPositionAndType(this, position, type);
                if (view != null) {
                    holder = getChildViewHolder(view);
                    if (holder == null) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned"
                                + " a view which does not have a ViewHolder");
                    } else if (holder.shouldIgnore()) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned"
                                + " a view that is ignored. You must call stopIgnoring before"
                                + " returning this view.");
                    }
                }
            }
            if (holder == null) { // fallback to recycler
                // try recycler.
                // Head to the shared pool.
                if (DEBUG) {
                    Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared "
                            + "pool");
                }
                holder = getRecycledViewPool()
                        .getRecycledView(mAdapter.getItemViewType(offsetPosition));
                if (holder != null) {
                    holder.resetInternal();
                    if (FORCE_INVALIDATE_DISPLAY_LIST) {
                        invalidateDisplayListInt(holder);
                    }
                }
            }
            if (holder == null) {
                holder = mAdapter.createViewHolder(RecyclerView.this,
                        mAdapter.getItemViewType(offsetPosition));
                if (DEBUG) {
                    Log.d(TAG, "getViewForPosition created new ViewHolder");
                }
            }
        }
        boolean bound = false;
        if (mState.isPreLayout() && holder.isBound()) {
            // do not update unless we absolutely have to.
            holder.mPreLayoutPosition = position;
        } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
            if (DEBUG && holder.isRemoved()) {
                throw new IllegalStateException("Removed holder should be bound and it should"
                        + " come here only in pre-layout. Holder: " + holder);
            }
            final int offsetPosition = mAdapterHelper.findPositionOffset(position);
            mAdapter.bindViewHolder(holder, offsetPosition);
            attachAccessibilityDelegate(holder.itemView);
            bound = true;
            if (mState.isPreLayout()) {
                holder.mPreLayoutPosition = position;
            }
        }

        final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        final LayoutParams rvLayoutParams;
        if (lp == null) {
            rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
            holder.itemView.setLayoutParams(rvLayoutParams);
        } else if (!checkLayoutParams(lp)) {
            rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
            holder.itemView.setLayoutParams(rvLayoutParams);
        } else {
            rvLayoutParams = (LayoutParams) lp;
        }
        rvLayoutParams.mViewHolder = holder;
        rvLayoutParams.mPendingInvalidate = fromScrap && bound;
        return holder.itemView;
}

6

මට වඩා හොඳ විසඳුමක් ඇත, එමඟින් ප්‍රකාශන සහ ආරක්ෂිත ආකාරයකින් බහුවිධ දර්ශන වර්ග නිර්මාණය කිරීමට ඉඩ ලබා දේ. එය කොට්ලින් හි ලියා ඇති අතර එය btw ඇත්තෙන්ම හොඳයි.

අවශ්‍ය සියලුම දර්ශන වර්ග සඳහා සරල දර්ශන දරන්නන්

class ViewHolderMedium(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val icon: ImageView = itemView.findViewById(R.id.icon) as ImageView
    val label: TextView = itemView.findViewById(R.id.label) as TextView
}

ඇඩැප්ටර දත්ත අයිතමයේ සාරාංශයක් ඇත. දර්ශන වර්ගයක් විශේෂිත දර්ශන දරන්නන්ගේ පන්තියේ හැෂ් කේතයක් මගින් නිරූපණය වන බව සලකන්න (කොට්ලින්හි KClass)

trait AdapterItem {
   val viewType: Int
   fun bindViewHolder(viewHolder: RecyclerView.ViewHolder)
}

abstract class AdapterItemBase<T>(val viewHolderClass: KClass<T>) : AdapterItem {
   override val viewType: Int = viewHolderClass.hashCode()  
   abstract fun bindViewHolder(viewHolder: T)
   override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
       bindViewHolder(viewHolder as T)
   }
}

එකම bindViewHolderකොන්ක්රීට් ඇඩප්ටරය අයිතමය පන්ති overriden කළ යුතුය (ආරක්ෂිත ක්රමයක් ටයිප්)

class AdapterItemMedium(val icon: Drawable, val label: String, val onClick: () -> Unit) : AdapterItemBase<ViewHolderMedium>(ViewHolderMedium::class) {
    override fun bindViewHolder(viewHolder: ViewHolderMedium) {
        viewHolder.icon.setImageDrawable(icon)
        viewHolder.label.setText(label)
        viewHolder.itemView.setOnClickListener { onClick() }
    }
}

එවැනි AdapterItemMediumවස්තූන් ලැයිස්තුව ඇත්ත වශයෙන්ම පිළිගන්නා ඇඩැප්ටරය සඳහා දත්ත ප්‍රභවයකිList<AdapterItem> .

මෙම විසඳුමේ වැදගත් අංගයක් වන්නේ දර්ශන දරන්නාගේ කර්මාන්ත ශාලාවක් වන අතර එමඟින් විශේෂිත ViewHolder හි නැවුම් අවස්ථා ලබා දෙනු ඇත

class ViewHolderProvider {
    private val viewHolderFactories = hashMapOf<Int, Pair<Int, Any>>()

    fun provideViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val (layoutId: Int, f: Any) = viewHolderFactories.get(viewType)
        val viewHolderFactory = f as (View) -> RecyclerView.ViewHolder
        val view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutId, viewGroup, false)
        return viewHolderFactory(view)
    }

    fun registerViewHolderFactory<T>(key: KClass<T>, layoutId: Int, viewHolderFactory: (View) -> T) {
        viewHolderFactories.put(key.hashCode(), Pair(layoutId, viewHolderFactory))
    }
}

සරල ඇඩැප්ටර පන්තිය මේ වගේ ය

public class MultitypeAdapter(val items: List<AdapterItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

   val viewHolderProvider = ViewHolderProvider() // inject ex Dagger2

   init {
        viewHolderProvider!!.registerViewHolderFactory(ViewHolderMedium::class, R.layout.item_medium, { itemView ->
            ViewHolderMedium(itemView)
        })
   }

   override fun getItemViewType(position: Int): Int {
        return items[position].viewType
    }

    override fun getItemCount(): Int {
        return items.size()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
        return viewHolderProvider!!.provideViewHolder(viewGroup, viewType)
    }

    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
        items[position].bindViewHolder(viewHolder)     
    }
}

නව දර්ශන වර්ගයක් නිර්මාණය කිරීමට පියවර 3 ක් පමණි:

  1. දර්ශන දරන්නා පන්තියක් සාදන්න
  2. ඇඩැප්ටර අයිතම පන්තියක් සාදන්න (ඇඩැප්ටර් අයිටම් බේස් වෙතින් විහිදේ)
  3. දර්ශන දරන්නාගේ පන්තිය ලියාපදිංචි කරන්න ViewHolderProvider

මෙන්න මෙම සංකල්පයට උදාහරණයක්: ඇන්ඩ්‍රොයිඩ්-ලාච්චු-අච්චුව එය තව දුරටත් ඉදිරියට යයි - දඟ පන්දු යවන අංගයක් ලෙස ක්‍රියා කරන දර්ශන වර්ගය, තෝරා ගත හැකි ඇඩැප්ටර අයිතම.


6

එය ඉතා සරල හා කෙළින්ම ඉදිරියට ය.

යන්තම් ඉක්මවා යන්න getItemViewType () ඔබේ අවශ්යතාවයට පාලන ක්රමය. දත්ත මත පදනම්ව විවිධ අයිතම දර්ශන දර්ශන අගයන් ලබා දේ. උදා: සාමාජිකයෙකු වන පුද්ගලයකු වැනි වස්තුවක් සලකා බලන්න, isMale සත්‍ය නම්, 1 ආපසු සහ isMale අසත්‍ය නම්, getItemViewType () හි 2 ආපසු එවන්න. ක්‍රමයට .

දැන් createViewHolder (ViewGroup parent, int viewType) වෙත පැමිණේ , විවිධ viewType yon මඟින් විවිධ පිරිසැලසුම් ගොනුව උඩුගත කළ හැකිය. පහත සඳහන් පරිදි

 if (viewType ==1){
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.male,parent,false);
    return new AdapterMaleViewHolder(view);
}
else{
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.female,parent,false);
    return new AdapterFemaleViewHolder(view);
}

දී onBindViewHolder (VH යනු හිමිකරු, int තත්ත්වය) හිමියා උදාහරණයක් කොහෙද චෙක්පත AdapterFemaleViewHolderහෝ AdapterMaleViewHolderවිසින් instanceofහා ඒ අනුව එම අගයන් ලබා දිය.

ViewHolder මේ වගේ විය හැකිය

    class AdapterMaleViewHolder extends RecyclerView.ViewHolder {
            ...
            public AdapterMaleViewHolder(View itemView){
            ...
            }
        }

    class AdapterFemaleViewHolder extends RecyclerView.ViewHolder {
         ...
         public AdapterFemaleViewHolder(View itemView){
            ...
         }
    }

5

තෝරාගත් පිළිතුර නිවැරදි වුවද, මට එය තවදුරටත් විස්තර කිරීමට අවශ්‍යය. ප්‍රතිචක්‍රීකරණ දර්ශනයේ බහු දර්ශන වර්ග සඳහා ප්‍රයෝජනවත් අභිරුචි ඇඩැප්ටරයක් මට මෙහි හමු විය . එහි කෝට්ලින් අනුවාදය මෙහි ඇත ඇත.

අභිරුචි ඇඩැප්ටරය අනුගමනය කරයි

public class CustomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
ArrayList<String> list; // ArrayList of your Data Model
final int VIEW_TYPE_ONE = 1;
final int VIEW_TYPE_TWO = 2;

public CustomAdapter(Context context, ArrayList<String> list) { // you can pass other parameters in constructor
    this.context = context;
    this.list = list;
}

private class ViewHolder1 extends RecyclerView.ViewHolder {

    TextView yourView;
    ViewHolder1(final View itemView) {
        super(itemView);
        yourView = itemView.findViewById(R.id.yourView); // Initialize your All views prensent in list items
    }
    void bind(int position) {
        // This method will be called anytime a list item is created or update its data
        //Do your stuff here
        yourView.setText(list.get(position));
    }
}

private class ViewHolder2 extends RecyclerView.ViewHolder {

    TextView yourView;
    ViewHolder2(final View itemView) {
        super(itemView);
        yourView = itemView.findViewById(R.id.yourView); // Initialize your All views prensent in list items
    }
    void bind(int position) {
        // This method will be called anytime a list item is created or update its data
        //Do your stuff here
        yourView.setText(list.get(position));
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
   if (viewType == VIEW_TYPE_ONE) {
       return new ViewHolder1(LayoutInflater.from(context).inflate(R.layout.your_list_item_1, parent, false));
   }
   //if its not VIEW_TYPE_ONE then its VIEW_TYPE_TWO
   return new ViewHolder2(LayoutInflater.from(context).inflate(R.layout.your_list_item_2, parent, false));

}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (list.get(position).type == Something) { // put your condition, according to your requirements
        ((ViewHolder1) holder).bind(position);
    } else {
        ((ViewHolder2) holder).bind(position);
    }

}

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

@Override
public int getItemViewType(int position) {
    // here you can get decide from your model's ArrayList, which type of view you need to load. Like
    if (list.get(position).type == Something) { // put your condition, according to your requirements
        return VIEW_TYPE_ONE;
    }
    return VIEW_TYPE_TWO;
}
}

3

මම මෙම පුස්තකාලය නිර්දේශ කරන්නේ හැන්ස් ඩෝර්ෆ්මන්ගෙනි. එය විශේෂිත දර්ශන වර්ගයට අදාළ සියලු තර්කනයන් "ඇඩැප්ටර් ඩෙලිගේට්" නමින් වෙනම වස්තුවක සංයුක්ත කරයි. https://github.com/sockeqwe/AdapterDelegates

public class CatAdapterDelegate extends AdapterDelegate<List<Animal>> {

  private LayoutInflater inflater;

  public CatAdapterDelegate(Activity activity) {
    inflater = activity.getLayoutInflater();
  }

  @Override public boolean isForViewType(@NonNull List<Animal> items, int position) {
    return items.get(position) instanceof Cat;
  }

  @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
    return new CatViewHolder(inflater.inflate(R.layout.item_cat, parent, false));
  }

  @Override public void onBindViewHolder(@NonNull List<Animal> items, int position,
      @NonNull RecyclerView.ViewHolder holder, @Nullable List<Object> payloads) {

    CatViewHolder vh = (CatViewHolder) holder;
    Cat cat = (Cat) items.get(position);

    vh.name.setText(cat.getName());
  }

  static class CatViewHolder extends RecyclerView.ViewHolder {

    public TextView name;

    public CatViewHolder(View itemView) {
      super(itemView);
      name = (TextView) itemView.findViewById(R.id.name);
    }
  }
}

public class AnimalAdapter extends ListDelegationAdapter<List<Animal>> {

  public AnimalAdapter(Activity activity, List<Animal> items) {

    // DelegatesManager is a protected Field in ListDelegationAdapter
    delegatesManager.addDelegate(new CatAdapterDelegate(activity))
                    .addDelegate(new DogAdapterDelegate(activity))
                    .addDelegate(new GeckoAdapterDelegate(activity))
                    .addDelegate(23, new SnakeAdapterDelegate(activity));

    // Set the items from super class.
    setItems(items);
  }
}

1

ඇත්තටම, මම කැමතියි ඇන්ටන්ගේ පිළිතුර වැඩිදියුණු කරන්න .

getItemViewType(int position)පූර්ණ සංඛ්‍යාවක් ලබා දෙන බැවින් , ඔබට උද්ධමනය කිරීමට අවශ්‍ය පිරිසැලසුම් සම්පත් හැඳුනුම්පත ආපසු ලබා දිය හැකිය. ඒ ආකාරයෙන් ඔබ යම් තර්කනයක් ඉතිරි කරයිonCreateViewHolder(ViewGroup parent, int viewType) ක්‍රමයෙන් .

getItemCount()ලැයිස්තුව විදැහුම් කිරීමේදී මෙන්ම දෘශ්‍යමාන අයිතම වලින් ඔබ්බට එක් එක් අයිතමය විදැහුම් කිරීමේදී එම විශේෂිත ශ්‍රිතය අවම වශයෙන් 5 වතාවක් කැඳවනු ලබන බැවින් දැඩි ගණනය කිරීම් කිරීමට මම යෝජනා නොකරමි . කනගාටුවට කරුණ නම් notifyDatasetChanged()ක්‍රමය අවසාන බැවින් ඔබට එය අභිබවා යා නොහැක, නමුත් ඇඩැප්ටරය තුළ ඇති වෙනත් ශ්‍රිතයකින් ඔබට එය ඇමතිය හැකිය.


3
ඔව්, එය ක්‍රියාත්මක විය හැකි නමුත් අනෙක් සංවර්ධකයින් ව්‍යාකූල කරයි. ප්‍රලේඛනයෙන් ද Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.වැඩි කේතයක් ලිවීම වඩා හොඳ වන අතර හක්ක භාවිතා නොකරන්න.
අයෝන් ෂර්වාඩ්සේ

1
මම එකඟයි. ඒ කාලේ මට ඒ විශේෂ වගන්තිය මග හැරුණා.
ඩ්‍රැගස්

1
විහිළුවක් ද RecyclerView.Adapter නිසා එහේ බෙහෙත් තිබුනේ: මෙහි getItemViewType () ලේඛන developer.android.com/reference/android/support/v7/widget/... Dragas ඔබ "අද්විතීය ලෙස අයිතමය දැක්ම වර්ග හඳුනා ගැනීම සඳහා id සම්පත් භාවිතා කිරීම සලකා බලන්න යුතු බව පල දේ යෝජනා කරමු. " getViewTypeCount () සඳහා අවශ්‍යතාවය නොසලකා හැර ඇති බවක් පෙනෙන්නට තිබේ
ඩීමෝ

1

ඔබට පුස්තකාලය භාවිතා කළ හැකිය: https://github.com/vivchar/RendererRecyclerViewAdapter

mRecyclerViewAdapter = new RendererRecyclerViewAdapter(); /* included from library */
mRecyclerViewAdapter.registerRenderer(new SomeViewRenderer(SomeModel.TYPE, this));
mRecyclerViewAdapter.registerRenderer(...); /* you can use several types of cells */

`

සෑම අයිතමයක් සඳහාම, ඔබ ViewRenderer, ViewHolder, SomeModel ක්‍රියාත්මක කළ යුතුය:

ViewHolder - එය ප්‍රතිචක්‍රීකරණ දසුනෙහි සරල දර්ශන දරන්නෙකි.

SomeModel - එය ItemModelඅතුරු මුහුණත සහිත ඔබේ ආකෘතියයි

public class SomeViewRenderer extends ViewRenderer<SomeModel, SomeViewHolder> {

  public SomeViewRenderer(final int type, final Context context) {
    super(type, context);
  }
  @Override
 public void bindView(@NonNull final SomeModel model, @NonNull final SomeViewHolder holder) {
    holder.mTitle.setText(model.getTitle());
 }
 @NonNull
 @Override
 public SomeViewHolder createViewHolder(@Nullable final ViewGroup parent) {
    return new SomeViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.some_item, parent, false));
 }
}

වැඩි විස්තර සඳහා ඔබට ලේඛන සොයා ගත හැකිය.


1

කෝට්ලින් සමඟ දර්ශන වර්ග ක්‍රියාත්මක කිරීම පහසු වේ, මෙන්න මෙම සැහැල්ලු පුස්තකාලය සමඟ නියැදියක් https://github.com/Link184/KidAdapter

recyclerView.setUp {
    withViewType {
        withLayoutResId(R.layout.item_int)
        withItems(mutableListOf(1, 2, 3, 4, 5, 6))
        bind<Int> { // this - is adapter view hoder itemView, it - current item
            intName.text = it.toString()
        }
    }


    withViewType("SECOND_STRING_TAG") {
        withLayoutResId(R.layout.item_text)
        withItems(mutableListOf("eight", "nine", "ten", "eleven", "twelve"))
        bind<String> {
            stringName.text = it
        }
    }
}

1

ඔබ multipleViewTypes කටයුතු කළ හැකි RecyclerAdapterබවට විසින් getItemViewType()අපේක්ෂිත ප්රතිලාභviewType ඒ තනතුරට අගය

මම සූදානම් කළා MultipleViewTypeAdapterවිභාග සඳහා MCQ ලැයිස්තුවක් සෑදීම සඳහා එමඟින් වලංගු පිළිතුරු 2 ක් හෝ වැඩි ගණනක් (පිරික්සුම් කොටු විකල්ප) සහ තනි පිළිතුරු ප්‍රශ්න (රේඩියෝබටන් විකල්ප) ඇති විය හැකිය.

මේ සඳහා මම API ප්‍රතිචාරයෙන් ප්‍රශ්න වර්ගය ලබා ගන්නා අතර එම ප්‍රශ්නය සඳහා මා පෙන්විය යුත්තේ කුමන දෘෂ්ටියද යන්න තීරණය කිරීම සඳහා මම එය භාවිතා කළෙමි.

public class MultiViewTypeAdapter extends RecyclerView.Adapter {

    Context mContext;
    ArrayList<Question> dataSet;
    ArrayList<String> questions;
    private Object radiobuttontype1; 


    //Viewholder to display Questions with checkboxes
    public static class Checkboxtype2 extends RecyclerView.ViewHolder {
        ImageView imgclockcheck;
        CheckBox checkbox;

        public Checkboxtype2(@NonNull View itemView) {
            super(itemView);
            imgclockcheck = (ImageView) itemView.findViewById(R.id.clockout_cbox_image);
            checkbox = (CheckBox) itemView.findViewById(R.id.clockout_cbox);


        }
    }

        //Viewholder to display Questions with radiobuttons

    public static class Radiobuttontype1 extends RecyclerView.ViewHolder {
        ImageView clockout_imageradiobutton;
        RadioButton clockout_radiobutton;
        TextView sample;

        public radiobuttontype1(View itemView) {
            super(itemView);
            clockout_imageradiobutton = (ImageView) itemView.findViewById(R.id.clockout_imageradiobutton);
            clockout_radiobutton = (RadioButton) itemView.findViewById(R.id.clockout_radiobutton);
            sample = (TextView) itemView.findViewById(R.id.sample);
        }
    }

    public MultiViewTypeAdapter(ArrayList<QueDatum> data, Context context) {
        this.dataSet = data;
        this.mContext = context;

    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {

        if (viewType.equalsIgnoreCase("1")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("2")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_cbox_list_row, viewGroup, false);
            view.setHorizontalFadingEdgeEnabled(true);
            return new Checkboxtype2(view);

        } else if (viewType.equalsIgnoreCase("3")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("4")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("5")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);
        }


        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int viewType) {
        if (viewType.equalsIgnoreCase("1")) {
            options =  dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            ((radiobuttontype1) viewHolder).clockout_radiobutton.setChecked(false);
            ((radiobuttontype1) viewHolder).sample.setText(question);
            //loading image bitmap in the ViewHolder's View
            Picasso.with(mContext)
                    .load(image)
                    .into(((radiobuttontype1) viewHolder).clockout_imageradiobutton);

        } else if (viewType.equalsIgnoreCase("2")) {
            options = (ArrayList<Clockout_questions_Option>) dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            //loading image bitmap in the ViewHolder's View
            Picasso.with(mContext)
                    .load(image)
                    .into(((Checkboxtype2) viewHolder).imgclockcheck);

        } else if (viewType.equalsIgnoreCase("3")) {
                //fit data to viewHolder for ViewType 3
        } else if (viewType.equalsIgnoreCase("4")) {
//fit data to viewHolder for ViewType 4   
        } else if (viewType.equalsIgnoreCase("5")) {
//fit data to viewHolder for ViewType 5     
        }
    }

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

    /**
     * returns viewType for that position by picking the viewType value from the 
     *     dataset
     */
    @Override
    public int getItemViewType(int position) {
        return dataSet.get(position).getViewType();

    }


}

onBindViewHolder()ViewHolders හරහා ස්ථානගත කිරීමෙහි වෙනස් වන සමාන අදහස් සඳහා එකම අයි.ඩී. ලබා දීමෙන් ඔබට කොන්දේසි සහිත පදනම් වූ දර්ශන හෝල්ඩර් දත්ත පිරවීම වළක්වා ගත හැකිය .


1

කොට්ලින් හි ලියා ඇති සුපිරි සරල විසඳුම බැලීමට යමෙක් කැමති නම්, මා විසින් නිර්මාණය කරන ලද බ්ලොග් පෝස්ට් එක පරීක්ෂා කරන්න. බ්ලොග් පෝස්ට් හි උදාහරණය පදනම් වී ඇත්තේ අංශගත ප්‍රතිචක්‍රීකරණ දර්ශනය නිර්මාණය කිරීම මත ය:

https://brona.blog/2020/06/sectioned-recyclerview-in-three-steps/


1

වෙන කවරදාටත් වඩා සරල, ViewTypes ගැන අමතක කරන්න. එක් ඇඩැප්ටරයක් ​​තුළ බහුවිධ දෘෂ්ටි කෝණයන් භාවිතා කිරීම රෙකමදාරු කරනු නොලැබේ, එය කේතය අවුල් කර තනි වගකීම් මූලධර්මය බිඳ දමනු ඇත. ඇඩැප්ටරය විසින් කුමන දෘෂ්ටියක් උද්ධමනය කළ යුතු දැයි දැන ගැනීම සඳහා තර්කනය හැසිරවිය යුතුය, දැන් සිතන්න එක් එක් කණ්ඩායම වැඩ කළ යුතු විශාල කණ්ඩායම්වල වැඩ කිරීම එම දර්ශන ලක්ෂණ වලින් එකක්, විවිධ දෘෂ්ටි කෝණයන්හි වැඩ කරන සියලුම කණ්ඩායම් විසින් එකම ඇඩැප්ටරය ස්පර්ශ කිරීම අවුල් ජාලයක් වනු ඇත, මෙය කොන්කාට් ඇඩැප්ටරය භාවිතයෙන් විසඳනු ලැබේ, එහිදී ඔබ ඇඩප්ටරයන් හුදකලා කර, ඒවා එකින් එක කේත කර ඒවා එකකින් ඒකාබද්ධ කරන්න දැක්ම.

recyclerview:1.2.0-alpha04ඔබ වෙතින් දැන් භාවිතා කළ හැකියConcatAdapter

ඔබට විවිධ දර්ශන ටයිප් සහිත දර්ශනයක් අවශ්‍ය නම්, ඔබට එක් එක් කොටස සඳහා ඇඩැප්ටර ලිවිය හැකි අතර ඒවා සියල්ලම එක් ප්‍රතිචක්‍රීකරණ දර්ශනයක් තුළ ඒකාබද්ධ කිරීමට කොන්කට් ඇඩැප්ටරය භාවිතා කරන්න.

කොන්කට් ඇඩැප්ටරය

මෙම ප්‍රතිරූපය මඟින් එක් ප්‍රතිචක්‍රීකරණ දර්ශනයක්, ශීර්ෂකය, අන්තර්ගතය සහ පාදකය යන විවිධ දර්ශන 3 ක් පෙන්වයි.

රූප විස්තරය මෙහි ඇතුළත් කරන්න

ඔබ එක් එක් කොටස සඳහා එක් ඇඩැප්ටරයක් ​​පමණක් සාදයි, ඉන්පසු ඒවා එක් ප්‍රතිචක්‍රීකරණ දර්ශනයක් තුළ ඒකාබද්ධ කිරීමට කොන්කට් ඇඩැප්ටරය භාවිතා කරන්න

val firstAdapter: FirstAdapter = 
val secondAdapter: SecondAdapter = 
val thirdAdapter: ThirdAdapter = 
val concatAdapter = ConcatAdapter(firstAdapter, secondAdapter, 
     thirdAdapter)
recyclerView.adapter = concatAdapter

රූප විස්තරය මෙහි ඇතුළත් කරන්න

ඔබ දැනගත යුතු සියල්ල එයයි , ඔබට පැටවීමේ තත්වය හැසිරවීමට අවශ්‍ය නම්, උදාහරණයක් ලෙස යම් පැටවීමක් සිදු වූ පසු අවසන් ඇඩැප්ටරය ඉවත් කරන්න, ඔබට ලෝඩ්ස්ටේට් භාවිතා කළ හැකිය


0

ඔබට එය ඇන්ඩ්‍රොයිඩ් දත්ත බන්ධනයට සමගාමීව භාවිතා කිරීමට අවශ්‍ය නම් https://github.com/evant/binding-collection-adapter - එය RecyclerViewමා දැක ඇති බහු දර්ශන වර්ග සඳහා හොඳම විසඳුමයි .

ඔබට එය භාවිතා කළ හැකිය

var items: AsyncDiffPagedObservableList<BaseListItem> =
        AsyncDiffPagedObservableList(GenericDiff)

    val onItemBind: OnItemBind<BaseListItem> =
        OnItemBind { itemBinding, _, item -> itemBinding.set(BR.item, item.layoutRes) }

ඉන්පසු ලැයිස්තුව ඇති පිරිසැලසුම තුළ

 <androidx.recyclerview.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                app:enableAnimations="@{false}"
                app:scrollToPosition="@{viewModel.scrollPosition}"

                app:itemBinding="@{viewModel.onItemBind}"
                app:items="@{viewModel.items}"

                app:reverseLayoutManager="@{true}"/>

ඔබගේ ලැයිස්තු අයිතමයන් BaseListItemමේ ආකාරයට පෙනෙන අතුරු මුහුණත ක්‍රියාත්මක කළ යුතුය

interface BaseListItem {
    val layoutRes: Int
}

අයිතම දර්ශනය මේ වගේ දෙයක් විය යුතුයි

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
                name="item"
                type="...presentation.somescreen.list.YourListItem"/>
    </data>

   ...

</layout>

කොහෙද YourListItemඋපකරණBaseListItem

එය යමෙකුට උපකාර කරනු ඇතැයි සිතමි.


0

පළමුව ඔබ xml පිරිසැලසුම් 2 ක් සෑදිය යුතුය. ඉන් පසු ප්‍රතිචක්‍රීකරණ ඇඩැප්ටරය TYPE_CALL සහ TYPE_EMAIL යනු ස්ථිතික අගයන් දෙකකි.

දැන් ප්‍රතිචක්‍රීකරණ දර්ශනයේ ස්ථිතික අගයන් දෙකක් නිර්වචනය කරන්න ඇඩැප්ටර පන්ති මට්ටම: උදාහරණයක් ලෙස පුද්ගලික ස්ථිතික int TYPE_CALL = 1; පුද්ගලික ස්ථිතික int TYPE_EMAIL = 2;

දැන් මේ වගේ බහුවිධ අදහස් ඇති දර්ශන දරන්නා සාදන්න:

class CallViewHolder extends RecyclerView.ViewHolder {

    private TextView txtName;
    private TextView txtAddress;

    CallViewHolder(@NonNull View itemView) {
        super(itemView);
        txtName = itemView.findViewById(R.id.txtName);
        txtAddress = itemView.findViewById(R.id.txtAddress);
    }
}
class EmailViewHolder extends RecyclerView.ViewHolder {

    private TextView txtName;
    private TextView txtAddress;

    EmailViewHolder(@NonNull View itemView) {
        super(itemView);
        txtName = itemView.findViewById(R.id.txtName);
        txtAddress = itemView.findViewById(R.id.txtAddress);
    }
}

දැන් ප්‍රතිචක්‍රීකරණ දර්ශන ඇඩැප්ටරයේ onCreateViewHolder සහ onBindViewHolder ක්‍රමයේ පහත පරිදි කේත කරන්න:

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
    View view;
    if (viewType == TYPE_CALL) { // for call layout
        view = LayoutInflater.from(context).inflate(R.layout.item_call, viewGroup, false);
        return new CallViewHolder(view);

    } else { // for email layout
        view = LayoutInflater.from(context).inflate(R.layout.item_email, viewGroup, false);
        return new EmailViewHolder(view);
    }
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
    if (getItemViewType(position) == TYPE_CALL) {
        ((CallViewHolder) viewHolder).setCallDetails(employees.get(position));
    } else {
        ((EmailViewHolder) viewHolder).setEmailDetails(employees.get(position));
    }
}

0

මෙම මාතෘකාව පිළිබඳ හැනස් ඩෝර්ෆ්මන්ගේ විශිෂ්ට ලිපිය කියවීමට මම ඔබට මුලින්ම නිර්දේශ කරමි .

නව දර්ශන වර්ගය පැමිණි විට, ඔබ ඔබේ ඇඩැප්ටරය සංස්කරණය කළ යුතු අතර ඔබට බොහෝ අවුල් සහගත දේවල් හැසිරවිය යුතුය. ඔබේ ඇඩැප්ටරය දිගුව සඳහා විවෘත විය යුතු නමුත් වෙනස් කිරීම සඳහා වසා ඇත.

ඔබට මෙම ව්‍යාපෘතිය දෙක පරීක්ෂා කළ හැකිය, ඇඩැප්ටරයේ විවිධ දර්ශන ටයිප් හැසිරවිය යුතු ආකාරය පිළිබඳ අදහස ඔවුන්ට ලබා දිය හැකිය:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.