RecyclerView - Nhận xem tại vị trí cụ thể


140

Tôi có một hoạt động với một RecyclerViewvà một ImageView. Tôi đang sử dụng RecyclerViewđể hiển thị một danh sách các hình ảnh theo chiều ngang. Khi tôi bấm vào một hình ảnh trong RecyclerViewcác ImageViewhoạt động cần hiển thị một bức tranh lớn hơn của hình ảnh. Cho đến nay mọi thứ hoạt động tốt.

Bây giờ có hai ImageButtonshoạt động nữa: imageButton_leftimageButton_right. Khi tôi nhấp vào imageButton_left, hình ảnh trong ImageViewphải rẽ trái và hình thu nhỏ trong RecyclerViewsẽ phản ánh sự thay đổi này. Tương tự là trường hợp với imageButton_right.

Tôi có thể xoay ImageView. Nhưng, làm thế nào tôi có thể xoay hình thu nhỏ trong RecyclerView? Làm thế nào tôi có thể nhận được ViewHolder's ImageView?

Mã số:

Hoạt động 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>

Mã hoạt động của tôi:

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);
    }
}

Bộ điều hợp tùy chỉnh của tôi cho 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
Bạn nên đặt nó trong công cụ xây dựng viewHolder của bạn, thêm một thuộc tính sẽ cho bạn biết nếu hình ảnh cần được xoay, sau đó chỉ cần thay đổi thuộc tính đó trên dữ liệu của bạn và gọi notifyDataSetChanged để tải lại recyclerView
Nanoc

Có bất kỳ câu trả lời giải quyết vấn đề của bạn?
Scott Bigss

ViewHolder nên tĩnh cho vấn đề hiệu suất. Tất cả các biến từ lớp bên ngoài phải được truyền qua hàm tạo.
AppiDevo

Để bổ sung cho câu trả lời của @ Scott Bấm vào đây
mut tony

Câu trả lời:


149

Tôi cho rằng bạn đang sử dụng một LinearLayoutManagerđể hiển thị danh sách. Nó có một phương thức findViewByPositionhay

Tìm khung nhìn đại diện cho vị trí bộ điều hợp đã cho.

Tất cả bạn cần là vị trí bộ chuyển đổi của mặt hàng bạn quan tâm.

chỉnh sửa : như được lưu ý bởi Paul Woitaschek trong các bình luận, findViewByPositionlà một phương pháp LayoutManagerđể nó sẽ hoạt động với tất cả các Trình quản lý (ví dụ StaggeredGridLayoutManager, v.v.)


9
Đó thực sự là một phương thức của LayoutManagervì vậy điều này sẽ hoạt động cho tất cả các lớp con LayoutManager.
Paul Woitaschek

Nhìn vào mã nguồn. Tuyến tínhLayoutManger tìm kiếm thông qua directAccess trên mảng sao lưu khi không ở chế độ trước, trong khi phương thức recyclerView luôn thực hiện truyền tải. Vì vậy, phương pháp này có khả năng hiệu quả hơn.
NameSpace

Xin chào @stanO, bạn có thể vui lòng giúp tôi với stackoverflow.com/questions/49952965/iêng

3
Trả về: Chế độ xem - Chế độ xem con đại diện cho vị trí đã cho hoặc null nếu vị trí không được đặt ra ... recyclerview -> hầu hết mọi thứ trả về null
me_

Hãy nhớ rằng bạn phải đợi cho đến khi bộ chuyển đổi sẽ được thêm vào danh sách, xem câu trả lời của tôi dưới đây để biết chi tiết
Konstantin Konopko

241

Đây là những gì bạn đang tìm kiếm .

Tôi cũng có vấn đề này. Và giống như bạn, câu trả lời là rất khó tìm. Nhưng có một cách dễ dàng để có được ViewHolder từ một vị trí cụ thể (điều mà có lẽ bạn sẽ làm được rất nhiều trong Bộ điều hợp).

myRecyclerView.findViewHolderForAdapterPosition(pos);

LƯU Ý: Nếu Chế độ xem đã được tái chế, điều này sẽ trở lại null. Cảm ơn Michael đã nhanh chóng nắm bắt được thiếu sót quan trọng của tôi.


3
Đây chính xác là những gì tôi đang tìm kiếm trong Trình quản lý bố cục
Ed Lee

12
Điều này hoạt động, tuy nhiên, nếu ViewHolderbạn đang cố gắng tham khảo là "tái chế", nó sẽ trở lại null.
Michael

5
@Michael, bắt tốt! Đó là lời cảnh báo cho tất cả các bạn ngoài kia, trước tiên hãy kiểm tra null (vâng, giống như mọi thứ khác trong Android)!
Scott Biggie

