package eu.davidea.samples.flexibleadapter; import android.os.Handler; import android.os.Looper; import android.os.Message; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.StaggeredGridLayoutManager; import java.util.List; import java.util.Random; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.samples.flexibleadapter.items.ScrollableExpandableItem; import eu.davidea.samples.flexibleadapter.items.ScrollableFooterItem; import eu.davidea.samples.flexibleadapter.items.ScrollableLayoutItem; import eu.davidea.samples.flexibleadapter.items.ScrollableSubItem; import eu.davidea.samples.flexibleadapter.items.ScrollableULSItem; import eu.davidea.samples.flexibleadapter.services.DatabaseConfiguration; /** * This is a custom implementation extending FlexibleAdapter. {@code AbstractFlexibleItem} is * used as most common Item for ALL view types. * <p>Binding is delegated via items (AutoMap), you <u>cannot</u> implement * {@code getItemViewType, onCreateViewHolder, onBindViewHolder}.</p> * * @see OverallAdapter * @see AbstractFlexibleItem */ public class ExampleAdapter extends FlexibleAdapter<AbstractFlexibleItem> { private static final String TAG = ExampleAdapter.class.getSimpleName(); ScrollableFooterItem scrollableFooterItem = new ScrollableFooterItem("SFI"); public ExampleAdapter(List<AbstractFlexibleItem> items, Object listeners) { // stableIds ? true = Items implement hashCode() so they can have stableIds! super(items, listeners, true); // In case you need a Handler, do this: // - Overrides the internal Handler with a custom callback that extends the internal one mHandler = new Handler(Looper.getMainLooper(), new MyHandlerCallback()); } @Override public void updateDataSet(List<AbstractFlexibleItem> items, boolean animate) { // NOTE: To have views/items not changed, set them into "items" before passing the final // list to the Adapter. // Overwrite the list and fully notify the change, pass false to not animate changes. // Watch out! The original list must a copy. super.updateDataSet(items, animate); // onPostUpdate() will automatically be called at the end of the Asynchronous update // process. Manipulate the list inside that method only or you won't see the changes. } /* * You can override this method to define your own concept of "Empty". * This method is never called internally. */ @Override public boolean isEmpty() { return super.isEmpty(); } /* * HEADER VIEW * This method shows how to add Header View as it was for ListView. * Same Header item is enqueued for removal with a delay. * The view is represented by a custom Item type to better represent any dynamic content. */ public void showLayoutInfo(boolean scrollToPosition) { if (!hasFilter()) { final ScrollableLayoutItem item = new ScrollableLayoutItem("LAY-L"); if (mRecyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) { item.setId("LAY-S"); item.setTitle(mRecyclerView.getContext().getString(R.string.staggered_layout)); } else if (mRecyclerView.getLayoutManager() instanceof GridLayoutManager) { item.setId("LAY-G"); item.setTitle(mRecyclerView.getContext().getString(R.string.grid_layout)); } else { item.setTitle(mRecyclerView.getContext().getString(R.string.linear_layout)); } item.setSubtitle(mRecyclerView.getContext().getString( R.string.columns, String.valueOf(getFlexibleLayoutManager().getSpanCount())) ); // NOTE: If you have to change at runtime the LayoutManager AND add // Scrollable Headers, consider to add them in post, using a delay >= 0 // otherwise scroll animations on all items will not start correctly. addScrollableHeaderWithDelay(item, 1200L, scrollToPosition); removeScrollableHeaderWithDelay(item, 4000L); } } /* * ANOTHER HEADER VIEW * This method showcases how to add a Header View with a delay. * The view is represented by a custom Item type to better represent any dynamic content. */ public void addUserLearnedSelection(boolean scrollToPosition) { if (!DatabaseConfiguration.userLearnedSelection && !hasFilter() && !(getItem(0) instanceof ScrollableULSItem)) { final ScrollableULSItem item = new ScrollableULSItem("ULS"); item.setTitle(mRecyclerView.getContext().getString(R.string.uls_title)); item.setSubtitle(mRecyclerView.getContext().getString(R.string.uls_subtitle)); addScrollableHeaderWithDelay(item, 1000L, scrollToPosition); } } /* * FOOTER VIEW * This method showcases how to delay add a Footer View. * The view is represented by a custom Item type to better represent any dynamic content. */ public void addScrollableFooter() { scrollableFooterItem.setTitle(mRecyclerView.getContext().getString(R.string.scrollable_footer_title)); scrollableFooterItem.setSubtitle(mRecyclerView.getContext().getString(R.string.scrollable_footer_subtitle)); addScrollableFooterWithDelay(scrollableFooterItem, 1000L, false); } public void updateScrollableFooter() { scrollableFooterItem.setTitle("Title update for SFI r" + new Random().nextInt(10)); updateItem(scrollableFooterItem); } /* * Showcase for EXPANDABLE HEADER VIEW */ public void addScrollableExpandableAsHeader() { final ScrollableExpandableItem expandable = new ScrollableExpandableItem("SEHI"); expandable.setTitle(mRecyclerView.getContext().getString(R.string.scrollable_expandable_header_title)); expandable.setSubtitle(mRecyclerView.getContext().getString(R.string.scrollable_expandable_header_subtitle)); expandable.addSubItem(new ScrollableSubItem("SEHI_1")); expandable.addSubItem(new ScrollableSubItem("SEHI_2")); addScrollableHeaderWithDelay(expandable, 1500L, false); } /* * Showcase for EXPANDABLE FOOTER VIEW */ public void addScrollableExpandableAsFooter() { final ScrollableExpandableItem expandable = new ScrollableExpandableItem("SEFI"); expandable.setTitle(mRecyclerView.getContext().getString(R.string.scrollable_expandable_footer_title)); expandable.setSubtitle(mRecyclerView.getContext().getString(R.string.scrollable_expandable_footer_subtitle)); expandable.addSubItem(new ScrollableSubItem("SEFI_1")); expandable.addSubItem(new ScrollableSubItem("SEFI_2")); addScrollableFooterWithDelay(expandable, 1500L, false); } /* * Delegated via item objects. You should not implement this method! */ // @Override // public int getItemViewType(int position) { // //Not implemented: METHOD A is used // } /* * Delegated via item objects. You should not implement this method! */ // @Override // public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // // Not implemented: METHOD A is used // } /* * Delegated via item objects. You should not implement this method! */ // @Override // public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { // // Not implemented: METHOD A is used // } @Override public String onCreateBubbleText(int position) { if (position < getScrollableHeaders().size()) { return "Top"; } else if (position >= getItemCount() - getScrollableFooters().size()) { return "Bottom"; } else { position -= getScrollableHeaders().size() + 1; } // TODO FOR YOU: The basic value, usually, is the first letter // return getItem(position).getBubbleText(position); // For me the position is (position + 1): return super.onCreateBubbleText(position); } /** * Showcase to reuse the internal Handler. * * <b>IMPORTANT:</b> In order to preserve the internal calls, this custom Callback * <u>must</u> extends {@link FlexibleAdapter.HandlerCallback} * which implements {@link android.os.Handler.Callback}, * therefore you <u>must</u> call {@code super().handleMessage(message)}. * <p>This handler can launch asynchronous tasks.</p> * If you catch the reserved "what", keep in mind that this code should be executed * <u>before</u> that task has been completed. * <p><b>Note:</b> numbers 0-9 are reserved for the Adapter, use others for new values.</p> */ private class MyHandlerCallback extends HandlerCallback { @Override public boolean handleMessage(Message message) { boolean done = super.handleMessage(message); switch (message.what) { // Currently reserved (you don't need to check these numbers!) case 1: //async updateDataSet case 2: //async filterItems case 3: //confirm delete case 8: //onLoadMore remove progress item return done; // Free to use, example: case 10: case 11: return true; } return false; } } }