RecyclerView - विशेष स्थिति में देखें


140

मेरे पास ए RecyclerViewऔर ए के साथ एक गतिविधि है ImageView। मैं RecyclerViewक्षैतिज रूप से छवियों की एक सूची दिखाने के लिए उपयोग कर रहा हूं । जब मैं में एक छवि पर क्लिक गतिविधि में छवि का एक बड़ी तस्वीर को दिखाना चाहिए। अब तक सब ठीक है।RecyclerViewImageView

अब ImageButtonsगतिविधि में दो और हैं : imageButton_leftऔर imageButton_right। जब मैं पर क्लिक करता हूं imageButton_left, तो छवि को ImageViewबाईं ओर मुड़ना चाहिए और साथ ही, थंबनेल में भी RecyclerViewइस बदलाव को प्रतिबिंबित करना चाहिए। ऐसा ही हाल है imageButton_right

मैं इसे घुमाने में सक्षम हूं ImageView। लेकिन, मैं थंबनेल को कैसे घुमा सकता हूं RecyclerView? मैं कैसे प्राप्त कर सकता ViewHolderहै ImageView?

कोड:

गतिविधि XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/original_image"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:scaleType="fitXY"
            android:src="@drawable/image_not_available_2" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center_horizontal"
            android:orientation="horizontal">


            <ImageButton
                android:id="@+id/imageButton_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="20dp"
                android:background="@drawable/rotate_left_icon" />

            <ImageButton
                android:id="@+id/imageButton_right"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/rotate_right_icon" />

        </LinearLayout>
    </LinearLayout>
</LinearLayout>

मेरी गतिविधि कोड:

public class SecondActivity extends AppCompatActivity implements IRecyclerViewClickListener {


    RecyclerView mRecyclerView;
    LinearLayoutManager mLayoutManager;
    RecyclerViewAdapter mRecyclerViewAdapter;
    List<String> urls = new ArrayList<String>();
    ImageView mOriginalImageView;
    ImageButton mLeftRotate, mRightRotate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        urls.clear();

        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mLayoutManager = new LinearLayoutManager(this, android.support.v7.widget.LinearLayoutManager.HORIZONTAL, false);
        mLayoutManager.setOrientation(android.support.v7.widget.LinearLayoutManager.HORIZONTAL);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerViewAdapter = new RecyclerViewAdapter(this, urls);
        mRecyclerView.setAdapter(mRecyclerViewAdapter);

        mOriginalImageView = (ImageView) findViewById(R.id.original_image);
        mLeftRotate = (ImageButton) findViewById(R.id.imageButton_left);
        mLeftRotate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOriginalImageView.setRotation(mOriginalImageView.getRotation() - 90);
            }
        });


        mRightRotate = (ImageButton) findViewById(R.id.imageButton_right);
        mRightRotate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOriginalImageView.setRotation(mOriginalImageView.getRotation() + 90);
            }
        });

        Intent intent = getIntent();
        if (intent != null) {

            String portfolio = intent.getStringExtra("portfolio");

            try {

                JSONArray jsonArray = new JSONArray(portfolio);

                for (int i = 0; i < jsonArray.length(); i++) {

                    JSONObject jsonObject = jsonArray.getJSONObject(i);

                    String url = jsonObject.getString("url");
                    urls.add(url);
                }

                Log.d(Const.DEBUG, "URLs: " + urls.toString());

                mRecyclerViewAdapter.notifyDataSetChanged();

            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }


    @Override
    public void onItemClick(int position) {
        Picasso.with(this).load(urls.get(position)).into(mOriginalImageView);
    }
}