1
Chúng ta có thể làm điều này từ bên trong bộ chuyển đổi?
Mauker

2
@Mauker: Bạn có thể sử dụng điều này từ bất cứ thứ gì có thể truy cập vào đối tượng RecyclerView.
Scott Biggie

27

Nếu bạn muốn View, hãy đảm bảo truy cập vào thuộc itemViewtính của ViewHolder như sau:myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;


11

Bạn có thể sử dụng cả hai

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition)recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition). Hãy chắc chắn rằng chế độ xem RecyclerView sử dụng hai loại vị trí

Vị trí bộ chuyển đổi: Vị trí của một mục trong bộ chuyển đổi. Đây là vị trí từ quan điểm của Adaptor. Vị trí bố trí: Vị trí của một mục trong tính toán bố trí mới nhất. Đây là vị trí theo quan điểm của Trình quản lý bố cục. Bạn nên sử dụng getAdapterPosition()cho findViewHolderForAdapterPosition(adapterPosition)getLayoutPosition()chofindViewHolderForLayoutPosition(layoutPosition) .

Lấy một biến thành viên để giữ vị trí mục đã chọn trước đó trong bộ điều hợp recyclerview và biến thành viên khác để kiểm tra xem người dùng có nhấp lần đầu hay không.

Mã mẫu và ảnh chụp màn hình được đính kèm để biết thêm thông tin ở phía dưới.

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();    
                }    
            }    
        });    
    }    
}       

} yếu tố đầu tiên được chọn phần tử thứ hai được chọn và mục được chọn trước đó trở thành không được chọn phần tử thứ năm được chọn và mục được chọn trước đó trở thành không được chọn


Và tôi nghĩ rằng cuộc thảo luận này đã hết! Cảm ơn đã làm rõ hơn vấn đề này.
Scott Biggie

2
Ở đây tôi nhận được ngoại lệ NullPulum trong khối khác khi tôi đang cố gắng thay đổi màu của mục trước đó, vì vậy tôi đã thêm kiểm tra null, bây giờ nó không bao giờ được nhập vào khối đó nếu có ngoại lệ NullPulum, vì vậy màu của mục trước không bao giờ thay đổi. bây giờ, khung nhìn Recycler của tôi có các mục có nhiều mục màu. Làm thế nào để tôi giải quyết điều này
Abhilash Reddy

8

Bạn có thể tạo ArrayList của ViewHolder:

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

và, tất cả các cửa hàng ViewHolder trong danh sách như:

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

        myViewHolders.add(position,holder);
}

và thêm / xóa ViewHolder khác trong ArrayList theo yêu cầu của bạn.


Cảm ơn bạn tôi đã đấu tranh để có được chủ sở hữu tái chế trong 2 ngày.
nimi0112

5

Bạn có thể có được chế độ xem cho một vị trí cụ thể trên recyclerview bằng cách sử dụng như sau

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

5

Bạn chỉ có thể sử dụng " findViewHolderForAd ModuleP vị trí phương thức " " của chế độ xem tái chế và bạn sẽ nhận được một đối tượng viewHolder từ đó đánh máy người xem đó vào trình xem bộ điều hợp của bạn để bạn có thể truy cập trực tiếp vào chế độ xem của người xem

sau đây là mã mẫu cho kotlin

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

4

Hãy nhớ rằng bạn phải đợi cho đến khi bộ điều hợp sẽ được thêm vào danh sách, sau đó bạn có thể cố gắng để xem theo vị trí

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

2
Điều này không phải lúc nào cũng hoạt động nếu bạn thêm nhiều mục (ví dụ: nếu bạn có một nút thêm chúng và nhấn nhanh). Bạn nên thêm runnable với độ trễ.
Alex Burdusel

3

Để có được Chế độ xem từ một vị trí cụ thể của recyclerView, bạn cần gọi findViewHolderForAd ModuleP vị trí (vị trí) trên đối tượng recyclerView sẽ trả về RecyclerView.ViewHolder

từ đối tượng RecyclerView.ViewHolder được trả về với itemView, bạn có thể truy cập tất cả các Chế độ xem tại vị trí cụ thể đó

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

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

1

Bạn cũng có thể làm điều này, điều này sẽ giúp ích khi bạn muốn sửa đổi chế độ xem sau khi nhấp vào mục vị trí tái chế

@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

Để có được chế độ xem cụ thể từ danh sách chế độ xem tái chế HOẶC hiển thị lỗi tại edittext của chế độ xem của trình tái chế.

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 !");
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.