从适配器外部控制 RecyclerView 膨胀视图:保持选择状态

Control RecyclerView inflated views from outside the adapter: keep selection state

一般

我想从 ViewHolder 和 RecyclerView class 之外控制我的 RecyclerView 的 ViewHolder 膨胀视图。换句话说,我想从其他 methods/classes.

控制这些视图

我的案例(示例)

在我的具体案例中,我制作了一个照片库 activity,它允许用户对每个膨胀视图执行选择和取消选择,并通过突出显示来通知选择了哪些项目。

目前,用户可以通过单击每个生成的对象/视图来完成此操作;然后,由于 "setOnClickListener" 和 "setOnLongClickListener" 方法,可以对 RecyclerView / 适配器的特定子项执行操作,它们在方法 inside 中执行相应的操作 ViewHolder class.

但是当 activity 重新启动时(即设备旋转),选择丢失,用户应再次执行选择(即删除照片)。

假设所选照片的​​位置保持不变(例如通过捆绑或通过数组)可以在 [=46= 之后在适配器视图上恢复选择(即突出显示相应的项目/视图) 】 重新开始?如果是,如何?

一些代码

下面的代码包含 Recyclerview class 和 AdapterView class,它们都是 activity Class.

的子项
private class ImageGalleryAdapter extends RecyclerView.Adapter<ImageGalleryAdapter.MyViewHolder>  {

    private ArrayList<PhotoObject.PhotoElement> photoAL;
    private Context mContext;
    public ImageGalleryAdapter(Context context, ArrayList<PhotoObject.PhotoElement> photosToPreviewInGallery) {
        mContext = context;
        photoAL = photosToPreviewInGallery;
    }

    @Override
    public ImageGalleryAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        // Inflate the layout
        View itemView = inflater.inflate(R.layout.item_photo, parent, false);

        ImageGalleryAdapter.MyViewHolder viewHolder = new ImageGalleryAdapter.MyViewHolder(itemView);
        // Retrieving the itemView
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ImageGalleryAdapter.MyViewHolder holder, int position) {

        PhotoObject.PhotoElement previewPhotoInGallery = photoAL.get(position);
        ImageView imageView = holder.mPhotoImageView;

        GlideApp.with(mContext)
                .load(previewPhotoInGallery.getUrl())
                .placeholder(R.drawable.ic_cloud_off_red)
                .into(imageView);
    }

    //The method which gives back the number of items to load as photo.
    @Override
    public int getItemCount() {
        return (photoAL.size());
    }

    // The class that assigns a view holder for each Image and checkbox in the RecyclerView.
    public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

        public ImageView mPhotoImageView;
        public CheckBox mPhotoCheckBox;
        public MyViewHolder(View item_view) {

            super(item_view);
            mPhotoImageView = (ImageView) item_view.findViewById(R.id.item_photo_iv);
            mPhotoCheckBox = (CheckBox) item_view.findViewById(R.id.item_photo_checkbox);

            item_view.setOnClickListener(this);
            item_view.setOnLongClickListener(this);

            // Retrieving the item_view
        }

        // The method for managing the click on an image.
        @Override
        public void onClick(View view) {
            itemSelection(view);
        }

        // Manages the selection of the items.
        private void itemSelection(View item) {
            // Retrieving the item

            int position = getAdapterPosition();

            if (position != RecyclerView.NO_POSITION) {
                if (!item.isSelected()) {
                    // Add clicked item to the selected ones
                    MultiPhotoShootingActivity.manageSelection(true, position);

                    // Visually highlighting the ImageView
                    item.setSelected(true);
                    mPhotoCheckBox.setChecked(true);
                    mPhotoCheckBox.setVisibility(View.VISIBLE);
                } else {
                    // Remove clicked item from the selected ones
                    MultiPhotoShootingActivity.manageSelection(false, position);

                    // Removing the visual highlights on the ImageView
                    item.setSelected(false);
                    mPhotoCheckBox.setChecked(false);
                    mPhotoCheckBox.setVisibility(View.INVISIBLE);
                }
            }
        }

        // The method for managing the long click on an image.
        @Override
        public boolean onLongClick(View view) {

            int position = getAdapterPosition();
            if(position != RecyclerView.NO_POSITION) {
                Intent intent = new Intent(mContext, PhotoDetail.class);
                intent.putExtra("KEY4URL", activityPhotoObject.getPath(position));
                startActivity(intent);
            }

            // return true to indicate that the click was handled (if you return false onClick will be triggered too)
            return true;
        }
    }

}

感谢您的宝贵时间。

@Alessandro

您可以自己处理 Runtime changes

在您的清单中,您可以定义您的 activity 将自行处理并且不会重新启动的更改。

android:configChanges="orientation|keyboardHidden"

之后,您必须在 activity:

中使用此方法处理您在清单中声明的​​配置更改
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        // Do your thing
    } 
}

您不应该 "control" 从适配器外部查看。相反,在 activity 中覆盖 onSaveState 和 onRestoreState。在您的适配器中使用相同的方法将包传递给适配器以保存状态。将选择的位置的整数数组保存到包中(您传递到适配器中)。通过相应的方式,您可以从 On restore state 的 bundle 中获取选定位置的数组。

activity:

@Override 
protected void onRestoreInstanceState(Bundle savedInstanceState){
          adapter.onRestoreInstanceState(savedInstanceState);
}

在您的适配器中:

public void onRestoreInstanceState(Bundle state){
    selectedItemsArray = state.getIntArray("my_array_key")
}

已解决

发现要解决这个问题,我必须完成两个小任务:

  • 保存和恢复所选项目的选择状态(例如通过数组,如@Inkognito 所建议的那样);
  • 正在根据 RecyclerView 中的位置检索应用选择的视图。

所以,我不得不修改一些代码。
在继续之前,我想指出 Activity class 有一个子 class,即 Adapter class(名为 ImageGalleryAdapter); Adapter subclass 又拥有自己的 subclass,即 ViewHolder class(名为 MyViewHolder)。
所以:Activity class -> Adapter class -> ViewHolder class

父class中修改的代码(activityclass,其中RecyclerView是)

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    adapter.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    adapter.onRestoreInstanceState(savedInstanceState);
}

onSaveInstanceStateonRestoreInstanceState方法中,我添加了用于保存和恢复"adapter"子class.

实例状态的引用

在适配器 class 中添加的代码(位于 RecyclerView class 内)

    private boolean [] selectedItemsArray;
    private void onSaveInstanceState(Bundle outState) {
        outState.putBooleanArray("my_array_key" , selectedItemsArray = mpsaPO.getItemsSelected());
    }

    private void onRestoreInstanceState(Bundle state) {
        if (state != null) {
            selectedItemsArray = state.getBooleanArray("my_array_key");
        }
    }

selectedItemsArray是一个布尔数组,其中包含了RecyclerView的哪些元素被选中(true=选中;false=未选中)的信息。
然后,在保存的实例中添加此元素并通过 activity class 检索,使应用程序能够知道在重新创建 activity 之后选择了哪些视图。

在 onBindViewHolder 方法中添加的代码,它在适配器中 class

        if (selectedItemsArray != null) {
            if (selectedItemsArray[position]) {
                holder.itemView.setSelected(true);
                holder.mPhotoCheckBox.setChecked(true);
                holder.mPhotoCheckBox.setVisibility(View.VISIBLE);
            }
        }

对于代码的最后一部分,我们将选择应用到相应的视图,基于在保存 activity 之前选择了 items/views。 holer 对象包含我们可以执行选择的 itemViewmPhotoCheckBox 对象。