RecyclerView - 在Activity中获取位置而不是RecyclerViewAdapter

时间:2016-12-08 13:53:08

标签: android android-recyclerview android-viewholder

现在是我处理点击次数的第三天。我最初使用ListView,然后切换到RecyclerView。我已在android:onclick的每个控件上添加了row_layout个元素,我正在MainActivity处理这些元素:

public void MyMethod(View view) {}

在我原来的ListView实施中,我已经完成了setTag(position),可以通过在MyMethod内完成此操作:

Integer.parseInt(view.getTag().toString())

这很好用,没有问题。虽然现在我正在处理RecyclerView并被迫使用ViewHolder,但不提供setTag方法。搜索了2个小时后,我发现人们使用setTag这样:

holder.itemView.setTag(position)

这是可以接受的。虽然当我尝试使用以下行从MyMethod函数获取值时:

Integer.parseInt(view.getTag().toString())

应用程序崩溃。我已经阅读了适配器内部的onclick处理的几个实现,但是我必须使用MainActivity,因为我正在使用该活动独有的东西。

TL; DR我想以简单的方式将点击的行的位置发送到MainActivity

编辑:我为这个混乱道歉,因为我的主题不是很彻底。我有一个RecyclerView和一个适配器。适配器已链接到我的row_layout。这个row_layout xml有一个根LinearLayout。其中有一个TextView,另一个LinearLayout(有两个TextViews)和一个Button(为简单起见)。我不想像处理RecylerView那样处理ListView点击而受到影响。因此,我决定为每个控件添加android:onclick,然后将TextViewLinearLayout链接到单个方法并链接Button(以及将来的Button s)他们独特的方法。我缺少的是,我希望能够在MainActivity上告诉每个接收方法的位置。如果我必须链接来自适配器的所有内容并进入MainActivity到单个onclick处理程序,那就这样吧。虽然,我怎么知道哪个控件触发了点击?

编辑2:请求的布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:onClick="MyMethod"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:weightSum="1">
    <TextView
        android:id="@+id/letter"
        android:onClick="MyMethod"
        android:layout_width="60dp"
        android:layout_height="fill_parent"
        />
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:onClick="MyMethod"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/firstname"
            android:onClick="MyMethod"
            android:layout_width="fill_parent"
            android:layout_height="17dp" />
        <TextView
            android:id="@+id/longname"
            android:onClick="MyMethod"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
    <Button
        android:text="Test"
        android:onClick="OtherMethod"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:id="@+id/process"/>
</LinearLayout>

2 个答案:

答案 0 :(得分:10)

您可以通过在适配器内为itemclicklistener创建一个接口来实现此目的,然后您可以从onItemClickListener设置MainActivity

RecyclerViewAdapter内的某处,您需要以下内容:

private onRecyclerViewItemClickListener mItemClickListener;

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

    public interface onRecyclerViewItemClickListener {
        void onItemClickListener(View view, int position);
    }

然后在ViewHolder(我已经在我的适配器中添加内部类)中,您可以将侦听器应用于您希望用户单击的组件,如下所示:

class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public ImageView imageview;

        RecyclerViewHolder(View view) {
            super(view);
            this.imageview = (ImageView) view
                    .findViewById(R.id.image);
            imageview.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mItemClickListener != null) {
                mItemClickListener.onItemClickListener(v, getAdapterPosition());
            }
        }
    }

此示例显示onClickListener正在应用于ViewHolder内的图片。

recyclerView.setAdapter(adapter);// set adapter on recyclerview
            adapter.notifyDataSetChanged();// Notify the adapter
            adapter.setOnItemClickListener(new RecyclerViewAdapter.onRecyclerViewItemClickListener() {
                @Override
                public void onItemClickListener(View view, int position) { 
//perform click logic here (position is passed)
                    }
                });

要实现此代码,您应setOnItemClickListener MainActivity内的适配器,如上所示。

修改

因为View已传递到OnItemClickListener,您可以在侦听器内执行switch语句,以确保正确的逻辑正在执行到正确的组件。您需要做的就是从MyMethod函数中获取逻辑并将其复制并粘贴到您希望应用它的组件中。

示例:

recyclerView.setAdapter(adapter);// set adapter on recyclerview
                adapter.notifyDataSetChanged();// Notify the adapter
                adapter.setOnItemClickListener(new RecyclerViewAdapter.onRecyclerViewItemClickListener() {
                    @Override
                    public void onItemClickListener(View view, int position) { 
        Switch (view.getId()) {
            case R.id.letter:
               //logic for TextView with ID Letter here
            break;
            case R.id.firstname:
               //logic for TextView with ID firstname here
            break;
            ....
            //the same can be applied to other components in Row_Layout.xml
        }
                        }
                    });

您还需要更改ViewHolder内的内容。而不是将OnClickListener应用于ImageView,您需要像这样应用于整行:

 RecyclerViewHolder(View view) {
                super(view);
                this.imageview = (ImageView) view
                        .findViewById(R.id.image);
                view.setOnClickListener(this);
            }

