簡體   English   中英

單擊圖像時如何在ListView中更改圖像?

[英]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...

}

//...

}

這是我建議您實現的目標:

  1. 在適配器中創建接口:
 public interface YourInterface{ void selectedImage(int position,ImageView iamgeView); } 
  1. 在剛創建的適配器中創建變量接口:
 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM