在过去的几个小时中,我一直在审查和尝试解决所有问题的方法,但是我无法让RecyclerView为我点击。我正在使用MVVM,并使用列表向导为此生成了基本代码。我尝试使用新的匿名View.OnClickListener以及在ViewHolder类中实现View.OnClickListener。我还尝试了一堆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,迈克
答案 0 :(得分:0)
德拉!我发送此邮件后,立即发现我做错了什么。 mListener传递给适配器时为null,因为我在onStart上设置了它,发生在onActivityCreated之后。所以这是一种解决方法
try {
mListener = (OnEventListFragmentInteractionListener)getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement interface");
}
这必须在onAttach(context)中完成,或者最晚在刚创建适配器的代码中完成。但是,当我仔细观察这一点时,我意识到该片段唯一要做的就是将其传递并存储对演员表的引用。我认为我们不需要存储它。所以我将适配器代码更改为:
final EventRecyclerViewAdapter adapter =
new EventRecyclerViewAdapter(mViewModel.getEvents().getValue(),
(OnListFragmentInteractionListener)getActivity());
由于该活动实现了接口,因此只需在传递给适配器的过程中将其强制转换即可。在执行此操作之前,您需要测试instanceof
并进行适当的抛出。
HTH,迈克