编辑2

说明:

所以,每个RecyclerView。您需要三个组件,RecyclerViewRecyclerViewAdapterRecyclerViewHolder。这些是定义用户看到的实际组件(RecyclerView)和该视图中的项目的内容。适配器是将所有内容拼凑在一起并实现逻辑的地方。比尔菲利普斯在Big Nerd Ranch上发表文章RecyclerView Part 1: Fundamentals For ListView Experts很好地解释了这些组成部分的细节。

但为了进一步解释点击事件背后的逻辑,它基本上利用interface将信息从RecyclerViewAdapter传递到RecyclerViewHolderMainActivity }。因此,如果您遵循RecyclerView适配器的生命周期,它就会有意义。

适配器在MainActivity内初始化,然后将通过传递的信息调用适配器的构造函数。然后,组件将通过OnCreateViewHolder方法传递到适配器。这本身告诉适配器,你希望列表看起来如何。然后,需要单独初始化该布局中的组件,即ViewHolder发挥作用的位置。正如您在Activities中初始化的任何其他组件一样,您可以在ViewHolder中执行相同操作,但由于RecyclerViewAdapterViewHolder进行了膨胀,您可以愉快地使用它们在你的适配器内,如Zeeshan Shabbir所示。但是,对于此示例,您希望多个组件将各种逻辑应用于MainActivity类中的每个组件。

在这种情况下,我们将点击侦听器创建为全局变量(因此ViewHolderAdapter都可以访问)适配器的工作是通过创建Interface来确保监听器存在,您可以通过初始化监听器。

 public interface onRecyclerViewItemClickListener {
    void onItemClickListener(View view, int position);
 }

在您定义了接口要保存的信息(EG组件及其位置)之后,您可以创建一个适配器将调用以应用您的逻辑的函数。 Activity(与调用View.OnClickListener的方式相同),但通过创建setOnItemClickListener,您可以对其进行自定义。

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

此函数需要传递给它的onRecyclerViewItemClickListener变量,如MainActivity中所示。 new RecyclerViewAdapter.onRecyclerViewItemClickListener()在这种情况下,您之前使用内部方法创建的接口需要实现,因此

@Override
                public void onItemClickListener(View view, int position) {
                }

被调用。

此方案中的所有ViewHolder都会将信息(其自身和位置的组件)传递到onItemClickListener并附加了组件(onClick内部function)完成实际的点击功能。

如果您希望我以任何方式更新说明,请告诉我。

答案 1 :(得分:1)

我认为你很难处理ReceylerView上的多次点击,如果是这种情况,那么让我分享一下我项目中的代码片段。这就是我如何处理RecyclerView

中的点击
public class ExploreItemAdapter extends RecyclerView.Adapter<ExploreItemAdapter.ViewHolder> {
private WSResponseDTO<Data> wsResponseDTO;

public ExploreItemAdapter(WSResponseDTO<Data> wsResponseDTO) {
    this.wsResponseDTO = wsResponseDTO;
}

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

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.tvCompanyName.setText(wsResponseDTO.getData().getPosts().get(position).getStoreInfo().getStoreName());
    holder.tvBranchName.setText("(" + wsResponseDTO.getData().getPosts().get(position).getStoreInfo().getBranchName() + ")");
    holder.tvLikes.setText(wsResponseDTO.getData().getPosts().get(position).getPost().getFavoriteCount() + "");
    holder.tvShares.setText(wsResponseDTO.getData().getPosts().get(position).getPost().getShareCount() + "");
    holder.validity.setText(wsResponseDTO.getData().getPosts().get(position).getPost().getValidFrom() + "-" +
            wsResponseDTO.getData().getPosts().get(position).getPost().getValidTo());
    holder.sTime.setText(wsResponseDTO.getData().getPosts().get(position).getPost().getTime());
    holder.tvTitle.setText(wsResponseDTO.getData().getPosts().get(position).getPost().getHeading());
    holder.cardView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Toast.makeText(view.getContext(), "card is touched", Toast.LENGTH_SHORT).show();
            view.getContext().startActivity(new Intent(view.getContext(), ConsumerDetailOfferActivity.class).putExtra("post", wsResponseDTO.getData().getPosts().get(position)));
        }
    });
}

@Override
public int getItemCount() {
    return wsResponseDTO.getData().getPosts().size();
}

public class ViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.card_explore)
    CardView cardView;
    @BindView(R.id.tv_company_name)
    TextView tvCompanyName;
    @BindView(R.id.tv_branch_name)
    TextView tvBranchName;
    @BindView(R.id.tv_title)
    TextView tvTitle;
    @BindView(R.id.tv_like_count)
    TextView tvLikes;
    @BindView(R.id.tv_share_count)
    TextView tvShares;
    @BindView(R.id.tv_validity)
    TextView validity;
    @BindView(R.id.tv_sTime)
    TextView sTime;


    public ViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}
}

您可以将click侦听器设置为bindViewHolder()中的任何项目,就像我为cardView所做的那样。我希望这会对某些人有所帮助。