RecyclerView onClick не стреляет - PullRequest
       36

RecyclerView onClick не стреляет

0 голосов
/ 31 января 2019

Последние несколько часов я проверял и опробовал все решения, но я не могу заставить свой RecyclerView щелкнуть для меня.Я использую MVVM и сгенерировал базовый код для этого с помощью мастера списка.Я попытался использовать новый анонимный View.OnClickListener, а также реализовать View.OnClickListener в классе ViewHolder.Я также пробовал несколько комбинаций clickable = "true" [/ false], устанавливая clickable во фрагменте ... Кажется, ничего не работает.

Самый простой пример - отображение списка событий изкалендарь.Вот файлы:

events_list_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.EventsListActivity">

    <fragment
        android:id="@+id/fragment"
        android:name="com.mycompany.myapp.ui.vf.EventsListFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</FrameLayout>

event_list_fragment.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/eventslist"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.vf.EventsListFragment">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/events_recycler"
        android:layout_width="395dp"
        android:layout_height="696dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:clickable="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/events_list_item"/>

</android.support.constraint.ConstraintLayout>

events_list_item.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:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/layout_event_list_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:orientation="horizontal"
        android:focusableInTouchMode="false"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:id="@+id/txt_event_id"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textAlignment="textStart"
            android:contentDescription="@string/str_event_id"
            android:text="@string/str_id"
            android:focusableInTouchMode="false"
            />

        <TextView
            android:id="@+id/txt_event_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:contentDescription="@string/str_event_name"
            android:text="@string/str_event_name"
            android:textAlignment="textStart"
            android:focusableInTouchMode="false"
            tools:text="@string/str_event_name"
            />

        <TextView
            android:id="@+id/txt_event_desc"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:contentDescription="@string/str_event_desc"
            android:text="@string/str_event_desc"
            android:textAlignment="textStart"
            android:focusableInTouchMode="false"
            tools:text="@string/str_event_desc"
            />

    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_marginTop="8dp"
        android:layout_height="2dp"
        android:background="@color/list_line_divider"
        app:layout_constraintTop_toBottomOf="@id/layout_event_list_item"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />

</android.support.constraint.ConstraintLayout>

EventsListActivity.java

public class EventsListActivity extends AppCompatActivity
    implements EventsListFragment.OnEventListFragmentInteractionListener
{

    private static final String TAG = "EventsListActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.events_list_activity);
        Bundle bundle = getIntent().getExtras();
        if (savedInstanceState == null) {
            EventsListFragment newFrag = EventsListFragment.newInstance();
            newFrag.setArguments(bundle);
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.container, newFrag)
                    .commitNow();
        }
    }

    @Override
    public void onListFragmentInteraction(Event item) {
        LogUtil.getInstance().Log(this, TAG, "ITEM NOT IMPLEMENTED");
        // click handler
        Intent intent = new Intent(this, EventInstanceActivity.class);
        intent.putExtra(Constants.ARG_EVENT, item);
        startActivity(intent);
    }
}

EventsListFragment.java

public class EventsListFragment extends Fragment {
    private static final String TAG = "EventsListFragment";

    // TODO: Check that calendarId is going to be there
    // TODO: How to handle single vs. multiple EventInstances
    private Long mCalendarId;
    private EventViewModel mViewModel;
    private OnEventListFragmentInteractionListener mListener;

