I have a recycler view in my app that populates by volley, and I get some restaurants name and address from REST api. I wanted to have swipe to delete in my app so I used Item Touch helper, but I don`t know why I'm getting this error. I'm kinda new in android. Please help.
my RecyclerItemTouchHelper
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;
public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
super(dragDirs, swipeDirs);
this.listener = listener;
}
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((RestaurantAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RestaurantAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((RestaurantAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RestaurantAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
}
my recycler adapter class
public class RestaurantAdapter extends RecyclerView.Adapter<RestaurantAdapter.MyViewHolder> implements View.OnClickListener {
private List<Restaurant> restaurantList;
private Context context;
private int position;
public int getPosition() {return position;}
public void setPosition(int position) { this.position = position;}
public RestaurantAdapter(List<Restaurant> restaurantList, Context context){
this.restaurantList = restaurantList;
this.context = context;
}
#Override
public void onClick(View view){
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
TextView listviewName,listviewAddress;
ImageView icon,noteIcon;
public RelativeLayout viewBackground, viewForeground;
MyViewHolder(View view){
super(view);
listviewName = view.findViewById(R.id.listview_name);
listviewAddress = view.findViewById(R.id.listview_address);
icon = view.findViewById(R.id.type_ic);
noteIcon = view.findViewById(R.id.note_icon);
viewBackground = view.findViewById(R.id.view_background);
viewForeground = view.findViewById(R.id.view_foreground);
view.setOnCreateContextMenuListener(this);
}
#Override
public void onCreateContextMenu(ContextMenu menu,View v,ContextMenu.ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
menu.add(0, 1, 0, "Edit");
menu.add(0, 2, 1, "Remove");
menu.add(0, 3, 2, "Add Note");
menu.add(0, 4, 3, "All Notes");
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout,parent,false);
Animation animation = AnimationUtils.loadAnimation(context, R.anim.fadein);
itemView.startAnimation(animation);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
setPosition(holder.getAdapterPosition());
return false;
}
});
Restaurant restaurant = restaurantList.get(position);
holder.listviewName.setText(restaurant.getName());
holder.listviewAddress.setText(restaurant.getAddress());
switch (restaurant.getImage()) {
case RestaurantContract.EntryRestaurants.RESTAURANT_TYPE_DELIVERY:
holder.icon.setImageResource(R.drawable.phoneorderr);
break;
case RestaurantContract.EntryRestaurants.RESTAURANT_TYPE_SITDOWN:
holder.icon.setImageResource(R.drawable.sitdownn);
break;
case RestaurantContract.EntryRestaurants.RESTAURANT_TYPE_TAKEAWAY:
holder.icon.setImageResource(R.drawable.takeaway);
break;
}
holder.noteIcon.setImageResource(R.drawable.notepadicon);
if(restaurant.isHasNote()) {
holder.noteIcon.setVisibility(View.VISIBLE);
}else {
holder.noteIcon.setVisibility(View.INVISIBLE);
}
}
#Override
public int getItemCount() {
return restaurantList.size();
}
public void removeItem(int position){
restaurantList.remove(position);
notifyItemRemoved(position);
}
public void restoreItem(Restaurant restaurant, int position){
restaurantList.add(position,restaurant);
notifyItemInserted(position);
}
}
my mainActivity class
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this);
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(fastfoodRecyclerView);
and my logcat
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.view.View.getTag(int)' on a null object reference
at androidx.recyclerview.widget.ItemTouchUIUtilImpl.onDraw(ItemTouchUIUtilImpl.java:38)
at com.test.fastfoodfinder.Restaurant.RecyclerItemTouchHelper.onChildDraw(RecyclerItemTouchHelper.java:54)
at androidx.recyclerview.widget.ItemTouchHelper$Callback.onDraw(ItemTouchHelper.java:1989)
at androidx.recyclerview.widget.ItemTouchHelper.onDraw(ItemTouchHelper.java:561)
at androidx.recyclerview.widget.RecyclerView.onDraw(RecyclerView.java:4284)
at android.view.View.draw(View.java:19192)
Related
I am trying to develop a functionality like Gmail, where you can swipe to delete.
This is my Main Fragment with recycler view.
public class MainFragment extends Fragment implements RecyclerItemTouchHelper.RecyclerItemTouchHelperListener {
RecyclerView recyclerView;
CoordinatorLayout coordinatorLayout;
RecyclerViewAdapter recyclerViewAdapter = null;
private View view;
private Context context = null;
ArrayList<Note> notes = new ArrayList<>();
ArrayList<Note> allNotes;
FloatingActionButton fab;
boolean isLoading = false;
private MainViewModel mViewModel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.main_fragment, container, false);
view = root;
recyclerView = view.findViewById(R.id.recyclerView);
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this);
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerView);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
coordinatorLayout = view.findViewById(R.id.mainContent)
populateNotesView();
}
#Override
public void onResume() {
super.onResume();
}
public void populateNotesView() {
MainViewModel obj = new MainViewModel();
allNotes = obj.getData(getContext());
notes.clear();
for (int i = 0; i < 10 && i < allNotes.size(); i++) {
notes.add(allNotes.get(i));
}
initAdapter(notes);
}
private void initAdapter(ArrayList<Note> notes) {
recyclerViewAdapter = new RecyclerViewAdapter(notes, getFragmentManager());
recyclerView.setAdapter(recyclerViewAdapter);
initScrollListener();
}
#Override
public void onDelete(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof RecyclerViewAdapter.ItemViewHolder) {
ArrayList<Note> notesList = allNotes;
String name = notesList.get(viewHolder.getAdapterPosition()).getText();
final Note deletedItem = notesList.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
recyclerViewAdapter = new RecyclerViewAdapter(notesList, getFragmentManager());
recyclerViewAdapter.removeItem(viewHolder.getAdapterPosition(), getContext());
Snackbar snackbar = Snackbar.make(coordinatorLayout, name + " removed from cart!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
recyclerViewAdapter.restoreItem(deletedItem, deletedIndex, getContext());
getFragmentManager().beginTransaction()
.replace(R.id.mainContent, MainFragment.newInstance())
.commitNow();
}
});
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
//Reloading fragment
getFragmentManager().beginTransaction()
.replace(R.id.mainContent, MainFragment.newInstance())
.commitNow();
}
}
}
And this is my RecyclerItemTouchHelper
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;
private boolean delete = false;
public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
super(dragDirs, swipeDirs);
this.listener = listener;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
final RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((RecyclerViewAdapter.ItemViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
listener.onDelete(viewHolder, viewHolder.getAdapterPosition());
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onDelete(RecyclerView.ViewHolder viewHolder, int position);
}
}
Now swiping a recyclerview item, doesn't call the onSwiped method every time. And I'm completely swiping the item.
EDIT: Any new item added is deleted successfully but already added items are not getting deleted.
EDIT 2: Adapter
public void removeItem(int position, Context context) {
MainViewModel obj = new MainViewModel();
obj.deleteData(context, mItemList.get(position).getText());
mItemList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mItemList.size());
}
public void restoreItem(Note item, int position, Context context) {
Util.newInstance().save(context, item.getText());
mItemList.add(position, item);
notifyItemInserted(position);
notifyItemRangeChanged(position, mItemList.size());
}
Any help is appreciated.
Thanks in advance.
The item isn't removed because you are using the original list in onDelete() by using below line of code:
ArrayList<Note> notesList = allNotes;
That means that whenever you delete an item, you just back to the original list.
The second issue is when you undo the deletion using the sanckbar action, you do the same thing by calling this:
populateNotesView();
To solve this, you need to remove the item from the original list you feed the RecyclerView adapter with, and just call notifyItemRemoved() for the removed position.
To do so, change onDelete() to be:
#Override
public void onDelete(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof RecyclerViewAdapter.ItemViewHolder) {
String name = allNotes.get(viewHolder.getAdapterPosition()).getText();
final Note deletedItem = allNotes.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
allNotes.remove(deletedIndex);
recyclerViewAdapter.notifyItemRemoved(deletedIndex);
Snackbar snackbar = Snackbar.make(coordinatorLayout, name + " removed from cart!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
allNotes.add(deletedIndex, deletedItem);
recyclerViewAdapter.notifyItemInserted(deletedIndex);
}
});
}
}
I'll use RecyclerView And I've more than 10 items in the list And I Have to change a text color and background layout on a single click of the item and else all the item color not change. Please suggest me the right way to solve this issue. I'll try to change the color in BindViewHolder, ViewHolder and Adapter click item but I'm Successful to change the color but unsuccessful to change the color back.
public class LoadVehicleTypeAdapter extends RecyclerView.Adapter<LoadVehicleTypeAdapter.CarTypesHolder> {
private List<TaxiTypeResponse.Message> CarTypesModelsList;
private Context mContext;
VehicleTypeView vehicleTypeView;
setOnitemclick listener;
private SparseBooleanArray selectedItems = new SparseBooleanArray();
int I=-1;
public class CarTypesHolder extends RecyclerView.ViewHolder {
public CustomTextView mCarType;
public CircleImageView mCarTypeImage;
LinearLayout llRoot;
CardView cardView;
private SparseBooleanArray selectedItems = new SparseBooleanArray();
setOnitemclick listener;
public CarTypesHolder(final View view) {
super(view);
mCarType = (CustomTextView) view.findViewById(R.id.frag_cartypes_inflated_name);
mCarTypeImage = (CircleImageView) view.findViewById(R.id.frag_cartype_inflated_frameImage);
llRoot = (LinearLayout)view.findViewById(R.id.root1);
cardView=(CardView) view.findViewById(R.id.cardf);
}
public void setOnItemClickListner(setOnitemclick listener12) {
listener=listener12;
}
}
public void setOnItemClickListner(setOnitemclick listener12) {
listener=listener12;
}
public LoadVehicleTypeAdapter(Context context, List<TaxiTypeResponse.Message> CarTypesModelsList, VehicleTypeView vehicleTypeView) {
this.CarTypesModelsList = CarTypesModelsList;
mContext = context;
this.vehicleTypeView = vehicleTypeView;
}
#Override
public CarTypesHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.frag_cartype_inflated_view, parent, false);
return new CarTypesHolder(itemView);
}
#SuppressLint("ResourceType")
#Override
public void onBindViewHolder(final CarTypesHolder holder, final int position) {
TaxiTypeResponse.Message carTypesModel = CarTypesModelsList.get(position);
I=CarTypesModelsList.get(position).getID();
holder.mCarType.setText(carTypesModel.getName());
holder.mCarTypeImage.setBackgroundResource(R.drawable.wait);
int color = Color.parseColor(PreferenceHandler.readString(mContext,PreferenceHandler.SECONDRY_COLOR,"#006fb6"));
holder.llRoot.setSelected(selectedItems.get(position, false));
holder.mCarType.setTextColor(color);
holder.setOnItemClickListner(listener);
holder. llRoot.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
I=position;
if (I==position)
{
holder.llRoot.setBackgroundColor(Color.parseColor("#999999"));
holder.mCarType.setTextColor(Color.parseColor("#ffffff"));
}
else
{
holder.llRoot.setBackgroundColor(Color.parseColor("#f3f3f3"));
holder.mCarType.setTextColor(Color.parseColor("#00000"));
}
}
});
Picasso.with(mContext).load(carTypesModel.getImagePath()).into(holder.mCarTypeImage);
}
#Override
public long getItemId(int position) {
return CarTypesModelsList.get(position).getID();
}
#Override
public int getItemCount() {
return CarTypesModelsList.size();
}
public void setSelection(LinearLayout imageView,CustomTextView textView,boolean value,int position){
if(value){
imageView.setBackgroundColor(Color.parseColor("#999999"));
textView.setTextColor(Color.parseColor("#FFFFFF"));
}else{
System.out.println("11111111111111111000000111111111111");
imageView.setBackgroundColor(Color.parseColor("#f3f3f3"));
textView.setTextColor(Color.parseColor("#2196F3"));
}
}
public interface setOnitemclick{
void ImageClick(int position, String Name,String Description,int id);
void ImageClickfade(int position, String Name,String Description,int id);
}
#Override
public int getItemViewType(int position) {
return position;
}
}
You can try this,
You'll use to update gradle
maven { url "https://maven.google.com" }
and update the code
public class LoadVehicleTypeAdapter extends RecyclerView.Adapter<LoadVehicleTypeAdapter.CarTypesHolder> {
private List<TaxiTypeResponse.Message> CarTypesModelsList;
private Context mContext;
VehicleTypeView vehicleTypeView;
int I=-1;
public class CarTypesHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public CustomTextView mCarType;
public CircleImageView mCarTypeImage;
LinearLayout llRoot;
CardView cardView;
setOnitemclick listener;
public void setOnItemClickListner(setOnitemclick listener)
{
this.listener=listener;
}
public CarTypesHolder(View view) {
super(view);
mCarType = (CustomTextView) view.findViewById(R.id.frag_cartypes_inflated_name);
mCarTypeImage = (CircleImageView) view.findViewById(R.id.frag_cartype_inflated_frameImage);
llRoot = (LinearLayout)view.findViewById(R.id.root1);
cardView=(CardView) view.findViewById(R.id.cardf);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
listener.ImageClick(v,getAdapterPosition());
}
}
public LoadVehicleTypeAdapter(Context context, List<TaxiTypeResponse.Message> CarTypesModelsList, VehicleTypeView vehicleTypeView) {
this.CarTypesModelsList = CarTypesModelsList;
mContext = context;
this.vehicleTypeView = vehicleTypeView;
}
#Override
public CarTypesHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.frag_cartype_inflated_view, parent, false);
return new CarTypesHolder(itemView);
}
#SuppressLint("ResourceType")
#Override
public void onBindViewHolder( final CarTypesHolder holder, int position) {
TaxiTypeResponse.Message carTypesModel = CarTypesModelsList.get(position);
holder.mCarType.setText(carTypesModel.getName());
holder.mCarTypeImage.setBackgroundResource(R.drawable.wait);
int color = Color.parseColor(PreferenceHandler.readString(mContext,PreferenceHandler.SECONDRY_COLOR,"#006fb6"));
holder.mCarType.setTextColor(color);
holder.setOnItemClickListner(new setOnitemclick() {
#Override
public void ImageClick(View v,int position1) {
I=position1;
notifyDataSetChanged();
}
});
if (I==position)
{
System.out.println("11100011111....");
holder.llRoot.setBackgroundColor(Color.parseColor("#999999"));
holder.mCarType.setTextColor(Color.parseColor("#ffffff"));
}
else
{
System.out.println("11100011111----");
holder.llRoot.setBackgroundColor(Color.parseColor("#f3f3f3"));
holder.mCarType.setTextColor(Color.parseColor("#2196F3"));
}
Picasso.with(mContext).load(carTypesModel.getImagePath()).into(holder.mCarTypeImage);
}
#Override
public long getItemId(int position) {
return CarTypesModelsList.get(position).getID();
}
#Override
public int getItemCount() {
return CarTypesModelsList.size();
}
public void setSelection(LinearLayout imageView,CustomTextView textView,boolean value,int position){
if(value){
imageView.setBackgroundColor(Color.parseColor("#999999"));
textView.setTextColor(Color.parseColor("#FFFFFF"));
}else{
System.out.println("11111111111111111000000111111111111");
imageView.setBackgroundColor(Color.parseColor("#f3f3f3"));
textView.setTextColor(Color.parseColor("#2196F3"));
}
}
public interface setOnitemclick{
void ImageClick(View view,int position);
}
#Override
public int getItemViewType(int position) {
return position;
}
}
Replace your click like below
public void onBindViewHolder(final CarTypesHolder holder, final int position) {
TaxiTypeResponse.Message carTypesModel = CarTypesModelsList.get(position);
I=CarTypesModelsList.get(position).getID();
holder.mCarType.setText(carTypesModel.getName());
holder.mCarTypeImage.setBackgroundResource(R.drawable.wait);
int color = Color.parseColor(PreferenceHandler.readString(mContext,PreferenceHandler.SECONDRY_COLOR,"#006fb6"));
holder.llRoot.setSelected(selectedItems.get(position, false));
holder.mCarType.setTextColor(color);
holder.setOnItemClickListner(listener);
holder. llRoot.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
I=position;
holder.llRoot.setBackgroundColor(Color.parseColor("#999999"));
holder.mCarType.setTextColor(Color.parseColor("#ffffff"));
notifyDataSetChanged()
}
});
if (I==position)
{
holder.llRoot.setBackgroundColor(Color.parseColor("#999999"));
holder.mCarType.setTextColor(Color.parseColor("#ffffff"));
}
else
{
holder.llRoot.setBackgroundColor(Color.parseColor("#f3f3f3"));
holder.mCarType.setTextColor(Color.parseColor("#00000"));
}
Picasso.with(mContext).load(carTypesModel.getImagePath()).into(holder.mCarTypeImage);
}
I'm doing a Note secure project, and I have set swipe to delete from a database. Also I have set password to delete it. My problem is while swiping the Card View, it shows an alert dialog box. When user selects cancel it, shows Background view not foreground View .but it structure in background view
Here is my code
#Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction, final int position) {
if (viewHolder instanceof NoteAdapter.MyViewHolder) {
// get the removed item name to display it in snack bar
String tittle = notesList.get(viewHolder.getAdapterPosition()).getTittle();
// backup of removed item for undo purpose
final Note note = notesList.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
// remove the item from recycler view
if (notesList.get(position).getLockstatus() == 0)
{
mAdapter.removeItem(viewHolder.getAdapterPosition());
}else{
final AlertDialog.Builder dBuilder = new AlertDialog.Builder(this);
LayoutInflater inflaterd = this.getLayoutInflater();
View viewd = inflaterd.inflate(R.layout.enter_password, null, false);
final EditText text3 = (EditText) viewd.findViewById(R.id.edpass);
dBuilder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String pass = text3.getText().toString();
String unlock = notesList.get(position).getPassword();
if (pass.equalsIgnoreCase(unlock))
{
mAdapter.removeItem(viewHolder.getAdapterPosition());
StyleableToast.makeText(MainActivity.this,"Delete successfully...",R.style.exampleToast).show();
}else {
StyleableToast.makeText(MainActivity.this,"Password does not match...",R.style.exampleToast).show();
}
}
});
dBuilder.setNegativeButton("cancel",null);
dBuilder.setCancelable(false);
dBuilder.setView(viewd);
dBuilder.create();
dBuilder.show();
}
// showing snack bar with Undo option
}
}
this is custom adapter for swipe
import android.graphics.Canvas;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.View;
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;
public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
super(dragDirs, swipeDirs);
this.listener = listener;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((NoteAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((NoteAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((NoteAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((NoteAdapter.MyViewHolder) viewHolder).viewForeground;
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
}
}
can anyone help me to solve this? If user cancel then its show as usually
I have a recycler view that displays a list of items.
Within each item, there is a title and another RecyclerView that display a list of items.
I want to access the click events of the items of the child RecyclerView.
Screenshot of the layout:
The parent RecyclerView:
public class DetailsGroupAdapter extends RecyclerView.Adapter<DetailsGroupAdapter.ViewHolder>{
private static OnItemClickListener listener;
private Context context;
private int lastPosition = -1;
RecyclerView mRecyclerView;
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
void onGroupItemLongClick(View itemView, int groupPosition, int itemPosition);
void onGroupItemClick(View itemView, int groupPosition, int itemPosition);
}
public void setOnItemClickListener(OnItemClickListener listener) {
DetailsGroupAdapter.listener = listener;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvTitle;
public CardView cvContainer;
public RecyclerView rvItems;
public ViewHolder(final View itemView)
{
super(itemView);
tvTitle = itemView.findViewById(R.id.group_title);
cvContainer = itemView.findViewById(R.id.container);
rvItems = itemView.findViewById(R.id.rv_group_items);
//click listener setup
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Triggers click upwards to the adapter on click
if (listener != null)
listener.onItemClick(itemView, getLayoutPosition());
}
});
}
public void clearAnimation()
{
cvContainer.clearAnimation();
}
}
private List<DetailsGroup> itemList;
public DetailsGroupAdapter(List<DetailsGroup> itemList)
{
this.itemList = itemList;
}
#Override
public DetailsGroupAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View layoutView = inflater.inflate(R.layout.item_details_group, parent, false);
mRecyclerView = (RecyclerView) parent;
return new ViewHolder(layoutView);
}
#Override
public void onBindViewHolder(final DetailsGroupAdapter.ViewHolder viewHolder, int groupPosition){
final DetailsGroup detailsGroup = itemList.get(groupPosition);
if(detailsGroup.Title != null){
viewHolder.tvTitle.setText(detailsGroup.Title);
} else {
viewHolder.tvTitle.setVisibility(View.GONE);
}
final DetailsGroupItemsAdapter detailsGroupAdapter = new DetailsGroupItemsAdapter(detailsGroup.itemsList, groupPosition);
detailsGroupAdapter.setOnItemClickListener(new DetailsGroupItemsAdapter.OnItemClickListener() {
#Override
public void onItemClick(View itemView, int position) {
if (listener != null){
listener.onGroupItemClick(itemView, (int) itemView.getTag(), position);
}
}
#Override
public void onLongClick(View itemView, int position) {
if (listener != null){
listener.onGroupItemLongClick(itemView, (int) itemView.getTag(), position);
}
}
});
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context) {};
viewHolder.rvItems.setLayoutManager(linearLayoutManager);
viewHolder.rvItems.setAdapter(detailsGroupAdapter);
}
private void setAnimation(View viewToAnimate, int position)
{
if (position > lastPosition) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(1000);
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
#Override
public void onViewDetachedFromWindow(final ViewHolder holder)
{
((ViewHolder)holder).cvContainer.clearAnimation();
}
#Override
public long getItemId(int position) {
return itemList.get(position).hashCode();
}
#Override
public int getItemCount()
{
return itemList.size();
}
public void clear() {
itemList.clear();
notifyDataSetChanged();
}
public void addAll(List<DetailsGroup> list){
itemList.addAll(list);
notifyDataSetChanged();
}
}
The child RecyclerView:
public class DetailsGroupItemsAdapter extends RecyclerView.Adapter<DetailsGroupItemsAdapter.ViewHolder>{
private static OnItemClickListener listener;
private Context context;
private int lastPosition = -1;
private int groupPosition;
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
void onLongClick(View itemView,int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
DetailsGroupItemsAdapter.listener = listener;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvTitle;
public TextView tvSubTitle;
public ImageView ivThumbnail;
public LinearLayout llContainer;
public ViewHolder(final View itemView)
{
super(itemView);
ivThumbnail = itemView.findViewById(R.id.thumbnail);
tvTitle = itemView.findViewById(R.id.title);
tvSubTitle = itemView.findViewById(R.id.subtitle);
llContainer = itemView.findViewById(R.id.container);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onItemClick(itemView, getLayoutPosition());
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
if (listener != null)
listener.onLongClick(itemView, getLayoutPosition());
return false;
}
});
}
public void clearAnimation()
{
llContainer.clearAnimation();
}
}
private List<ItemDetail> itemList;
public DetailsGroupItemsAdapter(List<ItemDetail> itemList, int groupPosition)
{
this.itemList = itemList;
this.groupPosition = groupPosition;
}
#Override
public DetailsGroupItemsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View layoutView = inflater.inflate(R.layout.item_details, parent, false);
return new ViewHolder(layoutView);
}
#Override
public void onBindViewHolder(DetailsGroupItemsAdapter.ViewHolder viewHolder, int position){
viewHolder.itemView.setTag(groupPosition);
ItemDetail itemDetail = itemList.get(position);
if(itemDetail.Title != null){
viewHolder.tvTitle.setText(itemDetail.Title);
} else {
viewHolder.tvTitle.setVisibility(View.GONE);
}
if(itemDetail.Sub_Title != null){
viewHolder.tvSubTitle.setText(itemDetail.Sub_Title);
} else {
viewHolder.tvSubTitle.setVisibility(View.GONE);
}
if(itemDetail.Thumbnail_Enabled){
PicManipulationUtility.SetGenericPictureFromThumbnailType(viewHolder.ivThumbnail, itemDetail.Thumbnail_Type, itemDetail.Thumbnail);
} else {
viewHolder.ivThumbnail.setVisibility(View.GONE);
}
setAnimation(viewHolder.llContainer, position);
}
private void setAnimation(View viewToAnimate, int position)
{
if (position > lastPosition) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(1000);
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
#Override
public void onViewDetachedFromWindow(final ViewHolder holder)
{
((ViewHolder)holder).llContainer.clearAnimation();
}
#Override
public long getItemId(int position) {
return itemList.get(position).hashCode();
}
#Override
public int getItemCount()
{
return itemList.size();
}
public void clear() {
itemList.clear();
notifyDataSetChanged();
}
public void addAll(List<ItemDetail> list){
itemList.addAll(list);
notifyDataSetChanged();
}
}
The classes used:
ItemDetail and DetailsGroup are POJOs to convert JSON into objects.
What I managed to do so far to temporarily fix the problem is:
In onBindViewHolder of parent RecyclerView, I grabbed the group position.
Then I passed the group position of the parent down to the child
adapter initializer in (DetailsGroupItemsAdapter)
Finally, in the child onBindViewHolder I set the tag to be the parent
group position(viewHolder.itemView.setTag(groupPosition);)
So in the click event of the child, I can say:
listener.onGroupItemClick(itemView, (int) itemView.getTag(), position);
Thus having both the group position and the child position in the bubbled event in my Activity or Fragment.
But I know for sure that the passed group position can change for any reason such as updating group items or removing items.
I want to know if there is a more robust solution to implement the click events of nested items in this case.
I used this https://gist.github.com/riyazMuhammad/1c7b1f9fa3065aa5a46f, especially
CustomItemClickListener.java :
public interface CustomItemClickListener {
public void onItemClick(View v, int position);
}
(Parent) RecyclerView modifications :
public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;
Context mContext;
CustomItemClickListener listener;
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
final ViewHolder mViewHolder = new ViewHolder(mView);
mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(v, mViewHolder.getPosition());
}
});
return mViewHolder;
}
//[... the other "classical" parts of your code...]
}
Alone, it allowed me to have separate click events on child and parent
With some modifications, it led me to something similar to your "fix", I think, but maybe it'll give you some clues : I am giving the parent position and the parent listener to the child when constructing it, and then a click on the child produces the same behavior as a click on the parent
Child RecyclerView constructor :
public AppsAdapter(ArrayList<PackageInformation.InfoObject> dataSet, CustomOnItemClickListener customItemClickListener, int parentPos) {
appsDataSet = dataSet;
onItemClickListener = customItemClickListener;
parentPosition = parentPos;
}
Child RecyclerView onCreateViewHolder :
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view.
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_app, viewGroup, false);
// Create the ViewHolder to return
final AppsAdapter.ViewHolder mViewHolder = new AppsAdapter.ViewHolder(v);
// Add the Listener
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { onItemClickListener.onItemClick(v, parentPosition); }
});
return mViewHolder;
I have implemented a RecyclerView with inbox style swipe view. When swiped, I removed the list item using the method below:
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
}
Similarly when the FAB is pressed I add data using the method,
public void addItem(String country) {
countries.add(country);
notifyItemInserted(countries.size());
}
However, when I remove a data item by swiping, it is removed from the ArrayList and RecyclerView list, but when I add data by FAB the removed data is still displayed in the list. I checked the ArrayList data set. It is as intended.
In the above screenshot you can see the String Test is the newly added data. The data in last two row I already deleted. It gets randomly displayed.
The complete code of my Adapter and Activity.
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<String> countries;
private TextView tv_country;
public DataAdapter(ArrayList<String> countries) {
this.countries = countries;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
tv_country.setText(countries.get(i));
}
#Override
public int getItemCount() {
return countries.size();
}
public void addItem(String country) {
countries.add(country);
notifyItemInserted(countries.size());
}
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
}
public class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(View view) {
super(view);
tv_country = (TextView)view.findViewById(R.id.tv_country);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ArrayList<String> countries = new ArrayList<>();
private DataAdapter adapter;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(this);
recyclerView = (RecyclerView)findViewById(R.id.card_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
adapter = new DataAdapter(countries);
recyclerView.setAdapter(adapter);
countries.add("Australia");
countries.add("India");
countries.add("United States of America");
countries.add("Germany");
countries.add("Russia");
adapter.notifyDataSetChanged();
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.LEFT){
adapter.removeItem(position);
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
Paint p = new Paint();
Bitmap icon;
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
View itemView = viewHolder.itemView;
if(dX > 0){
p.setColor(Color.parseColor("#388E3C"));
c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX,(float) itemView.getBottom(), p);
icon = BitmapFactory.decodeResource(
getResources(), R.drawable.ic_edit_white);
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
RectF dest = new RectF((float) itemView.getLeft() + width ,(float) itemView.getTop() + width,(float) itemView.getLeft()+ width+width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,dest,p);
} else {
p.setColor(Color.parseColor("#D32F2F"));
c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(),(float) itemView.getRight(), (float) itemView.getBottom(), p);
icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_delete_white);
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
RectF dest = new RectF((float) itemView.getRight() - width - width ,(float) itemView.getTop() + width,(float) itemView.getRight() - width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,dest,p);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.fab:
adapter.addItem("Test");
Log.d("Raj",countries.toString());
break;
}
}
}
What I have tried
I have tried using notifyItemRangeChanged() like this:
public void removeItem(int position) {
countries.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, countries.size());
}
I can't be sure that this will solve your problem, but one thing that is incorrect is how you are binding your data. tv_country should not be a part of the DataAdapter; it should be a part of each individual ViewHolder. One of the reasons we use the ViewHolder pattern is to maintain an easy reference to the views in each row.
Your bind method should end up similar to:
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.tv_country.setText(countries.get(i));
}
And be sure to make tv_country a public field of your inner ViewHolder class.
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView tv_country;
public ViewHolder(View view) {
super(view);
tv_country = (TextView) view.findViewById(R.id.tv_country);
}
}
Not sure I understood what is happening a 100%, but why are you actually trying to animate yourself? If you implement getItemId() and hasStableIds() if I remember correctly, you just should tell the recyclerview which element was removed or added (like you actually do).
Inside the onSwiped method, add viewHolder.setIsRecyclable(false);