मेरा कस्टम एडाप्टर RecyclerView के लिए:

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

    Context context;
    List<String> mUrls = new ArrayList<String>();

    IRecyclerViewClickListener mIRecyclerViewClickListener;

    public int position;

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }



    public RecyclerViewAdapter(Context context, List<String> urls) {
        this.context = context;
        this.mUrls.clear();
        this.mUrls = urls;

        Log.d(Const.DEBUG, "Urls Size: " + urls.size());
        Log.d(Const.DEBUG, urls.toString());

        if (context instanceof IRecyclerViewClickListener)
            mIRecyclerViewClickListener = (IRecyclerViewClickListener) context;
        else
            Log.d(Const.DEBUG, "Implement IRecyclerViewClickListener in Activity");
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_horizontal_recyclerview, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Picasso.with(context).load(mUrls.get(position)).into(holder.mImageView);
    }

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


    public void rotateThumbnail() {


    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        public ImageView mImageView;
        public View v;

        public ViewHolder(View v) {
            super(v);
            v.setTag(getAdapterPosition());
            v.setOnClickListener(this);
            this.mImageView = (ImageView) v.findViewById(R.id.image);
        }

        @Override
        public void onClick(View v) {
            this.v = v;
            mIRecyclerViewClickListener.onItemClick(getAdapterPosition());
        }
    }


}

1
आपको इसे अपने व्यूहोल्डर कंस्ट्रक्टर में बनाना चाहिए, एक प्रॉपर्टी जोड़ें जो आपको बताएगी कि क्या छवि को घुमाने की जरूरत है, तो बस अपने डेटा पर उस प्रॉपर्टी को बदल दें और recyclerView को फिर से लोड करने के लिए
InformDataSetChanged

क्या कोई उत्तर आपकी समस्या का समाधान करता है?
स्कॉट बिग्स

ViewHolder प्रदर्शन के मुद्दे के लिए स्थिर होना चाहिए। बाहरी वर्ग से सभी चर को कंस्ट्रक्टर के माध्यम से पारित किया जाना चाहिए।
AppiDevo

@ स्कॉट के जवाब के पूरक के रूप में यहां
म्यूट टोनी

जवाबों:


149

मुझे लगता है कि आप LinearLayoutManagerसूची दिखाने के लिए एक का उपयोग कर रहे हैं । यह कहा जाता है findViewByPositionकि एक अच्छा तरीका है

उस दृश्य को ढूंढता है जो दिए गए एडेप्टर की स्थिति को दर्शाता है।

आपको केवल उस वस्तु की एडॉप्टर स्थिति की आवश्यकता है जिसमें आप रुचि रखते हैं।

संपादित करें : जैसा कि पॉल Woitaschek द्वारा टिप्पणी में उल्लेख किया गया है , findViewByPositionयह एक तरीका है LayoutManagerताकि यह सभी LayoutManagers (यानी StaggeredGridLayoutManager, आदि) के साथ काम करेगा ।


9
Thats वास्तव में इस तरह की एक विधि LayoutManagerसभी LayoutManager उपवर्गों के लिए काम करेगी।
बजे पॉल Woitaschek

स्रोत कोड को देखा। LinearLayoutManger प्रीलेयट में नहीं होने पर बैकिंग एरे पर डायरेक्ट एसे के माध्यम से दिखता है, जबकि रिसाइक्लर व्यू पद्धति हमेशा ट्रैवर्सल करती है। तो यह विधि अधिक कुशल होने की संभावना है।
नेमस्पेस

अरे @stanO आप मुझे इस stackoverflow.com/questions/49952965/… के

3
रिटर्न: दृश्य - वह बच्चा दृश्य जो दी गई स्थिति या अशक्त का प्रतिनिधित्व करता है, यदि स्थिति निर्धारित नहीं की जाती है ... recyclerview -> अधिकांश चीजें अशक्त लौट
आती हैं

ध्यान रखें कि आपको तब तक इंतजार करना होगा जब तक एडेप्टर सूची में नहीं जुड़ जाएगा, विवरण के लिए मेरा जवाब नीचे देखें
कोंस्टेंटिन कोनपोको

241

यह वही है जो आप खोज रहे हैं