    public static EventsListFragment newInstance() {
        return new EventsListFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        // TODO: Check savedInstanceState
        Bundle bundle = getArguments();
        if (bundle != null) {
            mCalendarId = bundle.getLong(Constants.ARG_CALENDAR_ID);
        }
        return inflater.inflate(R.layout.events_list_fragment, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        LogUtil.getInstance().Log(this, TAG, "onActivityCreated");

        super.onActivityCreated(savedInstanceState);

        RecyclerView recyclerView = getActivity().findViewById(R.id.events_recycler);
        if (recyclerView != null) {
            Context context = recyclerView.getContext();
            mViewModel = ViewModelProviders.of(getActivity()).get(EventViewModel.class);
            mViewModel.setCalendar(mCalendarId);
            final EventRecyclerViewAdapter adapter =
                    new EventRecyclerViewAdapter(mViewModel.getEvents().getValue(), mListener);
            recyclerView.setLayoutManager(new LinearLayoutManager(context));
            recyclerView.setAdapter(adapter);

            mViewModel.getEvents().observe(this, new Observer<List<Event>>() {
                @Override
                public void onChanged(@Nullable List<Event> events) {
                    adapter.setEvents(events);
                    adapter.notifyDataSetChanged();
                }
            });
        }
    }

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

    @Override
    public void onStart() {
        super.onStart();
        try {
            mListener = (OnEventListFragmentInteractionListener)getActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException(getActivity().toString() + " must implement interface");
        }
    }

    public interface OnEventListFragmentInteractionListener {
        // TODO: Update argument type and name
        void onListFragmentInteraction(Event item);
    }
}

И, наконец, EventRecyclerViewAdapter.java

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

    // TODO: clean up naming standards 'm' for all class items
    List<Event> mEvents;
    EventsListFragment.OnEventListFragmentInteractionListener mListener;
    public EventRecyclerViewAdapter(List<Event> events, EventsListFragment.OnEventListFragmentInteractionListener listener) {
        mEvents = events;
        mListener = listener;
    }

    public void setEvents(List<Event> events) {
        mEvents = events;
    }

    @NonNull
    @Override
    public EventRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.events_list_item, viewGroup, false);
        return new ViewHolder(view);
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(@NonNull EventRecyclerViewAdapter.ViewHolder viewHolder, int i) {
        final Event event = mEvents.get(i);
        viewHolder.mItem = event;
        viewHolder.mIdView.setText(event.getEventId().toString());
        viewHolder.mTitleView.setText(event.getTitle());
        viewHolder.mDescriptionView.setText(event.getDesc());

        viewHolder.mView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mListener != null) {
                    mListener.onListFragmentInteraction(event);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return mEvents == null ? 0 : mEvents.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public final View mView;
        public final TextView mIdView;
        public final TextView mTitleView;
        public final TextView mDescriptionView;
        public Event mItem;

        public ViewHolder(View view) {
            super(view);
            mView = view;
            mIdView = view.findViewById(R.id.txt_event_id);
            mTitleView = view.findViewById(R.id.txt_event_name);
            mDescriptionView = view.findViewById(R.id.txt_event_desc);
        }

        @Override
        public String toString() {
            return super.toString() + " '" + mTitleView.getText() + "'";
        }
    }

}

Может ли быть, что представление рециркулятора в xml находится внутри ограничения?Когда я нажимаю на устройство, я слышу системный звук, но он не останавливается на точке останова в активности, в которой реализован слушатель, и не останавливается на точке останова в обработчике onClick.Кто-нибудь может увидеть, чего не хватает в этом?

TIA, Mike

1 Ответ

0 голосов
/ 31 января 2019

убирайся!Сразу после того, как я отправил это, я узнал, что я сделал не так.MListener равен нулю, когда он передается адаптеру, потому что я устанавливал его в onStart, что происходит после onActivityCreated.Итак, вот один из способов исправить это

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

Это должно быть сделано в onAttach (контекст) или, самое позднее, в коде чуть выше создания адаптера.Но когда я посмотрел поближе на это, я понял, что единственное, что фрагмент делал с этим, - это передать его и сохранить ссылку на актерский состав.Я не думаю, что мы должны хранить это.Поэтому я изменил код адаптера следующим образом:

final EventRecyclerViewAdapter adapter =
    new EventRecyclerViewAdapter(mViewModel.getEvents().getValue(),
        (OnListFragmentInteractionListener)getActivity());

Поскольку в упражнении реализован интерфейс, просто приведите его во время перехода к адаптеру.Вы захотите проверить instanceof, прежде чем сделать это, и выбросить, если необходимо.HTH, Майк

...