0

I've tried to set up a click and toch listener for my RecyclerView with tutorials. But every tutorial I've tried I finaly failed because I've set the RecyclerView up with an other tutorial and all tutorials are looking different. Please can you help me detect click for each row? For example when a user clicks my first row (which is a logout field) it should logout the user from the app. All of my logout actions are working but the click on RecyclerView don't.

My SettingsAdapter:

import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

/**
 * Created by Johannes on 19.01.2017.
 */

public class SettingsAdapter extends RecyclerView.Adapter<SettingsAdapter.MySettingHolder> {

    private List<Settings> settingList;

    public class MySettingHolder extends RecyclerView.ViewHolder {
        public ImageView settingImage;
        public TextView settingTitle, settingSubtitle;

        public MySettingHolder(View view) {
            super(view);
            settingImage = (ImageView) view.findViewById(R.id.settingImage);
            settingTitle = (TextView) view.findViewById(R.id.settingTitle);
            settingSubtitle = (TextView) view.findViewById(R.id.settingSubtitle);
        }
    }

    public SettingsAdapter (List<Settings> settingList) {
        this.settingList = settingList;
    }

    @Override
    public MySettingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.settings_list_row, parent, false);

        return new MySettingHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MySettingHolder holder, int position) {
        // Setting for one entry
        Settings setting = settingList.get(position);

        holder.settingImage.setImageResource(setting.getSettingImageUrl());
        // If the settingSubtitle is empty it should be not visible and just the settingTitle
        if (setting.getSettingSubtitle().equals("")) {
            holder.settingTitle.setText(setting.getSettingTitle());
            holder.settingSubtitle.setVisibility(View.GONE);
        } else {
            holder.settingTitle.setText(setting.getSettingTitle());
            holder.settingSubtitle.setText(setting.getSettingSubtitle());
        }
    }

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

}

This is my SettingsFragment where I implement the RecyclerView

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CalendarView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import static android.content.Context.MODE_PRIVATE;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link SettingsFragment.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link SettingsFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class SettingsFragment extends Fragment {
    // Variables
    private OnFragmentInteractionListener mListener;
    // Variables for Recycler View
    private List<Settings> settingList = new ArrayList<>();
    private RecyclerView accountRecyclerView;
    private SettingsAdapter aAdapter;

    public SettingsFragment() {
        // Required empty public constructor
    }

    //Change the title in action bar
    public void onResume(){
        super.onResume();
        String titleString = getResources().getString(R.string.title_activity_navigation_drawer_settings);
        // Set title bar
        ((NavigationDrawerActivity) getActivity())
                .setActionBarTitle(titleString);
    }

    public static SettingsFragment newInstance() {
        SettingsFragment fragment = new SettingsFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

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

        View view  =  inflater.inflate(R.layout.fragment_settings, container, false);

        accountRecyclerView = (RecyclerView) view.findViewById(R.id.account_recycler_view);

        aAdapter = new SettingsAdapter(settingList);
        RecyclerView.LayoutManager aLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext()) {
            // Disable scrolling in the RecyclerView
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        };

        // Setup account RecyclerView
        accountRecyclerView.setLayoutManager(aLayoutManager);
        accountRecyclerView.setItemAnimator(new DefaultItemAnimator());
        prepareAccountData();
        accountRecyclerView.setAdapter(aAdapter);

        return view;
    }

    private void prepareAccountData() {
        // Create new setting
        Settings setting = new Settings(R.drawable.ic_menu_logout, "Abmelden", "Deine Daten bleibe erhalten");
        // Add Object to list
        settingList.add(setting);

        // Notify data changes
        aAdapter.notifyDataSetChanged();
    }

    // TODO: Rename method, update argument and hook method into UI event
    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onStart() {
        super.onStart();

        try {
            mListener = (OnFragmentInteractionListener) getActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException(getActivity().toString()
                    + " must implement OnFragmentInteractionListener");
        }

    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
ItsOdi1
  • 219
  • 3
  • 22
  • In Adapter, make a callback interface and you can detect onClick inside `onBindView` using `holder.itemview.setOnClickListener()` – Harry T. Jan 20 '17 at 18:47
  • Possible duplicate of [Why doesn't RecyclerView have onItemClickListener()? And how RecyclerView is different from Listview?](http://stackoverflow.com/questions/24885223/why-doesnt-recyclerview-have-onitemclicklistener-and-how-recyclerview-is-dif) – OneCricketeer Jan 20 '17 at 18:50
  • @cricket_007 But thats a tutorial which detect click a ALL elements but I need to detect click on a special element in my case the first of finaly eight rows – ItsOdi1 Jan 20 '17 at 19:04
  • @cricket_007 Are you serious? I've searched two days to find solution and you mark my question.... I've searched a lot and I don't ask before searching. Thats all I have to say.. – ItsOdi1 Jan 20 '17 at 19:12
  • I am serious. I cannot mysteriously know what posts you have or have not used and what worked and what didn't work. If you want the first row (or any row) to use a different event, check `if (position == 0)` within `onBindViewHolder` – OneCricketeer Jan 20 '17 at 19:15
  • @cricket_007 I've seen this question before. For your information. I'll try what you said. – ItsOdi1 Jan 20 '17 at 19:16
  • There's also this thing called the "item view type" that you can use. If you have a header that is different from all other rows, you should set a different view type. – OneCricketeer Jan 20 '17 at 19:18
  • Or, if you are trying to make an actual settings view, there is a `PreferenceFragment` class that you should use. https://developer.android.com/guide/topics/ui/settings.html – OneCricketeer Jan 20 '17 at 19:20

1 Answers1

2
    @Override
    public void onBindViewHolder(MySettingHolder holder, int position) {
        // Setting for one entry
        Settings setting = settingList.get(position);

        holder.settingImage.setImageResource(setting.getSettingImageUrl());
        // If the settingSubtitle is empty it should be not visible and just the settingTitle
        if (setting.getSettingSubtitle().equals("")) {
            holder.settingTitle.setText(setting.getSettingTitle());
            holder.settingSubtitle.setVisibility(View.GONE);
        } else {
            holder.settingTitle.setText(setting.getSettingTitle());
            holder.settingSubtitle.setText(setting.getSettingSubtitle());
        }

        holder.type = setting.getType();
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MySettingHolder holder = (MySettingHolder )(v.getTag());
                switch (holder.type) {

                    case 1:                        
                        // do logout
                        break;

                    case 2:                        
                        // do other stuff
                        break;

                    default:
                        break;
                }
            }
        });

        // set viewholder
        holder.itemView.setTag(holder);
    }

