如何突出显示 Recycler View 的选定项目?
how to highlight the selected Item of Recycler View?
我有一个 Recycler 视图,其中包含从内部存储加载的图像。
我想在单击时突出显示所选项目。
我尝试了很多东西,但没有用。
实际上,我需要的是当我单击 Recycler View 中的任何项目时,该项目必须进入我的 ArrayList 并且它也应该被突出显示,并且当我单击或说取消选择时它必须再次变得正常。
这是我的代码:
public class Images extends Fragment {
private List<ImageHolder> imageList;
Cursor imageCursor;
RecyclerView recyclerView;
MyImageAdapter adapter;
ActionButton clickButton;
List<String> listofImages;
List<Integer> pos;
int columnIndex;
StringBuilder stringBuilder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootlayout = inflater.inflate(R.layout.image, container, false);
listofImages=new ArrayList<String>();
pos=new ArrayList<Integer>();
stringBuilder=new StringBuilder();
ContentResolver imageResolver = getActivity().getContentResolver();
Uri imageUri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String projection[]={MediaStore.Images.Thumbnails._ID,MediaStore.Images.Media.TITLE};
imageCursor = getActivity().managedQuery(imageUri, projection, null, null, null);
clickButton= (ActionButton) rootlayout.findViewById(R.id.action_button);
recyclerView = (RecyclerView) rootlayout.findViewById(R.id.recycler_view_image);
adapter = new MyImageAdapter(getActivity(), getImageList());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(),recyclerView,new RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, int position) {
TextView tv= (TextView) view.findViewById(R.id.list_text_all);
int flag=0;
String[] projection = {MediaStore.Images.Media.DATA};
imageCursor = getActivity().managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
columnIndex = imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
imageCursor.moveToPosition(position);
// Get image filename
String imagePath = imageCursor.getString(columnIndex);
if (listofImages.contains(imagePath)){
Log.d("Contains Test","Yes");
listofImages.remove(imagePath);
pos.remove(position);
} else {
listofImages.add(imagePath);
pos.add(position);
Log.d("Contains Test","No");
}
String s=listofImages.size()+" "+imagePath;
Log.d("Inserted",s);
}
@Override
public void onLongClick(View view, int position) {}
}));
clickButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i=0;i<listofImages.size();i++){
stringBuilder.append(listofImages.get(i)+"\n");
}
Toast.makeText(getActivity(),stringBuilder,Toast.LENGTH_LONG).show();
}
});
return rootlayout;
}
public List<ImageHolder> getImageList() {
imageList=new ArrayList<ImageHolder>();
if(imageCursor!=null && imageCursor.moveToFirst()){
int titleColumn = imageCursor.getColumnIndex
(android.provider.MediaStore.Images.Media.TITLE);
int idColumn = imageCursor.getColumnIndex
(android.provider.MediaStore.Images.Media._ID);
do {
ImageHolder img=new ImageHolder();
img.id=imageCursor.getLong(idColumn);
img.title=imageCursor.getString(titleColumn);
img.iconid= imageCursor.getInt(idColumn);
imageList.add(img);
}
while (imageCursor.moveToNext());
}
return imageList;
}
}
这是我的适配器Class:
public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> {
Context context;
private LayoutInflater inflater;
List<ImageHolder> data= Collections.emptyList();
private ClickListener clickListener;
int width,height;
public MyImageAdapter(Context context, List<ImageHolder> data1) {
inflater = LayoutInflater.from(context);
this.data=data1;
this.context=context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.all_row, parent, false);
MyViewHolder holder=new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
try{
ImageHolder current=data.get(position);
holder.title.setText(current.title);
Log.d("Imageid:"+current.iconid,"");
Uri IMAGE_URI = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + current.iconid);
Bitmap bitmap = Bitmap.createScaledBitmap(decodeUri(IMAGE_URI), 200, 200, true);
holder.img.setImageBitmap(bitmap);
}
catch(Exception e){}
}
public void deleteRecyclerData(int position){
data.remove(position);
notifyItemRemoved(position);
}
private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(
context.getContentResolver().openInputStream(selectedImage), null, o);
final int REQUIRED_SIZE = 100;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(
context.getContentResolver().openInputStream(selectedImage), null, o2);
}
@Override
public int getItemCount() {
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView title;
// TextView artist;
ImageView img;
CheckBox checkBox;
public MyViewHolder(View itemView) {
super(itemView);
title= (TextView) itemView.findViewById(R.id.list_text_all);
img= (ImageView) itemView.findViewById(R.id.list_image_all);
img.setOnClickListener(this);
}
@Override
public void onClick(View v) {}
}
public interface ClickListener{
public void itemClicked(View view, int position);
}
}
RecyclerView 中没有像 ListView 和 GridView 这样的选择器,但你可以尝试下面的方法,它对我有用
如下所示创建一个选择器可绘制对象
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="@color/blue" />
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>
然后将此可绘制对象设置为 RecyclerView 行布局的背景
android:background="@drawable/selector"
你可以使用一个StateListDrawable来达到你想要的效果。
例子
在您的 drawable
目录中创建一个新的 Drawable 资源文件,内容如下:
selector_row.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Color when the row is selected -->
<item android:drawable="@android:color/darker_gray" android:state_pressed="false" android:state_selected="true" />
<!-- Standard background color -->
<item android:drawable="@android:color/white" android:state_selected="false" />
</selector>
现在只需使用此 StateListDrawable
作为 RecyclerView
行布局中的背景
row_recyclerview.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_row">
<!-- row content -->
</RelativeLayout>
现在,一旦调用适配器中的 onClick()
方法,您只需执行以下操作:
// myBackground is the RelativeLayout root of your row
myBackground.setSelected(true);
只要您调用 myBackground.setSelected(false)
,行的背景就会有颜色(在本例中为 darker_gray)。当然,您应该创建一个 SparseBooleanArray,例如,为了知道哪一行被选中,哪一行没有被选中,因为这些行在滚动时会被重用。
编辑:记住所选项目
SparseBooleanArray 背后的想法是记住选择的项目。以下是有关如何使用它的示例:
public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> {
private SparseBooleanArray selectedItems;
// Other stuff [...]
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
// Set the selected state of the row depending on the position
holder.myBackground.setSelected(selectedItems.get(position, false));
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@Override
public void onClick(View v) {
// Save the selected positions to the SparseBooleanArray
if (selectedItems.get(getAdapterPosition(), false)) {
selectedItems.delete(getAdapterPosition());
myBackground.setSelected(false);
}
else {
selectedItems.put(getAdapterPosition(), true);
myBackground.setSelected(true);
}
}
}
}
如果您设法使用 Obto 或 AndroidRx 等可观察模式风格,您可以按照上面解释的如何突出显示背景,并且对于每个 viewHolder 的 itemView,您可以订阅可观察对象并在它与您的分离时取消订阅recyclerview 就像我在这里做的那样:
顺便说一句,为了快速演示,我的 itemView 使用的是 linearLayout,因此很容易将背景颜色设置为黄色。
您可以将此添加到您的 row_item.xml
android:clickable="true"
android:background="?attr/selectableItemBackground"
例如:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:background="?attr/selectableItemBackground"
<!-- row content -->
如果 android 版本是 Lolipop 或更高版本,选择器带有波纹。以及其他版本的亮点。希望对你有帮助
我已经尝试了几个小时的几种方法,这是我提出的两种解决方案。 两种解决方案 假设我的 RecyclerView
声明如下:
activity.xml
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
这里没什么特别的,只是一个常规的 RecyclerView
声明。现在让我们看看其他文件,从最简单可行的解决方案开始。
第一个解决方案(仅XML)
layout/item.xml
项目根 ViewGroup
中的两个重要属性是 background
和 clickable
。
<?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:background="@drawable/selector_item"
android:clickable="true"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:padding="16dp">
...
</LinearLayout>
drawable/selector_item.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/background_item_pressed"
android:state_pressed="true"
/>
<item
android:drawable="@drawable/background_item"
/>
</selector>
第二种解法(XML + Java)
item.xml
此处没有 background
或 clickable
属性。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:padding="16dp">
...
</LinearLayout>
Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnTouchListener(itemTouchListener);
}
}
...
private View.OnTouchListener itemTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setBackgroundResource(R.drawable.background_item_event_pressed);
break;
case MotionEvent.ACTION_CANCEL:
// CANCEL triggers when you press the view for too long
// It prevents UP to trigger which makes the 'pressed' background permanent which isn't what we want
case MotionEvent.ACTION_OUTSIDE:
// OUTSIDE triggers when the user's finger moves out of the view
case MotionEvent.ACTION_UP:
v.setBackgroundResource(R.drawable.background_item_event);
break;
default:
break;
}
return true;
}
};
...
}
我强烈建议使用第一种解决方案,因为它更易于维护且功能更强大,因为它还允许您添加涟漪效应(在 drawable/background_item...
XML 文件中),我认为这不是'解决方案 2 不可能。
此解决方案更像是 IOS 中的 tableView 的交互式外观。它会突出显示然后取消突出显示单元格。
@Override
public void onBindViewHolder(Cell holder, final int position) {
if(requests != null) {
holder.setView(requests.get(position), context);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
Logs.print("In OnClickListener", position + " selected");
}
});
holder.itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Logs.print("In Touch Handler", "A press has started");
v.setSelected(true);
break;
case MotionEvent.ACTION_UP:
Logs.print("In Touch Handler", "A press has been completed");
v.setSelected(false);
break;
case MotionEvent.ACTION_CANCEL:
Logs.print("In Touch Handler", "gesture aborted");
v.setSelected(false);
break;
}
return true;
}
});
}
}
您可以在适配器外使用此代码
LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager();
View itemSelected = RvLayoutManager.findViewByPosition(position);
itemSelected.setBackgroundColor(Color.Red);
您应该创建一个具有 android:state_focused="true"
属性的可绘制选择器,如下所示
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@color/colorAccent"
android:state_focused="true" />
</selector>
</item>
</ripple>
然后将此可绘制对象设置为 RecyclerView 行布局的背景
android:background="@drawable/selector"
我有一个 Recycler 视图,其中包含从内部存储加载的图像。 我想在单击时突出显示所选项目。 我尝试了很多东西,但没有用。 实际上,我需要的是当我单击 Recycler View 中的任何项目时,该项目必须进入我的 ArrayList 并且它也应该被突出显示,并且当我单击或说取消选择时它必须再次变得正常。 这是我的代码:
public class Images extends Fragment {
private List<ImageHolder> imageList;
Cursor imageCursor;
RecyclerView recyclerView;
MyImageAdapter adapter;
ActionButton clickButton;
List<String> listofImages;
List<Integer> pos;
int columnIndex;
StringBuilder stringBuilder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootlayout = inflater.inflate(R.layout.image, container, false);
listofImages=new ArrayList<String>();
pos=new ArrayList<Integer>();
stringBuilder=new StringBuilder();
ContentResolver imageResolver = getActivity().getContentResolver();
Uri imageUri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String projection[]={MediaStore.Images.Thumbnails._ID,MediaStore.Images.Media.TITLE};
imageCursor = getActivity().managedQuery(imageUri, projection, null, null, null);
clickButton= (ActionButton) rootlayout.findViewById(R.id.action_button);
recyclerView = (RecyclerView) rootlayout.findViewById(R.id.recycler_view_image);
adapter = new MyImageAdapter(getActivity(), getImageList());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(),recyclerView,new RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, int position) {
TextView tv= (TextView) view.findViewById(R.id.list_text_all);
int flag=0;
String[] projection = {MediaStore.Images.Media.DATA};
imageCursor = getActivity().managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
columnIndex = imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
imageCursor.moveToPosition(position);
// Get image filename
String imagePath = imageCursor.getString(columnIndex);
if (listofImages.contains(imagePath)){
Log.d("Contains Test","Yes");
listofImages.remove(imagePath);
pos.remove(position);
} else {
listofImages.add(imagePath);
pos.add(position);
Log.d("Contains Test","No");
}
String s=listofImages.size()+" "+imagePath;
Log.d("Inserted",s);
}
@Override
public void onLongClick(View view, int position) {}
}));
clickButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i=0;i<listofImages.size();i++){
stringBuilder.append(listofImages.get(i)+"\n");
}
Toast.makeText(getActivity(),stringBuilder,Toast.LENGTH_LONG).show();
}
});
return rootlayout;
}
public List<ImageHolder> getImageList() {
imageList=new ArrayList<ImageHolder>();
if(imageCursor!=null && imageCursor.moveToFirst()){
int titleColumn = imageCursor.getColumnIndex
(android.provider.MediaStore.Images.Media.TITLE);
int idColumn = imageCursor.getColumnIndex
(android.provider.MediaStore.Images.Media._ID);
do {
ImageHolder img=new ImageHolder();
img.id=imageCursor.getLong(idColumn);
img.title=imageCursor.getString(titleColumn);
img.iconid= imageCursor.getInt(idColumn);
imageList.add(img);
}
while (imageCursor.moveToNext());
}
return imageList;
}
}
这是我的适配器Class:
public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> {
Context context;
private LayoutInflater inflater;
List<ImageHolder> data= Collections.emptyList();
private ClickListener clickListener;
int width,height;
public MyImageAdapter(Context context, List<ImageHolder> data1) {
inflater = LayoutInflater.from(context);
this.data=data1;
this.context=context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.all_row, parent, false);
MyViewHolder holder=new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
try{
ImageHolder current=data.get(position);
holder.title.setText(current.title);
Log.d("Imageid:"+current.iconid,"");
Uri IMAGE_URI = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + current.iconid);
Bitmap bitmap = Bitmap.createScaledBitmap(decodeUri(IMAGE_URI), 200, 200, true);
holder.img.setImageBitmap(bitmap);
}
catch(Exception e){}
}
public void deleteRecyclerData(int position){
data.remove(position);
notifyItemRemoved(position);
}
private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(
context.getContentResolver().openInputStream(selectedImage), null, o);
final int REQUIRED_SIZE = 100;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(
context.getContentResolver().openInputStream(selectedImage), null, o2);
}
@Override
public int getItemCount() {
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView title;
// TextView artist;
ImageView img;
CheckBox checkBox;
public MyViewHolder(View itemView) {
super(itemView);
title= (TextView) itemView.findViewById(R.id.list_text_all);
img= (ImageView) itemView.findViewById(R.id.list_image_all);
img.setOnClickListener(this);
}
@Override
public void onClick(View v) {}
}
public interface ClickListener{
public void itemClicked(View view, int position);
}
}
RecyclerView 中没有像 ListView 和 GridView 这样的选择器,但你可以尝试下面的方法,它对我有用
如下所示创建一个选择器可绘制对象
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="@color/blue" />
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>
然后将此可绘制对象设置为 RecyclerView 行布局的背景
android:background="@drawable/selector"
你可以使用一个StateListDrawable来达到你想要的效果。
例子
在您的 drawable
目录中创建一个新的 Drawable 资源文件,内容如下:
selector_row.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Color when the row is selected -->
<item android:drawable="@android:color/darker_gray" android:state_pressed="false" android:state_selected="true" />
<!-- Standard background color -->
<item android:drawable="@android:color/white" android:state_selected="false" />
</selector>
现在只需使用此 StateListDrawable
作为 RecyclerView
row_recyclerview.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_row">
<!-- row content -->
</RelativeLayout>
现在,一旦调用适配器中的 onClick()
方法,您只需执行以下操作:
// myBackground is the RelativeLayout root of your row
myBackground.setSelected(true);
只要您调用 myBackground.setSelected(false)
,行的背景就会有颜色(在本例中为 darker_gray)。当然,您应该创建一个 SparseBooleanArray,例如,为了知道哪一行被选中,哪一行没有被选中,因为这些行在滚动时会被重用。
编辑:记住所选项目
SparseBooleanArray 背后的想法是记住选择的项目。以下是有关如何使用它的示例:
public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> {
private SparseBooleanArray selectedItems;
// Other stuff [...]
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
// Set the selected state of the row depending on the position
holder.myBackground.setSelected(selectedItems.get(position, false));
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@Override
public void onClick(View v) {
// Save the selected positions to the SparseBooleanArray
if (selectedItems.get(getAdapterPosition(), false)) {
selectedItems.delete(getAdapterPosition());
myBackground.setSelected(false);
}
else {
selectedItems.put(getAdapterPosition(), true);
myBackground.setSelected(true);
}
}
}
}
如果您设法使用 Obto 或 AndroidRx 等可观察模式风格,您可以按照上面解释的如何突出显示背景,并且对于每个 viewHolder 的 itemView,您可以订阅可观察对象并在它与您的分离时取消订阅recyclerview 就像我在这里做的那样:
顺便说一句,为了快速演示,我的 itemView 使用的是 linearLayout,因此很容易将背景颜色设置为黄色。
您可以将此添加到您的 row_item.xml
android:clickable="true"
android:background="?attr/selectableItemBackground"
例如:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:background="?attr/selectableItemBackground"
<!-- row content -->
如果 android 版本是 Lolipop 或更高版本,选择器带有波纹。以及其他版本的亮点。希望对你有帮助
我已经尝试了几个小时的几种方法,这是我提出的两种解决方案。 两种解决方案 假设我的 RecyclerView
声明如下:
activity.xml
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
这里没什么特别的,只是一个常规的 RecyclerView
声明。现在让我们看看其他文件,从最简单可行的解决方案开始。
第一个解决方案(仅XML)
layout/item.xml
项目根 ViewGroup
中的两个重要属性是 background
和 clickable
。
<?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:background="@drawable/selector_item"
android:clickable="true"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:padding="16dp">
...
</LinearLayout>
drawable/selector_item.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/background_item_pressed"
android:state_pressed="true"
/>
<item
android:drawable="@drawable/background_item"
/>
</selector>
第二种解法(XML + Java)
item.xml
此处没有 background
或 clickable
属性。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:padding="16dp">
...
</LinearLayout>
Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnTouchListener(itemTouchListener);
}
}
...
private View.OnTouchListener itemTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setBackgroundResource(R.drawable.background_item_event_pressed);
break;
case MotionEvent.ACTION_CANCEL:
// CANCEL triggers when you press the view for too long
// It prevents UP to trigger which makes the 'pressed' background permanent which isn't what we want
case MotionEvent.ACTION_OUTSIDE:
// OUTSIDE triggers when the user's finger moves out of the view
case MotionEvent.ACTION_UP:
v.setBackgroundResource(R.drawable.background_item_event);
break;
default:
break;
}
return true;
}
};
...
}
我强烈建议使用第一种解决方案,因为它更易于维护且功能更强大,因为它还允许您添加涟漪效应(在 drawable/background_item...
XML 文件中),我认为这不是'解决方案 2 不可能。
此解决方案更像是 IOS 中的 tableView 的交互式外观。它会突出显示然后取消突出显示单元格。
@Override
public void onBindViewHolder(Cell holder, final int position) {
if(requests != null) {
holder.setView(requests.get(position), context);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
Logs.print("In OnClickListener", position + " selected");
}
});
holder.itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Logs.print("In Touch Handler", "A press has started");
v.setSelected(true);
break;
case MotionEvent.ACTION_UP:
Logs.print("In Touch Handler", "A press has been completed");
v.setSelected(false);
break;
case MotionEvent.ACTION_CANCEL:
Logs.print("In Touch Handler", "gesture aborted");
v.setSelected(false);
break;
}
return true;
}
});
}
}
您可以在适配器外使用此代码
LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager();
View itemSelected = RvLayoutManager.findViewByPosition(position);
itemSelected.setBackgroundColor(Color.Red);
您应该创建一个具有 android:state_focused="true"
属性的可绘制选择器,如下所示
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@color/colorAccent"
android:state_focused="true" />
</selector>
</item>
</ripple>
然后将此可绘制对象设置为 RecyclerView 行布局的背景
android:background="@drawable/selector"