为什么有时不调用我的RecyclerView.ViewHolder的onClick方法?

问题描述 投票:1回答:2

我的ViewHolder实施View.OnClickListener,因为它在this answer建议。除此之外,我仔细检查了我的适配器类与官方文档中的示例类似。

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    private View view;

    public ViewHolder(View view) {
        super(view);
        view.setOnClickListener(this);
        this.view = view;
    }

    public View getView() {
        return view;
    }

    @Override
    public void onClick(View view) {
        Context context = view.getContext();
        Intent intent = new Intent(context, DetailsActivity.class);
        context.startActivity(intent);
    }
}

但是,如果我正在测试我的应用程序,我会观察到这种奇怪的行为:如果我正在点击启动时可见的行,则会按预期执行onClick方法。现在我向下滚动,使其他行可见。我点击某个地方没有任何反应,第二次点击 - 如果它在同一行或不同 - 再次工作。如果我回滚到顶部同样的事情发生,我必须点击两次以获得我的onClick方法调用。

任何想法为什么会这样?

编辑:完整代码,现在在onBindViewHolder中设置监听器:

public class ComposersAdapter extends RecyclerView.Adapter<ComposersAdapter.ViewHolder> {

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private View view;

        public ViewHolder(View view) {
            super(view);
            this.view = view;
        }

        public View getView() {
            return view;
        }
    }

    private final String EXTRA_COMPOSER_ID = "composerId";
    private List<Composer> composers;

    public ComposersAdapter(List<Composer> composers) {
        this.composers = composers;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        View view = holder.getView();
        TextView textView = view.findViewById(R.id.textView);
        textView.setText(composers.get(position).getTitle());
        holder.getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Context context = view.getContext();
                Intent intent = new Intent(context, ComposerActivity.class);
                intent.putExtra(EXTRA_COMPOSER_ID, holder.getAdapterPosition());
                context.startActivity(intent);
            }
        });
    }

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

更新:问题似乎与RecyclerView所在活动的工具栏相关联。我设置了app:layout_scrollFlags="scroll|enterAlways",如果我删除了问题就不再存在了。也许这与捕获触摸事件的工具栏有关?我没有经验足以自己检查。

java android
2个回答
1
投票

onBindViewHolder(RecyclerView.ViewHolder holder, int position)中分配单击侦听器。

onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 holder.itemView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
                  // start some activity
             }
});
}

在绑定视图持有者是指视图正确绑定到适配器并且此处可以使用视图的各个实例。

holder.itemView 

将为您提供viewHolder的视图实例的引用。因此,您不会像ViewHolder中的方法那样使用getView()


0
投票

ViewHolder描述了一个项目视图和有关其在RecyclerView中的位置的元数据。

RecyclerView.Adapter实现应该是ViewHolder的子类,并添加用于缓存潜在昂贵的findViewById(int)结果的字段。

我在项目中有类似的问题,我已经做了一些示例,你可以看看这可能有助于解决你的问题。

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder> {

    private List<Ad> adsList= new ArrayList<>();
    private Context mContext;
    static OnItemClickListener mItemClickListener;
    //Provide a reference to the views for each data item
    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        @BindView(R.id.mainHolder)
        public RelativeLayout placeHolder;

        @BindView(R.id.tv_ad_name)
        public TextView tvAdName;

        @BindView(R.id.tv_no_of_rating)
        public TextView tvNoOfRating;

        @BindView(R.id.tv_minOs)
        public TextView tvMinOs;

        @BindView(R.id.iv_product_thumbnail)
        public ImageView ivPrductThumbnail;


        public ViewHolder(View v) {
            super(v);
            ButterKnife.bind(this, v);
            placeHolder.setOnClickListener(this);
        }
        @Override
        public void onClick(View v) {
            if (mItemClickListener != null) {
                mItemClickListener.onItemClick(itemView, getPosition());
            }
        }

    }

    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }

    public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
        this.mItemClickListener = mItemClickListener;
    }

    //Provide a suitable constructor
    public ProductAdapter(Context context){
        mContext = context;
    }
    public void setAd(List<Ad> aList) {
        adsList.clear();
        adsList.addAll(aList);
        notifyDataSetChanged();
    }
    //Create new views (invoked by the layout manager)
    @Override
    public ProductAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        //Creating a new view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_list_items,parent,false);

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    //Replace the contents of a view (invoked by the layout manager
    @Override
    public void onBindViewHolder(ProductAdapter.ViewHolder holder, int position) {

        // - replace the contents of the view with that element

        Ad ad = adsList.get(position);
        holder.tvAdName.setText(ad.getProductName());
        holder.tvNoOfRating.setText(ad.getNumberOfRatings());
        holder.tvMinOs.setText(ad.getMinOSVersion());

        Glide.with(mContext)
                .load(ad.getProductThumbnail())
                .into(holder.ivPrductThumbnail);
    }

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

完整可行的代码链接here。和link2

编辑:您可能必须在ViewHolder类中声明textview。

© www.soinside.com 2019 - 2024. All rights reserved.