我需要一个夏季项目的帮助
我正在使用RecyclerView + Cardview来显示事件。这个想法是,用户可以单击每张卡右侧的大加号,该卡将显示在MyList片段中。我想问一下是否可以将卡直接从一个片段转移到另一个片段吗?另外,两个片段都包含在同一活动中,这使操作变得有些棘手(我尚未找到任何可用的解决方案)。
如果不可能,另一种方法是将CardView中包含的引用类型对象转移到MyList片段。但是,这要简单得多。这是因为在适配器中按钮已膨胀,但此处未创建引用类型对象。我看过许多有关使用Parcelable接口的教程,但是,当我什至无法在适配器中创建对象时,我都不知道如何在这里实现它。引用对象是在另一个活动中创建的,并在读取和显示之前存储在Firebase中。
我将在下面附加我的EventsAdapter.java和EventsItem.java和EventsFragment.java代码,但是请告诉我是否应该包含更多代码来描述问题。
感谢您阅读我的长篇文章!
public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
private ArrayList<EventsItem> mEventsList;
private ArrayList<EventsItem> mEventsListFull;
private EventsAdapter.OnItemClickListener mListener;
private Context mContext;
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);
public interface OnItemClickListener {
void onItemClick(int position);
}
//the ViewHolder holds the content of the card
public static class EventsViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public ImageView mAddButton;
public TextView mTextView1;
public TextView mTextView2;
public TextView mTextView3;
public TextView mTextView4;
public TextView mTextView5;
public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
super(itemView);
final Context context1 = context;
mImageView = itemView.findViewById(R.id.imageView);
mAddButton = itemView.findViewById(R.id.image_add);
mTextView1 = itemView.findViewById(R.id.title);
mTextView2 = itemView.findViewById(R.id.event_description);
mTextView3 = itemView.findViewById(R.id.date);
mTextView4 = itemView.findViewById(R.id.location);
mTextView5 = itemView.findViewById(R.id.time);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
mAddButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str1 = mTextView1.getText().toString();
String str2 = mTextView2.getText().toString();
String str3 = mTextView3.getText().toString();
String str4 = mTextView4.getText().toString();
String str5 = mTextView5.getText().toString();
Bundle bundle = new Bundle();
bundle.putString("title", str1);
bundle.putString("event description", str2);
bundle.putString("date", str3);
bundle.putString("location", str4);
bundle.putString("time", str5);
MylistFragment mlf = new MylistFragment();
mlf.setArguments(bundle);
}
});
}
}
//Constructor for EventsAdapter class. This ArrayList contains the
//complete list of items that we want to add to the View.
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
}
//inflate the items in a EventsViewHolder
@NonNull
@Override
public EventsAdapter.EventsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
return evh;
}
@Override
public void onBindViewHolder(@NonNull EventsAdapter.EventsViewHolder holder, int position) {
EventsItem currentItem = mEventsList.get(position);
holder.mImageView.setImageResource(currentItem.getProfilePicture());
holder.mTextView1.setText(currentItem.getTitle());
holder.mTextView2.setText(currentItem.getDescription());
holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
holder.mTextView4.setText(currentItem.getLocationInfo());
holder.mTextView5.setText(currentItem.getTimeInfo());
}
@Override
public int getItemCount() {
return mEventsList.size();
}
public class EventsItem implements Occasion, Parcelable {
//fields removed for brevity
//constructor removed for brevity
}
public EventsItem() {
}
public EventsItem(Parcel in) {
profilePicture = in.readInt();
timeInfo = in.readString();
hourOfDay = in.readInt();
minute = in.readInt();
locationInfo = in.readString();
title = in.readString();
description = in.readString();
}
public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
@Override
public EventsItem createFromParcel(Parcel in) {
return new EventsItem(in);
}
@Override
public EventsItem[] newArray(int size) {
return new EventsItem[size];
}
};
//getter methods have been removed for brevity
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(profilePicture);
dest.writeString(timeInfo);
dest.writeString(locationInfo);
dest.writeString(title);
dest.writeString(description);
dest.writeString(df.format(dateInfo));
dest.writeInt(hourOfDay);
dest.writeInt(minute);
}
}
public class EventsFragment extends Fragment {
ArrayList<EventsItem> EventsItemList;
FirebaseDatabase mDatabase;
DatabaseReference mDatabaseReference;
ValueEventListener mValueEventListener;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private EventsAdapter mAdapter;
private View rootView;
public FloatingActionButton floatingActionButton;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_events, container, false);
mDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mDatabase.getReference().child("Events");
createEventsList();
buildRecyclerView();
floatingActionButton = rootView.findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), EventsAdder.class);
startActivity(intent);
}
});
mValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
EventsItemList.add(snapshot.getValue(EventsItem.class));
}
EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setAdapter(eventsAdapter);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
setHasOptionsMenu(true);
Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
return rootView;
}
public void createEventsList() {
EventsItemList = new ArrayList<>();
}
public void buildRecyclerView() {
mRecyclerView = rootView.findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
如果您希望在MyListFragment中看到相同的CardView,则可以使MyListFragment包含RecyclerView,并重用相同的EventsAdapter和EventsViewHolder。唯一的不同是,您只需要使用所需的单个事件来填充适配器,而不是用数据库中所有“事件”的子代填充适配器。
此外,由于已经使您的Event
类实现可拆分,因此在单击加号按钮时不需要手动创建包。
我假设您只有一个Activity,而您只想用EventsFragment
替换MyListFragment
。签出replacing one fragment with another的文档。
步骤1:
将onItemClickListener
扩展为:
public interface OnItemClickListener { void onItemClick(int position); void onPlusButtonClick(int position); }
并在单击加号按钮时调整
EventsViewHolder
构造函数中的代码,使其看起来像这样:
mAddButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { // no need to manually create the bundle here // you already have all the information you need int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { listener.onPlusButtonClick(position); } } } });
步骤2:
实施我们的新方法onPlusButtonClick
。根据我们在评论中的讨论,似乎您没有在任何地方实现此接口。您可以在构造函数内将其实现到EventsAdapter
:
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) { mEventsList = EventsList; mContext = context; mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView mListener = new OnItemClickListener() { @Override public void onItemClick() { // handle clicking the entire view holder } @Override public void onPlusButtonClick(int position) { MyListFragment myListFragment = new MyListFragment(); Event event = mEventsList.get(position); Bundle bundle = new Bundle(); bundle.putExtra("event", event); // this will work due to implementing parcelable myListFragment.setArguments(bundle); // use mContext since im assuming we areinside adapter // if in an Activity, no need to use context to get the fragment manager FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction(); // Replace the EventsFragment with the MyListFragment // and add the transaction to the back stack so the user can navigate back transaction.replace(R.id.fragment_container, myListFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit(); } } }
第3步:
在您的MyListFragment
的onCreateView()
方法内部:
@Override public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { Bundle bundle = getArguments(); Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable // from here you should bind to a recycler view, and you can even reuse your adapter like so: List<EventsItem> singleEventList = new List<EventsItem>(); singleEventList.add(event); EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList); // be sure to inflate and return your view here... }
你应该很好!
为了简化起见,我在这里和此处都省略了一些代码。但是我希望这是可以理解的。
作为补充,在Firebase数据库侦听器中,每当数据更新时都创建一个新的EventsAdapter
是一种不好的做法。相反,您应该使用新值更新适配器中的数据。为此,请在适配器内部创建一个公共方法,例如replaceEvents(List<EventsItem> newEvents)
,然后在内部用新事件替换mEventsList
,然后调用notifyDataSetChanged()
。