编辑:我已经解决了这个问题,如果有兴趣,请看看我的答案,看看我是怎么做到的!
我目前在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;
}
}
答案 0 :(得分:3)
问题在于ListView,视图正被重用以节省内存并避免创建大量视图,因此当您更改视图时,它会保留状态,同时重用它以显示另一个项目。 / p>
例如,您有100个元素,触摸第一个元素ImageButton并更改该按钮。也许在屏幕上显示列表的5个元素,并且您更改了第一个元素。但是,如果滚动到元素编号15,系统不会创建15个视图,而是使用之前单击的第一个视图并更改内容。 所以,你期望有一个&#34; +&#34; ImageButton图标但你看到另一个图标,因为你必须将视图状态保持在模型对象中,并且每次都设置状态&#39; getView&#39;被称为。
发布您的列表适配器以了解如何实施。
更新:
现在我看到你的适配器实现我建议你在Movie类中添加一个int字段来保存你想要在ImageButton上显示的资源ID。然后在onClickListener
内,您必须将要在视图点击时显示的资源设置为此字段,然后调用notifyDataSetChanged()
。之后你必须在getView()里面做:
movieSeen.setImageResource(movies.get(position).getButtonImageResource());
答案 1 :(得分:1)
使用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...
}
//...
}
答案 2 :(得分:0)
以下是我想要达到你想要的建议:
public interface YourInterface{ void selectedImage(int position,ImageView iamgeView); }
private YourInterface yourInterface;
并使你的适配器构造函数如下:
在ImageView onClickListener中public YourAdapterConstructor(YourInterface yourInterface){ this.yourInterface = yourInterface; }
:
final ImageButton movieSeen = (ImageButton) convertView.findViewById(R.id.movieWatched); movieSeen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { yourInterface.selectedImage(position, imageView); } });
然后最后在你的类活动中,实现你的接口并在那里改变你的ImageView:
@Override public void selectedImage(final int position,final ImageView imageView) { //change your image view here }
答案 3 :(得分:0)
我要感谢大家的支持。不幸的是,随着我的代码编写方式(相当混乱而且不太考虑我的教授教给我的东西),我无法使大多数这些解决方案起作用。但是,我确实找到了一个符合我自己的框架的解决方案。不幸的是,我无法重做我的整个适配器方法,或实现各种接口,这些接口会导致我必须重写大量的代码,看似微不足道。
所以,如果将来发现自己处于这种情况,这是我的解决方案:
在Movie类中,我添加了一个表示我的值的布尔值,以及一些getter和setter:
private boolean watchedStatus;
public boolean hasSeen() {return watchedStatus;}
public void toggleWatchedStatus(){
watchedStatus = !watchedStatus;
}
在getView方法中,我只是获取对ImageButton的引用,然后根据&#34; hasSeen,&#34;返回的布尔值。我将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的方法&#34; notifyDataSetChanged()&#34;这样就完成了这个过程,让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();
}
});
再次感谢您提供信息所花费的时间,其中很多确实引导我指向正确的方向,我只需要正确地使用我的代码构建方式的信息。