मुझे यह समस्या भी हुई। और आप की तरह, उत्तर खोजने के लिए बहुत मुश्किल है। लेकिन एक विशिष्ट स्थिति से ViewHolder प्राप्त करने का एक आसान तरीका है (कुछ आप शायद एडॉप्टर में बहुत कुछ करेंगे)।

myRecyclerView.findViewHolderForAdapterPosition(pos);

नोट: यदि दृश्य पुनर्नवीनीकरण किया गया है, तो यह वापस आ जाएगा null। मेरी महत्वपूर्ण चूक को जल्दी से पकड़ने के लिए माइकल को धन्यवाद।


3
यह वही है जो मैं लेआउटमैनगर में देख रहा था
एड ली

12
यह काम करता है, हालांकि, यदि ViewHolderआप संदर्भ देने की कोशिश कर रहे हैं , तो "पुनर्नवीनीकरण" किया गया था, यह वापस आ जाएगा null
माइकल

5
@ मिचेल, अच्छी पकड़! यह आप सभी के लिए एक चेतावनी है, पहले अशक्त के लिए परीक्षण (हाँ, Android में बाकी सब की तरह)!
स्कॉट बिग्स

1
क्या हम एडॉप्टर के अंदर से ऐसा कर सकते हैं?
मौकर

2
@Mauker: आप इसे किसी भी चीज़ से उपयोग कर सकते हैं जो RecyclerView के उदाहरण तक पहुँच सकता है।
स्कॉट बिग्स

26

यदि आप चाहते हैं View, तो सुनिश्चित करें कि itemViewViewHolder की संपत्ति का उपयोग करना सुनिश्चित करें :myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;


11

आप दोनों का उपयोग कर सकते हैं

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) और recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition)। सुनिश्चित करें कि RecyclerView दृश्य दो प्रकार के पदों का उपयोग करता है

एडेप्टर की स्थिति: एडॉप्टर में किसी आइटम की स्थिति। यह एडेप्टर के दृष्टिकोण से स्थिति है। लेआउट की स्थिति: नवीनतम लेआउट गणना में किसी आइटम की स्थिति। यह LayoutManager के दृष्टिकोण से स्थिति है। आप के getAdapterPosition()लिए findViewHolderForAdapterPosition(adapterPosition)और के getLayoutPosition()लिए उपयोग करना चाहिए findViewHolderForLayoutPosition(layoutPosition)

उपयोगकर्ता पहली बार क्लिक कर रहा है या नहीं, यह जांचने के लिए रिसाइकलव्यू एडॉप्टर और अन्य सदस्य वैरिएबल में पहले से चयनित आइटम स्थिति को रखने के लिए एक सदस्य चर लें।

नीचे दिए गए अधिक जानकारी के लिए नमूना कोड और स्क्रीन शॉट्स संलग्न हैं।

public class MainActivity extends AppCompatActivity {     

private RecyclerView mRecyclerList = null;    
private RecyclerAdapter adapter = null;    

@Override    
protected void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);    
    setContentView(R.layout.activity_main);    

    mRecyclerList = (RecyclerView) findViewById(R.id.recyclerList);    
}    

@Override    
protected void onStart() {    
    RecyclerView.LayoutManager layoutManager = null;    
    String[] daysArray = new String[15];    
    String[] datesArray = new String[15];    

    super.onStart();    
    for (int i = 0; i < daysArray.length; i++){    
        daysArray[i] = "Sunday";    
        datesArray[i] = "12 Feb 2017";    
    }    

    adapter = new RecyclerAdapter(mRecyclerList, daysArray, datesArray);    
    layoutManager = new LinearLayoutManager(MainActivity.this);    
    mRecyclerList.setAdapter(adapter);    
    mRecyclerList.setLayoutManager(layoutManager);    
}    
}    


