[英]How to change an image in a ListView, when the image is clicked?
編輯:我已經解決了這個問題,如果有興趣,請看看我的回答,看看我是如何做到的!
我目前在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;
}
}
問題出在ListView上,視圖被重用以節省內存並避免創建大量視圖,因此,當您更改視圖時,它會保留狀態,而視圖將被重用於顯示另一個項目。
例如,您有100個元素,您觸摸第一個元素ImageButton,然后該按鈕被更改。 也許在屏幕上顯示了列表的5個元素,而您更改了第一個。 但是,如果滾動到元素編號15,則系統不會創建15個視圖,而是會使用您之前單擊的第一個視圖並正在更改內容。 因此,您希望有一個帶有“ +” ImageButton圖標的視圖,但您會看到另一個圖標,這是因為您必須將視圖狀態保留在模型對象內,並在每次調用“ getView”時設置該狀態。
發布您的列表適配器以了解其實現方式。
更新:現在,我看到您的適配器實現,建議您在Movie類內添加一個int字段,以保存要在ImageButton上顯示的資源ID。 然后,必須在onClickListener
內將要在單擊時在視圖上顯示的資源設置為此字段,並調用notifyDataSetChanged()
。 之后,您必須在getView()中執行以下操作:
movieSeen.setImageResource(movies.get(position).getButtonImageResource());
使用RecyclerView並在視圖持有者內的ImageButton上設置OnItemClickListener。
這個已經回答的問題應該有所幫助。
下面的改編代碼來自這個不錯的教程 。 將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...
}
//...
}
這是我建議您實現的目標:
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 }
我要感謝大家的支持。 不幸的是,用我的代碼編寫方式(相當混亂,並且沒有過多考慮我的教授教給我的東西),我無法使大多數這些解決方案起作用。 但是,我確實找到了一個符合我自己的框架的解決方案。 不幸的是,我無法重做我的整個適配器方法,或者無法實現各種接口,這將導致我不得不為看似微不足道的某些內容重寫大量代碼。
因此,如果將來有人遇到這種情況,這是我的解決方案:
在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();
}
});
再次感謝您提供信息所花的時間,其中很多確實確實引導了我正確的方向,我只需要按照代碼的結構方式正確使用信息即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.