Also remind to update your ViewHolder like this and to add a type variable into Settings.class

public class MySettingHolder extends RecyclerView.ViewHolder {

        public int type;
        public ImageView settingImage;
        public TextView settingTitle, settingSubtitle;

        public MySettingHolder(View view) {
            super(view);
            settingImage = (ImageView) view.findViewById(R.id.settingImage);
            settingTitle = (TextView) view.findViewById(R.id.settingTitle);
            settingSubtitle = (TextView) view.findViewById(R.id.settingSubtitle);
        }
    }
ItsOdi1
  • 219
  • 3
  • 22
firegloves
  • 5,581
  • 2
  • 29
  • 50
  • And how can I detect **a special** element? For example the first one? And the the getView() method can't be resolved – ItsOdi1 Jan 20 '17 at 19:01
  • you can set a variable in your MySettingHolder and switch on this var. Or better you could migrate to a custom view class approach. Is more complex but is very more powerful – firegloves Jan 20 '17 at 19:06
  • firegloves that surpasses my abilities. Please can you be a little bit more detailed? – ItsOdi1 Jan 20 '17 at 19:08
  • @firegloves Did you mean `holder.itemView`? `getView()` is not a method – OneCricketeer Jan 20 '17 at 19:17
  • `Attempt to read from field 'int de.myfirstapp.app.SettingsAdapter$MySettingHolder.type' on a null object reference` – ItsOdi1 Jan 20 '17 at 19:30
  • Same problem again – ItsOdi1 Jan 20 '17 at 19:40
  • @ItsOdi1 try adding setTag as showed in edited answer – firegloves Jan 20 '17 at 19:41
  • `Settings setting = new Settings(1, R.drawable.ic_menu_logout, "Abmelden", "Deine Daten bleibe erhalten");` I've added a 1 at the beginning but null object again – ItsOdi1 Jan 20 '17 at 19:49
  • I've set in the first case this `Toast.makeText(v.getContext(), "Clicked Laugh Vote", Toast.LENGTH_SHORT).show();` but it's not showing – ItsOdi1 Jan 20 '17 at 20:23