RecyclerView项onClickListener在第一次点击时不起作用,但在第二次点击时起作用

时间:2018-05-14 15:33:06

标签: android android-recyclerview onclicklistener

适配器

public class MoviesAdapter extends 
RecyclerView.Adapter<MoviesAdapter.MoviesViewHolder> {
private static final String baseMovieUrl = "http://image.tmdb.org/t/p/w500";
private ArrayList<Movie> movies;
private Context context;

public MoviesAdapter(ArrayList<Movie> movies, Context context) {
    this.movies = movies;
    this.context = context;
}

@NonNull
@Override
public MoviesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    return new MoviesViewHolder(layoutInflater.inflate(R.layout.movie_square, parent, false));
}

@Override
public void onBindViewHolder(@NonNull MoviesViewHolder holder, int position) {
    holder.setData(position);

}


@Override
public int getItemCount() {
    return movies.size();
}


public class MoviesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private ConstraintLayout movieConstraint;
    private TextView movieName;
    private TextView movieRate;
    private ImageView moviePoster;

    public MoviesViewHolder(View itemView) {
        super(itemView);
        movieConstraint = itemView.findViewById(R.id.movie_holder_constraints);
        movieName = itemView.findViewById(R.id.movie_name_tv);
        movieRate = itemView.findViewById(R.id.movie_rating_tv);
        moviePoster = itemView.findViewById(R.id.movie_iv);
        movieConstraint.setOnClickListener(this);

    }

    public void setData(int position) {
        movieConstraint.setTag(position);
        movieName.setText(movies.get(position).getMovieName());
        movieRate.setText(movies.get(position).getMovieRating() + "");
        if (!Objects.equals(movies.get(position).getMovieUrl(), "") && movies.get(position).getMovieUrl() != null) {
            Glide.with(moviePoster).load
                    (baseMovieUrl + movies.get(position).getMovieUrl())
                    .into(moviePoster);
        } else Log.i("No url!", "No url!");
    }

    @Override
    public void onClick(View view) {
        int pos = (int) view.getTag();
        view.setEnabled(false);
        changeActivity(pos);
        view.setEnabled(true);    // TODO Find a way to prevent 2 acctivites to open simultaniously
    }


    private void changeActivity(int pos) {
        Movie movie = movies.get(pos);
        Intent intent = new Intent(context, MovieInfo.class);
        intent.putExtra("movie", movie);
        ActivityOptionsCompat options = ActivityOptionsCompat.
                makeSceneTransitionAnimation((Activity) context, moviePoster, "profile");
        context.startActivity(intent, options.toBundle());
    }
}
}

和xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/movie_holder_constraints"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp">

<android.support.v7.widget.CardView
    android:id="@+id/movie_cv"
    android:layout_width="185dp"
    android:layout_height="250dp"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:focusable="false"
    android:focusableInTouchMode="false"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/inside_movie_constraints"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="false"
        android:focusableInTouchMode="false"
        >

        <ImageView
            android:id="@+id/movie_iv"
            android:layout_width="185dp"
            android:layout_height="180dp"
            android:scaleType="fitXY"
            android:focusable="false"
            android:focusableInTouchMode="false"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@mipmap/ic_launcher" />

        <TextView
            android:id="@+id/movie_rating_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="2dp"
            android:text="9.5"
            android:textColor="@color/colorAccent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/movie_name_tv"
            app:layout_constraintVertical_bias="1.0" />

        <TextView
            android:id="@+id/movie_name_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="Guardian's Of The Galaxy"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintHorizontal_weight="1"
            android:gravity="center"
            android:includeFontPadding="false"
            app:layout_constraintTop_toBottomOf="@+id/movie_iv" />
    </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>

单击recyclelerView中的项目时,在单击另一个时间调用该函数后,它将不会打开该活动或调用OnClickListener。 滚动也可以让我点击这些项目。

我听说将foucsable改为false可以解决这个问题,但正如你在xml中看到的那样,它并没有。

编辑适配器: 我将onClick更改为onBindViewHolder,它修复了问题,虽然我觉得这样做不是正确的方法。 你怎么说?

package com.example.galzaid.movies;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.Objects;

public class MoviesAdapter extends 
RecyclerView.Adapter<MoviesAdapter.MoviesViewHolder> implements 
View.OnClickListener {
private static final String baseMovieUrl = "http://image.tmdb.org/t/p/w500";
private ArrayList<Movie> movies;
private Context context;

public MoviesAdapter(ArrayList<Movie> movies, Context context) {
    this.movies = movies;
    this.context = context;
}

@NonNull
@Override
public MoviesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    return new MoviesViewHolder(layoutInflater.inflate(R.layout.movie_square, parent, false));
}

@Override
public void onBindViewHolder(@NonNull MoviesViewHolder holder, int position) {
    holder.setData(position);
    holder.itemView.setOnClickListener(this);
    holder.getAdapterPosition();
}


@Override
public int getItemCount() {
    return movies.size();
}

@Override
public void onClick(View view) {
    ImageView moviePoster = view.findViewById(R.id.movie_iv);
    changeActivity((int) view.getTag(), moviePoster);
}

private void changeActivity(int pos, ImageView moviePoster) {
    Movie movie = movies.get(pos);
    Intent intent = new Intent(context, MovieInfo.class);
    intent.putExtra("movie", movie);
    ActivityOptionsCompat options = ActivityOptionsCompat.
            makeSceneTransitionAnimation((Activity) context, moviePoster, "profile");
    context.startActivity(intent, options.toBundle());
}


public class MoviesViewHolder extends RecyclerView.ViewHolder {
    private ConstraintLayout movieConstraint;
    private TextView movieName;
    private TextView movieRate;
    private ImageView moviePoster;

    public MoviesViewHolder(View itemView) {
        super(itemView);
        movieConstraint = itemView.findViewById(R.id.movie_holder_constraints);
        movieName = itemView.findViewById(R.id.movie_name_tv);
        movieRate = itemView.findViewById(R.id.movie_rating_tv);
        moviePoster = itemView.findViewById(R.id.movie_iv);

    }

    public void setData(int position) {
        movieConstraint.setTag(position);
        movieName.setText(movies.get(position).getMovieName());
        movieRate.setText(movies.get(position).getMovieRating() + "");
        if (!Objects.equals(movies.get(position).getMovieUrl(), "") && movies.get(position).getMovieUrl() != null) {
            Glide.with(moviePoster).load
                    (baseMovieUrl + movies.get(position).getMovieUrl())
                    .into(moviePoster);
        } else Log.i("No url!", "No url!");
    }
}
}

2 个答案:

答案 0 :(得分:0)

在绑定方法中设置OnClickListener,在您的情况下为public void setData(int position)

RecyclerView正如其名称所示,正在重用其创建的视图,因此对于每个项目,您应该从一开始就设置所有信息,包括onClick侦听器

这应该可以解决您的问题,并且您可以使用setTag来区分视图

避免在ViewHolder构造函数中设置onClick侦听器。

答案 1 :(得分:0)

我相信你的问题就在这一行

movieConstraint.setOnClickListener(this);

您不应将其设置为ConstraintLayout,将上述行更改为此

itemView.setOnClickListener(this);

onClickListener构造函数中设置ViewHolder并没有错。

修改

为了获得onClick中的排名,您可以使用getAdapterPosition()方法。