单击图像时如何更改ListView中的图像?
Posted
技术标签:
【中文标题】单击图像时如何更改ListView中的图像?【英文标题】:How to change an image in a ListView, when the image is clicked? 【发布时间】:2016-07-21 04:50:06 【问题描述】:编辑:我已经解决了这个问题,如果有兴趣,请看看我的回答,看看我是怎么做到的!
我目前在 android Studio 工作。我有一个 ListView 填充了几个项目。在这些项目中的每一个中都有一个带有“+”作为图像的 ImageButton。我想要做的是,每当单击该图像(不是整个 ListView 项目,只是图像)时,我希望那个“+”图像成为另一个图像。任何帮助将不胜感激,因为这一直是一个持续的问题!
这是我尝试用来实现此目的的当前代码:
final ImageButton movieSeen = (ImageButton convertView.findViewById(R.id.movieWatched);
movieSeen.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
movieSeen.setImageResource(R.drawable.ic_check_circle_black_24dp);
);
目前这确实会更新我正确单击的图像,但它也会更新尚未在屏幕上呈现的图像,因此当我向下滚动列表视图时,其他对象也会更改为 ic_check_circle_black_24dp。
我想要的很简单,我只是不知道如何实现它。我只想单击一个 ImageButton,它位于 ListView 上的一个项目内,并让该 ImageButton 更改其图像资源。
这是我要求的自定义数组适配器!
private class MovieScrollAdapter extends ArrayAdapter<Movie> //custom array adapter
private Context context;
private List<Movie> movies;
public MovieScrollAdapter(Context context, List<Movie> movies)
super(context, -1, movies);
this.context = context;
this.movies = movies;
if(this.movies.isEmpty())//if no results were returned after all processing, display a toast letting the user know
Toast.makeText(getApplicationContext(), R.string.no_matches, Toast.LENGTH_SHORT).show();
@Override
public View getView(final int position, View convertView, ViewGroup parent)
if (convertView == null)
LayoutInflater inflater = (LayoutInflater) context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.movie_layout, parent, false);
TextView title = (TextView) convertView.findViewById(R.id.title);
title.setText(movies.get(position).getTitle());
TextView plot = (TextView) convertView.findViewById(R.id.plot);
plot.setText(movies.get(position).getPlot());
TextView genre = (TextView) convertView.findViewById(R.id.genre);
genre.setText(movies.get(position).getGenre());
TextView metaScore = (TextView) convertView.findViewById(R.id.metascore);
if(movies.get(position).getMetaScore() == -1)//if the metaScore is set to -1, that means movie has not been rated, which by inference means it is not yet released
metaScore.setText(R.string.movie_not_released);
metaScore.setTextSize(TypedValue.COMPLEX_UNIT_SP, 9.5f);//smaller text so it fits without breaking anything
metaScore.setTextColor(getColor(R.color.colorAccent));
else
metaScore.setText(" " + Integer.valueOf(movies.get(position).getMetaScore()).toString() + " ");//using white space for minor formatting, instead of altering margins each time this is rendered
metaScore.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
//setting up a "highlighted" background to achieve metacritic square effect
Spannable spanText = Spannable.Factory.getInstance().newSpannable(metaScore.getText());
spanText.setSpan(new BackgroundColorSpan(getColor(R.color.metaScore)), 3, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
metaScore.setText(spanText);
metaScore.setTextColor(getColor(android.R.color.primary_text_dark));
ImageView image = (ImageView) convertView.findViewById(R.id.imageView);
new ImageDownloadTask((ImageView)image).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, movies.get(position).getPosterURL());//because there are several images to load here, we let these threads run parallel
title.setOnClickListener(new View.OnClickListener() //setting up a simple onClickListener that will open a link leading to more info about the movie in question!
@Override
public void onClick(View v)
Uri uri = Uri.parse(movies.get(position).getMovieURL());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
);
final ImageButton movieSeen = (ImageButton) convertView.findViewById(R.id.movieWatched);
movieSeen.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
movieSeen.setImageResource(R.drawable.ic_check_circle_black_24dp);
);
return convertView;
【问题讨论】:
显示你的适配器,我会给你一个解决方案 在这里查看我的答案。您需要在适配器中放置一个 else 条件。维护一些其他列表以跟踪单击了哪个项目。 ***.com/a/36327143/3145960 【参考方案1】:问题出在 ListView 上,视图被重用以节省内存并避免创建大量视图,因此当您更改视图时,它会在重用于显示另一个项目时保持状态。
例如,您有 100 个元素,您触摸第一个元素 ImageButton 并更改该按钮。也许屏幕上显示了列表的 5 个元素,而您更改了第一个元素。但是,如果您滚动到元素编号 15,则系统不会创建 15 个视图,而是采用您之前单击的第一个视图并更改内容。 因此,您希望有一个带有“+”ImageButton 图标的视图,但您看到另一个图标,这是因为您必须将视图状态保留在模型对象中,并在每次调用 'getView' 时设置状态。
发布您的列表适配器以查看如何实现。
更新:
现在我看到了你的适配器实现,我建议你在 Movie 类中添加一个 int 字段来保存你想在 ImageButton 上显示的资源 id。然后在onClickListener
中,您必须在此字段中设置您希望在单击时在视图上显示的资源,并调用notifyDataSetChanged()
。之后你必须在 getView() 里面做:
movieSeen.setImageResource(movies.get(position).getButtonImageResource());
【讨论】:
你是对的,但是使用 ListView frank 将无法仅在图像上设置点击侦听器(他说“每当单击该图像时(不是整个 ListView 项目,只是图像)”) 如果视图是ImageButton,在ImageButton上设置点击监听提供了预期的行为,所以他的点击监听的实现是可以的。【参考方案2】:使用 RecyclerView 并在您的视图持有者的 ImageButton 上设置 OnItemClickListener。
这已经回答了question 应该会有所帮助。
下面的改编代码来自这个漂亮的tutorial。将 ReciclerView 与这样的适配器一起使用将解决您的问题。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
private ArrayList<String> mDataset;
public class ViewHolder extends RecyclerView.ViewHolder
public ImageView imageView;
public TextView txtHeader;
public ViewHolder(View v)
super(v);
txtHeader = (TextView) v.findViewById(R.id.xxx);
imageView = (ImageView) v.findViewById(R.id.yyy);
public MyAdapter(ArrayList<String> myDataset)
mDataset = myDataset;
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position)
final String name = mDataset.get(position);
holder.txtHeader.setText(mDataset.get(position));
holder.imageView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// Do here what you need to change the image content
);
holder.itemView.setBackground(....); // Initialize your image content here...
//...
【讨论】:
【参考方案3】:这是我实现您想要的目标的建议:
-
在您的适配器中创建一个接口:
public interface YourInterface void selectedImage(int position,ImageView iamgeView);
-
在您刚刚创建的适配器中创建变量接口:
private YourInterface yourInterface;
让你的适配器构造函数像这样:
public YourAdapterConstructor(YourInterface yourInterface) this.yourInterface = yourInterface;
在您的 ImageView onClickListener 中:
final ImageButton movieSeen = (ImageButton) convertView.findViewById(R.id.movieWatched); movieSeen.setOnClickListener(new View.OnClickListener() @Override public void onClick(View v) yourInterface.selectedImage(position, imageView); );
最后在你的课堂活动中,实现 YourInterface 并在那里改变你的 ImageView:
@Override public void selectedImage(final int position,final ImageView imageView) //change your image view here
【讨论】:
我总是使用这种解决方法来让我的列表视图和我的活动相互交流,对我来说,当您将来想要更改或修改您的项目时也更容易【参考方案4】:我要感谢大家的支持。不幸的是,由于我的代码编写方式(相当混乱,并且没有太多考虑我的教授教我的内容),我无法让大多数这些解决方案发挥作用。然而,我确实找到了一个符合我自己的框架的解决方案。不幸的是,我无法重做整个适配器方法,或实现各种接口,这将导致我不得不为看似微不足道的事情重写大量代码。
因此,如果将来有人发现自己处于这种情况,这是我的解决方案:
在 Movie 类中,我添加了一个表示我的值的布尔值,以及一些 getter 和 setter:
private boolean watchedStatus;
public boolean hasSeen() return watchedStatus;
public void toggleWatchedStatus()
watchedStatus = !watchedStatus;
在 getView 方法中,我只是简单地获取 ImageButton 的引用,然后根据“hasSeen”返回的布尔值,我将 ImageResource 设置为以下两种状态之一:
@Override
public View getView(final int position, View convertView, ViewGroup parent)
ImageButton movieSeen = (ImageButton) convertView.findViewById(R.id.movieSeen);
if(movies.get(position).hasSeen())
movieSeen.setImageResource(R.drawable.ic_check_circle_black_24dp);
else
movieSeen.setImageResource(R.drawable.ic_add_circle_black_24dp);
接下来,我重写 OnClickListener,并使其每当单击按钮时,都会切换 Movie.java 类中的布尔值。这里的关键是使用 ArrayAdapter 的方法“notifyDataSetChanged()” 这完成了这个过程,并让 ListView 知道它应该更新自己:
final ImageButton movieSeenForClick = (ImageButton) convertView.findViewById(R.id.movieSeen);
movieSeen.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//movieSeenForClick.setImageResource(R.drawable.ic_check_circle_black_24dp);
movies.get(position).toggleWatchedStatus();
System.out.println(movies.get(position).hasSeen() + " ------- position: " + position);
notifyDataSetChanged();
);
再次感谢您花时间提供信息,其中很多确实将我引向正确的方向,我只需要按照我的代码结构正确使用这些信息。
【讨论】:
以上是关于单击图像时如何更改ListView中的图像?的主要内容,如果未能解决你的问题,请参考以下文章
Swift:如何在单击提交按钮时更改 UIButton 图像
VB中如何在ListView中添加ImageList中的图像
如何根据 android studio 中的 listview 项目点击更改活动图像和文本? java 或 kotlin