简体   繁体   中英

How to do you implement a recyclerview onClick in a Fragment?

My question is similar to this one.

Best approach to communicate between Fragment/Activity and RecyclerView.Adapter?

I know how to implement an onClickListener, an Interface and an OnItemSelected method in the corresponding activity when the user clicks on a button in a Fragment. I have a fragment with an array list. By clicking on each item in the array list in the fragment, an ExoPlayer will open in a new activity or a fragment. As I understand it, onItemClickListener doesn't work with Recyclerview. How do I set the onClick method to the items in the list? Also, do I set onClick outside of RecyclerView? This is my RecyclerView adapter class. Should the interface take additional parameters? Thank you in advance.

public class StepsAdapter extends RecyclerView.Adapter {

private static final String TAG = StepsAdapter.class.getSimpleName();
private ArrayList<Steps> stepsList = new ArrayList<Steps>();
private StepsAdapter.StepsAdapterOnClickHandler mClickHandler;

/**
 * The interface that receives onClick messages.
 */
public interface StepsAdapterOnClickHandler {
    void onClick(Steps stepClick);
}

/**
 * Creates a StepsAdapter.
 *
 * @param clickHandler The on-click handler for this adapter. This single handler is called
 *                     when an item is clicked.
 */
public StepsAdapter(StepsAdapterOnClickHandler clickHandler,ArrayList<Steps> stepsList) {
    mClickHandler = clickHandler;
    this.stepsList = stepsList;
}

/**
 * Cache of the children views for a steps list item.
 */
public class StepsAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    @BindView(R.id.step_short_desc)
    public TextView stepShortDescription;

    @BindView(R.id.step_description)
    public TextView stepDescription;

    public StepsAdapterViewHolder(View view) {
        super(view);
        ButterKnife.bind(this, view);
        view.setOnClickListener(this);
    }

    /**
     * This gets called by the child views during a click.
     *
     * @param v The View that was clicked
     */
    @Override
    public void onClick(View v) {
        int adapterPosition = getAdapterPosition();
        Steps stepClick = stepsList.get(adapterPosition);
        mClickHandler.onClick(stepClick);
    }
}

@Override
public StepsAdapter.StepsAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    Context context = viewGroup.getContext();
    int layoutIdForListItem = R.layout.steps_list_item;
    LayoutInflater inflater = LayoutInflater.from(context);
    boolean shouldAttachToParentImmediately = false;
    View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
    return new StepsAdapter.StepsAdapterViewHolder(view);
}

@Override
public void onBindViewHolder(StepsAdapter.StepsAdapterViewHolder holder, int position) {

    //Binding data
    final Steps stepsView = stepsList.get(position);

    holder.stepShortDescription.setText(stepsView.getStepShortDescription());
    holder.stepDescription.setText(stepsView.getStepDescription());
}

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

public void setStepsList(ArrayList<Steps> mStepsList) {
    this.stepsList = mStepsList;
    notifyDataSetChanged();
}

}

The corresponding fragment. Is the click method implemented correctly?

public class StepsListFragment extends Fragment implements StepsAdapter.StepsAdapterOnClickListener {

    // Tag for logging
    private final String TAG = StepsListFragment.class.getSimpleName();

    @BindView(R.id.recyclerview_steps)
    RecyclerView mRecyclerView;

    ArrayList<Steps> stepsArrayList;

    Recipes recipes;

    // Final Strings to store state information about the list of steps and list index
    public static final String STEPS_LIST_INDEX = "list_index";


    // Define a new interface OnStepsClickListener that triggers a callback in the host activity
    OnStepClickListener mCallback;

    // OnStepsClickListener interface, calls a method in the host activity named onStepSelected
    public interface OnStepClickListener {
        void onClick(Steps stepClick);
    }

    // Override onAttach to make sure that the container activity has implemented the callback
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

//        // This makes sure that the host activity has implemented the callback interface
//        // If not, it throws an exception
        try {
            mCallback = (OnStepClickListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement OnStepSelectedListener");
        }
    }

   /**
     * Mandatory empty constructor for the fragment manager to instantiate the fragment
     */
    public StepsListFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

//        //Inflate the Steps fragment layout
        View rootView = inflater.inflate(R.layout.fragment_steps, container, false);
//        // Bind the views
        ButterKnife.bind(this, rootView);

        Bundle bundle = this.getArguments();
        if (bundle != null) {
            recipes = getArguments().getParcelable("Recipes");

            stepsArrayList = new ArrayList<>();
            stepsArrayList = recipes.getRecipeSteps();
        }
        if (savedInstanceState != null) {
            //Restore the fragment's state here
            stepsArrayList = savedInstanceState.getParcelableArrayList(STEPS_LIST_INDEX);
        }

        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getContext());
        mRecyclerView.setLayoutManager(mLayoutManager);
        Log.i("listSteps", stepsArrayList.size() + "");

        StepsAdapter stepsAdapter = new StepsAdapter(this, stepsArrayList);
        mRecyclerView.setAdapter(stepsAdapter);

        // Return the root view
        return rootView;
}

public void onClick(Steps stepClick){
        mCallback.onClick(stepClick);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveIn`enter code here`stanceState(outState);

        //Save the fragment's state here
        outState.putParcelableArrayList(STEPS_LIST_INDEX, stepsArrayList);
        super.onSaveInstanceState(outState);
    }  }

The best way to implement click function on each item of recyclerview is initialise onClickListener when the view is populated inside in the recyclerview viewholder. Then in the onClick method, use a custom interface/listener to catch the click activity in your parent fragment/activity.

eg: create a custom interface like this;

public interface RecyclerviewOnClickListener{
void recyclerviewClick(int position);
}

Now implement this interface in your parent activity/fragment containing the recyclerview. Suppose your fragment name is ChatFragment. Then,

public class ChatFragment extends Fragment implements RecyclerviewOnClickListener{
.
.
}

This will implement the function onClick(int position) in your fragment. In your adapter constructor, you should create a field for the RecyclerviewOnClickListener. Suppose your adapter name is ChatAdapter, then

Adapter Constructor.

public ChatAdapter(RecyclerviewClickListener listener, .....<other params>){
this.listener = listener;
}

In your fragment, you can initialise your adapter like the following

ChatAdapter adapter = new ChatAdapter(this, <any additional params>);

You should pass the same instance of 'listener' to your viewholder also, and initialise the listener there also

Now in your recyclerview ViewHolder, you can set view.setOnClickListener(new OnClickListener{ this.listener.recyclerviewClick(getAdapterPosition()) });

The getAdapterPosition() function returns the position of the click in the recyclerview, which will get a callback in the recyclerviewClick() function in your fragment.

About the number of parameter you are passing, you can use as much as you want, but for a click function in recyclerview, the ideal way is to use only one param which the position. Now you can modify the contents in the list that you are passing from your fragment to adapter and call notifyDataSetChanged() which will update the recyclerview. Hope it's clear.

Try this inside OnBindviewHolder

 holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
              //code here

        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM