I've got a RecylerView that is displaying a list of data. I need to add dividers or spacers that I need to add two Dividers or spacers too that I can add text to as shown in the image below(with the text DEFAULT or OTHER).
*NOTE Headers are in the image below with the text "DEFAULT" and another that says "OTHER".
The CC's shown are drag and drop items but i don't want the "spaces or headers" marked as default and other to be moved.
I've started adding the divider as shown in the code below but I cannot figure out how to add text.
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
LinearLayoutManager mAdapterLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(mAdapterLayoutManager);
billingMethodRecyclerViewAdapter = new BillingMethodRecyclerViewAdapter(context, billingMethods, paymentService, ListPaymentMethods.this );
billingMethodRecyclerViewAdapter.setMasterpassService(masterpassService);
billingMethodRecyclerViewAdapter.setChoosePaymentMode(choosePaymentMode);
DividerItemDecoration itemDecor = new DividerItemDecoration(context, mAdapterLayoutManager.getOrientation());
recyclerView.addItemDecoration(itemDecor);
recyclerView.setAdapter(billingMethodRecyclerViewAdapter);
billingMethodRecyclerViewAdapter.clear();
if (!choosePaymentMode) {
setupSwipeListener(billingMethodRecyclerViewAdapter);
}
if (!BuildConfig.SHOW_AVAILABILITY_INRIX) {
parkmobileProAd.setVisibility(View.GONE);
}
if (getArguments() != null) {
isAddPaymentZoneDetails = getArguments().getBoolean(AddPaymentActivity.ADD_PAYMENT_FROM_ZONE_DETAIL);
}
}
and the xml for the recylcerview
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
EDIT
Adapter:
public class BillingMethodRecyclerViewAdapter extends RecyclerView.Adapter<BillingMethodHolder> {
private static final int PENDING_REMOVAL_TIMEOUT = 3000; // in milliseconds
private ArrayList<BillingMethod> billingMethods;
private Handler handler = new Handler(); // handler for running delayed runnables
private HashMap<BillingMethod, Runnable> pendingRunnables = new HashMap<>(); // map of items to pending runnables, so we can cancel a removal if need be
private BillingMethodHolder.BillingMethodListener billingMethodListener;
private PaymentService paymentService;
private MasterpassService masterpassService;
private boolean choosePaymentMode = false;
private Context mContext;
private int maxPaymentMethods = 6;
public BillingMethodRecyclerViewAdapter(Context context, ArrayList<BillingMethod> objects, PaymentService paymentService, BillingMethodHolder.BillingMethodListener billingMethodListener) {
this.billingMethods = objects;
this.billingMethodListener = billingMethodListener;
this.mContext = context.getApplicationContext();
this.paymentService = paymentService;
}
public int getMaxPaymentMethods() {
return maxPaymentMethods;
}
public void setMaxPaymentMethods(int maxPaymentMethods) {
this.maxPaymentMethods = maxPaymentMethods;
}
public void setMasterpassService(MasterpassService masterpassService) {
this.masterpassService = masterpassService;
}
public boolean onItemMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(billingMethods, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(billingMethods, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
return true;
}
public List<BillingMethod> getBillingMethods() {
return billingMethods;
}
public void setChoosePaymentMode(boolean choosePaymentMode) {
this.choosePaymentMode = choosePaymentMode;
}
@NonNull
@Override
public BillingMethodHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_payment_methods, parent, false);
return new BillingMethodHolder(v);
}
@Override
public void onBindViewHolder(@NonNull BillingMethodHolder holder, final int position) {
holder.bind(getBillingMethods().get(position), billingMethodListener, choosePaymentMode);
}
@Override
public int getItemCount() {
return billingMethods.size();
}
public void pendingRemoval(int position) {
final BillingMethod billingMethod = billingMethods.get(position);
billingMethod.setPendingDeletion(true);
this.notifyItemChanged(position); // redraw row in "undo" state
Runnable pendingRemovalRunnable = () -> {
deleteBillingMethod(position);
};
handler.postDelayed(pendingRemovalRunnable, PENDING_REMOVAL_TIMEOUT);
pendingRunnables.put(billingMethod, pendingRemovalRunnable);
}
public void savePaymentOrder() {
List<BillingMethod> newOrder = new ArrayList<>();
int order = 0;
for (BillingMethod method : billingMethods) {
if (order == 0) {
method.setPreferred(true);
LocalyticsUtil.getInstance(mContext).setPrimaryPaymentMethod(method);
} else {
method.setPreferred(false);
}
method.setSortOrder(order);
newOrder.add(method);
order++;
}
paymentService.setPaymentMethodsOrder(newOrder, new PaymentService.GenericListener() {
@Override
public void onSuccess() {
Log.d("TAG", "Saved");
}
@Override
public void onError(String errorMessage) {
Log.d("TAG", "Saved");
}
});
}
private void deleteBillingMethod(int position) {
BillingMethod method = billingMethods.get(position);
if (method.getBillingType() == BillingType.CREDIT_CARD) {
paymentService.deleteCreditCard(method.getCreditCard().getCardStatus(), new PaymentService.GenericListener() {
@Override
public void onSuccess() {
billingMethods.remove(position);
notifyItemRemoved(position);
}
@Override
public void onError(String errorMessage) {
}
});
} else if (method.getBillingType() == BillingType.PREPAID) {
paymentService.deleteWallet(new PaymentService.GenericListener() {
@Override
public void onSuccess() {
billingMethods.remove(position);
notifyItemRemoved(position);
}
@Override
public void onError(String errorMessage) {
}
});
} else if (method.getBillingType() == BillingType.PAYPAL) {
paymentService.deletePaypal(new PaymentService.GenericListener() {
@Override
public void onSuccess() {
billingMethods.remove(position);
notifyItemRemoved(position);
}
@Override
public void onError(String errorMessage) {
}
});
} else if (method.getBillingType() == BillingType.CHASEPAY) {
paymentService.deleteChasepay(new PaymentService.GenericListener() {
@Override
public void onSuccess() {
billingMethods.remove(position);
notifyItemRemoved(position);
}
@Override
public void onError(String errorMessage) {
}
});
} else if (method.getBillingType() == BillingType.MASTERPASSV7) {
masterpassService.deleteMasterpassV7(String.valueOf(method.getBillingMethodId()), new MasterpassService.GenericListener() {
@Override
public void onSuccess() {
billingMethods.remove(position);
notifyItemRemoved(position);
}
@Override
public void onError(String errorMessage) {
}
});
} else {
notifyDataSetChanged();
}
}
public void clear() {
billingMethods.clear();
notifyDataSetChanged();
}
public void stopRemoval(BillingMethod billingMethod) {
Runnable pendingRemovalRunnable = pendingRunnables.get(billingMethod);
pendingRunnables.remove(billingMethod);
if (pendingRemovalRunnable != null) {
handler.removeCallbacks(pendingRemovalRunnable);
}
billingMethod.setPendingDeletion(false);
this.notifyItemChanged(billingMethods.indexOf(billingMethod));
}
}
I took a bit of time but I was able to do it.
This is the output
1) MainActivity.java
public class MainActivity extends AppCompatActivity implements OnStartDragListener{
RecyclerView recyclerView;
private ItemTouchHelper mItemTouchHelper;
private List<Item> itemList = new ArrayList<>();
private RecyclerViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mAdapter = new RecyclerViewAdapter(itemList, MainActivity.this);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new SeparationDecorator());
recyclerView.setAdapter(mAdapter);
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);
prepareItemData();
}
private void prepareItemData() {
Item item = new Item("Apple Pay");
itemList.add(item);
item = new Item("1706-XXXX-XXXX-1112");
itemList.add(item);
item = new Item("Google pay");
itemList.add(item);
mAdapter.notifyDataSetChanged();
}
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
}
2) OnStartDragListener.java
public interface OnStartDragListener {
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
3) SimpleItemTouchHelperCallback.java
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false; // make this true to enable swipe to delete
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}
4) ItemTouchHelperAdapter.java
public interface ItemTouchHelperAdapter {
void onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
5) SeparationDecorator.java
public class SeparationDecorator extends RecyclerView.ItemDecoration {
private int textSize = 50;
private int groupSpacing = 100;
private Paint paint = new Paint();
{
paint.setTextSize(textSize);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
if (position == 0) {
c.drawText("DEFAULT", view.getLeft(),
view.getTop() - groupSpacing / 2 + textSize / 3, paint);
} else if(position == 1) {
c.drawText("OTHER", view.getLeft(),
view.getTop() - groupSpacing / 2 + textSize / 3, paint);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0 || parent.getChildAdapterPosition(view) == 1) {
outRect.set(0, groupSpacing, 0, 0);
}
}
}
6) RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> implements ItemTouchHelperAdapter{
private List<Item> itemList;
private Context context;
@Override
public void onItemMove(int fromPosition, int toPosition) {
Item prev = itemList.remove(fromPosition);
itemList.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev);
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemDismiss(int position) {
itemList.remove(position);
notifyItemRemoved(position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
}
}
public RecyclerViewAdapter(List<Item> itemList, Context context) {
this.itemList = itemList;
this.context = context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Item movie = itemList.get(position);
holder.title.setText(movie.getTitle());
}
@Override
public int getItemCount() {
return itemList.size();
}
}
7) Item.java
public class Item {
private String title;
public Item(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
This is it. This was able to solve your problem.
I am not able to explain you the complete code, I will take some time in future definitely and explain it.