从适配器外部控制 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中修改的代码(activity
class,其中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);
}
在onSaveInstanceState
和onRestoreInstanceState
方法中,我添加了用于保存和恢复"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
对象包含我们可以执行选择的 itemView
和 mPhotoCheckBox
对象。
一般
我想从 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中修改的代码(activity
class,其中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);
}
在onSaveInstanceState
和onRestoreInstanceState
方法中,我添加了用于保存和恢复"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
对象包含我们可以执行选择的 itemView
和 mPhotoCheckBox
对象。