public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyCardViewHolder>{          

private final String TAG = "RecyclerAdapter";        
private Context mContext = null;        
private TextView mDaysTxt = null, mDateTxt = null;    
private LinearLayout mDateContainerLayout = null;    
private String[] daysArray = null, datesArray = null;    
private RecyclerView mRecyclerList = null;    
private int previousPosition = 0;    
private boolean flagFirstItemSelected = false;    

public RecyclerAdapter(RecyclerView mRecyclerList, String[] daysArray, String[] datesArray){    
    this.mRecyclerList = mRecyclerList;    
    this.daysArray = daysArray;    
    this.datesArray = datesArray;    
}    

@Override    
public MyCardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    
    LayoutInflater layoutInflater = null;    
    View view = null;    
    MyCardViewHolder cardViewHolder = null;    
    mContext = parent.getContext();    
    layoutInflater = LayoutInflater.from(mContext);    
    view = layoutInflater.inflate(R.layout.date_card_row, parent, false);    
    cardViewHolder = new MyCardViewHolder(view);    
    return cardViewHolder;    
}    

@Override    
public void onBindViewHolder(MyCardViewHolder holder, final int position) {    
    mDaysTxt = holder.mDaysTxt;    
    mDateTxt = holder.mDateTxt;    
    mDateContainerLayout = holder.mDateContainerLayout;    

    mDaysTxt.setText(daysArray[position]);    
    mDateTxt.setText(datesArray[position]);    

    if (!flagFirstItemSelected){    
        mDateContainerLayout.setBackgroundColor(Color.GREEN);    
        flagFirstItemSelected = true;    
    }else {    
        mDateContainerLayout.setBackground(null);    
    }    
}    

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

class MyCardViewHolder extends RecyclerView.ViewHolder{    
    TextView mDaysTxt = null, mDateTxt = null;    
    LinearLayout mDateContainerLayout = null;    
    LinearLayout linearLayout = null;    
    View view = null;    
    MyCardViewHolder myCardViewHolder = null;    

    public MyCardViewHolder(View itemView) {    
        super(itemView);    
        mDaysTxt = (TextView) itemView.findViewById(R.id.daysTxt);    
        mDateTxt = (TextView) itemView.findViewById(R.id.dateTxt);    
        mDateContainerLayout = (LinearLayout) itemView.findViewById(R.id.dateContainerLayout);    

        mDateContainerLayout.setOnClickListener(new View.OnClickListener() {    
            @Override    
            public void onClick(View v) {    
                LinearLayout linearLayout = null;    
                View view = null;    

                if (getAdapterPosition() == previousPosition){    
                    view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackgroundColor(Color.GREEN);    
                    previousPosition = getAdapterPosition();    

                }else {    
                    view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackground(null);    

                    view = mRecyclerList.findViewHolderForAdapterPosition(getAdapterPosition()).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackgroundColor(Color.GREEN);    
                    previousPosition = getAdapterPosition();    
                }    
            }    
        });    
    }    
}       

} पहला तत्व चयनित दूसरा तत्व चयनित और पहले से चयनित आइटम अचयनित हो जाता है पांचवें तत्व का चयन किया और पहले से चयनित आइटम अचयनित हो जाता है


और मुझे लगा कि यह चर्चा समाप्त हो गई है! इस मुद्दे को और स्पष्ट करने के लिए धन्यवाद।
स्कॉट बिग्स

2
यहाँ मुझे दूसरे ब्लॉक में NullPointer अपवाद मिल रहा है जब मैं पिछले आइटम का रंग बदलने की कोशिश कर रहा हूं, इसलिए मैंने null चेक जोड़ा है, अब यह उस ब्लॉक में प्रवेश नहीं कर रहा है यदि इसमें NullPointer अपवाद हो रहा है, तो पिछले आइटम रंग कभी नहीं बदला है। अब मेरे पुनर्नवीनीकरण दृश्य में कई रंगीन वस्तुओं के साथ आइटम हैं। मैं इसे कैसे हल करूं
अभिलाष रेड्डी

8

आप ViewHolder के ArrayList बना सकते हैं:

 ArrayList<MyViewHolder> myViewHolders = new ArrayList<>();
 ArrayList<MyViewHolder> myViewHolders2 = new ArrayList<>();

