繁体   English   中英

Android:将卡片视图从一个片段发送到另一个片段

[英]Android: Sending a cardview from one fragment to another

我需要一些暑期项目的帮助

这是我的事件片段

这是我的 MyList 片段

我正在使用 RecyclerView+Cardview 来显示事件。 这个想法是用户可以单击每张卡片右侧的大加号,卡片将显示在 MyList 片段中。 我想问是否可以将卡片直接从一个片段转移到另一个片段? 此外,两个片段都包含在同一个活动中,这使得它有点棘手(我还没有找到任何可用的解决方案)。

如果这不可能,另一种方法是将 CardView 中包含的引用类型 object 传输到 MyList 片段。 然而,这更不简单。 这是因为按钮在适配器中被充气,但是这里没有创建引用类型 object。 我看过很多关于使用 Parcelable 接口的教程,但是,当我什至无法在适配器中创建 object 时,我不知道如何在这里实现它。 引用 object 在另一个活动中创建,并在读取和显示之前存储在 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 class 实现 parcelable,因此单击加号按钮时无需手动创建捆绑包。

我假设您有一个 Activity,并且您只想将EventsFragment替换为MyListFragment 查看文档以将一个片段替换为另一个片段。

步骤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
            // NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
        }

        @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 步:

在您的MyListFragmentonCreateView()方法中:

@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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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