और, सभी स्टोर ViewHolder (ओं) को सूची में शामिल करें जैसे:

 @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        final String str = arrayList.get(position);

        myViewHolders.add(position,holder);
}

और अपनी आवश्यकता के अनुसार ArrayList में अन्य ViewHolder जोड़ें / निकालें।


धन्यवाद, मैं 2 दिनों के लिए पुनर्नवीनीकरण धारकों को पाने के लिए संघर्ष कर रहा था।
nimi0112

5

आप निम्न का उपयोग करके किसी रिसाइकिलव्यू पर किसी विशेष स्थिति के लिए एक दृश्य प्राप्त कर सकते हैं

int position = 2;
RecyclerView.ViewHolder viewHolder = recyclerview.findViewHolderForItemId(position);
View view = viewHolder.itemView;
ImageView imageView = (ImageView)view.findViewById(R.id.imageView);

5

आप बस रिसाइकलर व्यू का " findViewHolderForAdapterPosition " विधि का उपयोग कर सकते हैं और आपको एक व्यूहॉल्ड ऑब्जेक्ट मिलेगा, फिर उस एडॉप्टर व्यूअर को अपने एडॉप्टर व्यूहोल्डर में टाइप करें ताकि आप सीधे अपने व्यूहोल्डर के विचारों तक पहुंच सकें

निम्नलिखित कोटलिन के लिए नमूना कोड है

 val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
 val textview=(viewHolder as YourViewHolder).yourTextView

4

ध्यान रखें कि आपको तब तक इंतजार करना होगा जब तक एडेप्टर सूची में नहीं जुड़ जाएगा, तब आप स्थिति के अनुसार देखने का प्रयास कर सकते हैं

final int i = 0;
recyclerView.setAdapter(adapter);
recyclerView.post(new Runnable() {
    @Override
    public void run() {
        View view = recyclerView.getLayoutManager().findViewByPosition(i);
    }
});

2
यदि आप कई आइटम जोड़ते हैं तो यह हमेशा काम नहीं करता है (यानी: यदि आपके पास एक बटन है जो उन्हें जोड़ता है और इसे तेजी से दबाएं)। आपको देरी के साथ रननेबल को जोड़ना चाहिए।
एलेक्स बुरडुलस

3

RecyclerView की एक विशिष्ट स्थिति से एक दृश्य प्राप्त करने के लिए आपको recyclerView ऑब्जेक्ट पर findViewHolderForAdapterPosition (स्थिति) को कॉल करने की आवश्यकता होती है जो RecyclerView.ViewHolder को लौटा देगा

आइटम दृश्य के साथ दिए गए RecyclerView.ViewHolder ऑब्जेक्ट से आप उस विशेष स्थान पर सभी दृश्य एक्सेस कर सकते हैं

RecyclerView.ViewHolder rv_view = recyclerView.findViewHolderForAdapterPosition(position);

ImageView iv_wish = rv_view.itemView.findViewById(R.id.iv_item);

1

आप ऐसा कर सकते हैं, यह तब मदद करेगा जब आप किसी रिसाइक्लेव्यू स्थिति आइटम पर क्लिक करने के बाद किसी दृश्य को संशोधित करना चाहते हैं

@Override
public void onClick(View view, int position) {

            View v =  rv_notifications.getChildViewHolder(view).itemView;
            TextView content = v.findViewById(R.id.tv_content);
            content.setText("Helloo");

        }

1

पुनर्नवीनीकरण दृश्य सूची से विशिष्ट दृश्य प्राप्त करने के लिए या पुनर्नवीनीकरण दृश्य के संपादन में त्रुटि दिखाएं।

private void popupErrorMessageAtPosition(int itemPosition) {

    RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(itemPosition);
    View view = viewHolder.itemView;
    EditText etDesc = (EditText) view.findViewById(R.id.et_description);
    etDesc.setError("Error message here !");
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.