I made an swipe to delete functionality in my recycleView and i want to add another background when item is swiped across the screen.
I'm using tutorial for this: https://medium.com/#zackcosborn/step-by-step-recyclerview-swipe-to-delete-and-undo-7bbae1fce27e
I wrote some code, but i have an java.lang.IllegalStateException: Fragment PatientsFragment{dcddb65} not attached to a context.
public class PatientsFragment extends Fragment {
ClinicViewModel clinicViewModel;
private final ColorDrawable background= new ColorDrawable(getResources().getColor(R.color.colorPrimary));
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.patients_fragment, container, false);
FloatingActionButton fab = root.findViewById(R.id.fabAddPatient);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AddPatientFragment addPatientFragment = new AddPatientFragment();
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction()
.replace(R.id.nav_host_fragment, addPatientFragment)
.addToBackStack(null)
.commit();
}
});
RecyclerView recyclerView = (RecyclerView) root.findViewById(R.id.recyclerViewPatients);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setHasFixedSize(true);
final PatientsAdapter adapter = new PatientsAdapter();
recyclerView.setAdapter(adapter);
clinicViewModel = ViewModelProviders.of(this).get(ClinicViewModel.class);
clinicViewModel.getAllPatients().observe(this, new Observer<List<Patient>>() {
#Override
public void onChanged(List<Patient> patients) {
adapter.setPatients(patients);
}
});
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int backgroundCornerOffset = 20;
if (dX > 0) { // Swiping to the right
background.setBounds(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + ((int) dX) + backgroundCornerOffset,
itemView.getBottom());
} else if (dX < 0) { // Swiping to the left
background.setBounds(itemView.getRight() + ((int) dX) - backgroundCornerOffset,
itemView.getTop(), itemView.getRight(), itemView.getBottom());
} else { // view is unSwiped
background.setBounds(0, 0, 0, 0);
}
background.draw(c);
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
clinicViewModel.deletePatient(adapter.getPatientAt(viewHolder.getAdapterPosition()));
Toast.makeText(getActivity(), "Patient deleted", Toast.LENGTH_SHORT).show();
}
}).attachToRecyclerView(recyclerView);
return root;
}
}
Any ideas why?
Thanks in advance!
Related
I'm trying to send data from a an activity to a fragment.The data is the name of the item witch is currently clicked, I needed because I want to make a query.But the data is never sent. I also tried to send the broadcast before calling fragment.begingTrascation, but still doesn't worked,
I also changed the name of the constants but still, the broadcast from the Fragment is never triggered.
I don't know why is not working, what can I do to solve this?
private NavigationView.OnNavigationItemSelectedListener navigationListener = new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.nav_today) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new TodayFragment())
.commit();
} else if (item.getItemId() == R.id.nav_inbox) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new InboxFragment())
.commit();
} else if (item.getItemId() == R.id.nav_add_list) {
ListBottomSheet bottomSheet = new ListBottomSheet();
bottomSheet.showNow(getSupportFragmentManager(), "bottomSheetList");
} else if (item.getItemId() == R.id.nav_account) {
startActivity(new Intent(HomeDrawerActivity.this, AccountActivity.class));
} else if (item.getItemId() == R.id.nav_random_task) {
startActivity(new Intent(HomeDrawerActivity.this, RandomTaskActivity.class));
} else {
/* one of the list items
was clicked therefore
get the data form db
*/
item.setCheckable(true);
item.setChecked(true);
String listName = item.getTitle().toString();
Toast.makeText(HomeDrawerActivity.this, listName, Toast.LENGTH_LONG).show();
/* create the fragment */
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new ListFragment())
.commit();
/* send data to the fragment */
Intent intent = new Intent(LIST_ACTION);
intent.putExtra(KEY_LIST_NAME, listName);
LocalBroadcastManager.getInstance(HomeDrawerActivity.this).sendBroadcast(intent);
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
};
public class ListFragment extends Fragment {
private Context context;
private String documentName;
private ListAdaptor listAdaptor;
private RecyclerView recyclerViewList;
private ColorDrawable swipeBackgroundRight = new ColorDrawable(Color.parseColor("#FF0000"));
private ColorDrawable swipeBackgroundLeft = new ColorDrawable(Color.parseColor("#1E88E5"));
private Drawable iconDelete;
private Drawable iconComplete;
private SoundPool soundPool;
private int soundId;
private FirebaseFirestore firestore = FirebaseFirestore.getInstance();
private CollectionReference collectionReference = firestore.collection("Users")
.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.collection("Lists");
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = LayoutInflater.from(getActivity()).inflate(R.layout.list_fragment, container, false);
LocalBroadcastManager.getInstance(context)
.registerReceiver(broadcastReceiver, new IntentFilter(HomeDrawerActivity.LIST_ACTION));
iconDelete = ContextCompat.getDrawable(getActivity(), R.drawable.ic_delete);
iconComplete = ContextCompat.getDrawable(getActivity(), R.drawable.ic_completed);
if (!TextUtils.isEmpty(documentName)) {
collectionReference.document(documentName);
} else {
Toast.makeText(getActivity(), "Error", Toast.LENGTH_SHORT).show();
}
/* create the option query
for the recycler
*/
Query query = collectionReference;
FirestoreRecyclerOptions<Task> options =
new FirestoreRecyclerOptions.Builder<Task>()
.setQuery(query, Task.class)
.build();
listAdaptor = new ListAdaptor(options);
recyclerViewList = rootView.findViewById(R.id.recycler_view_list);
recyclerViewList.setHasFixedSize(true);
recyclerViewList.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerViewList.setAdapter(listAdaptor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes audioAttributes =
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
soundPool = new SoundPool.Builder()
.setMaxStreams(1)
.setAudioAttributes(audioAttributes)
.build();
} else {
soundPool = new SoundPool(1, AudioManager.STREAM_RING, 0);
}
soundId = soundPool.load(getActivity(), R.raw.completed, 1);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
if (direction == ItemTouchHelper.RIGHT) {
listAdaptor.delete(viewHolder.getAdapterPosition());
Toast.makeText(context, "Task deleted", Toast.LENGTH_SHORT).show();
} else if (direction == ItemTouchHelper.LEFT) {
listAdaptor.update(viewHolder.getAdapterPosition());
soundPool.play(soundId, 1, 1, 1, 0, 1);
Toast.makeText(context, "Task completed", Toast.LENGTH_SHORT).show();
swipeBackgroundRight.setBounds(0, 0, 0, 0);
iconDelete.setBounds(0, 0, 0, 0);
}
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
View itemView = viewHolder.itemView;
int iconMargin = (itemView.getHeight() - iconDelete.getIntrinsicHeight()) / 2;
if (dX > 0) {
swipeBackgroundRight.setBounds(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
iconDelete.setBounds(itemView.getLeft() + iconMargin, itemView.getTop() + iconMargin, itemView.getLeft() + iconMargin + iconDelete.getIntrinsicWidth(), itemView.getBottom() - iconMargin);
} else if (dX < 0) {
swipeBackgroundLeft.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
iconComplete.setBounds(itemView.getRight() - iconMargin - iconComplete.getIntrinsicWidth(), itemView.getTop() + iconMargin, itemView.getRight() - iconMargin,
itemView.getBottom() - iconMargin);
} else {
swipeBackgroundLeft.setBounds(0, 0, 0, 0);
swipeBackgroundRight.setBounds(0, 0, 0, 0);
}
c.save();
swipeBackgroundRight.draw(c);
swipeBackgroundLeft.draw(c);
if (dX > 0) {
c.clipRect(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
} else {
c.clipRect(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
}
iconDelete.draw(c);
iconComplete.draw(c);
c.restore();
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}).attachToRecyclerView(recyclerViewList);
return rootView;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (HomeDrawerActivity.LIST_ACTION.equals(intent.getAction())) {
/* get the data from db */
documentName = intent.getStringExtra(HomeDrawerActivity.KEY_LIST_NAME);
Toast.makeText(getActivity(), "List fragment" + documentName, Toast.LENGTH_LONG).show();
}
}
};
#Override
public void onStart() {
super.onStart();
listAdaptor.startListening();
}
#Override
public void onDestroyView() {
super.onDestroyView();
LocalBroadcastManager.getInstance(context).unregisterReceiver(broadcastReceiver);
}
}
If you send a broadcast before the Fragment transaction is started, it is very likely that the Fragment will not manage to set up its BroadcastReceiver in time to catch the transmission.
But in your case, you can add the data you want to pass to the Fragment to the arguments Bundle of the ListFragment instance before starting the transaction:
String listName = item.getTitle().toString();
/* create the fragment */
ListFragment listFragment = new ListFragment();
/* store data in arguments Bundle */
Bundle args = new Bundle();
args.putString(KEY_LIST_NAME, listName);
listFragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, listFragment )
.commit();
In ListFragment, you can access the data as follows:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = LayoutInflater.from(getActivity()).inflate(R.layout.list_fragment, container, false);
Bundle args = getArguments();
String listName = args.getString(KEY_LIST_NAME);
// ....
}
I have a fragment called today, in which i get all the tasks with the current day. But, when i add an item to the firestore with the current day, and this is the first task witch is added to the firestore, the task is now showed in the fragment, when I add the second task is showed, and the third the same. But the first task is never showed, do you know why is doing this?
This is today fragment:
public class TodayFragment extends Fragment {
private View rootView;
private TodayAdaptor todayAdaptor;
private ColorDrawable swipeBackgroundRight = new ColorDrawable(Color.parseColor("#FF0000"));
private Drawable iconDelete;
private FirebaseFirestore firestore = FirebaseFirestore.getInstance();
private CollectionReference collectionReference;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (getActivity() != null) {
getActivity().setTitle(R.string.today);
}
collectionReference = firestore.collection("Users")
.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.collection("Tasks");
iconDelete = ContextCompat.getDrawable(getActivity(), R.drawable.ic_delete);
rootView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_today, container, false);
RecyclerView recyclerViewToday = rootView.findViewById(R.id.recycler_view_today);
/* create the options for query */
Calendar calendar = Calendar.getInstance();
String dateFormatted = java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL).format(calendar.getTime());
Query query = collectionReference.whereEqualTo("date", dateFormatted);
FirestoreRecyclerOptions<Task> options =
new FirestoreRecyclerOptions.Builder<Task>()
.setQuery(query, Task.class)
.build();
todayAdaptor = new TodayAdaptor(options);
recyclerViewToday.setHasFixedSize(true);
recyclerViewToday.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerViewToday.setAdapter(todayAdaptor);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
if (direction == ItemTouchHelper.RIGHT) {
todayAdaptor.deleteTask(viewHolder.getAdapterPosition());
Toast.makeText(getActivity(), "Task deleted", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
View itemView = viewHolder.itemView;
int iconMargin = (itemView.getHeight() - iconDelete.getIntrinsicHeight()) / 2;
if (dX > 0) {
swipeBackgroundRight.setBounds(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
iconDelete.setBounds(itemView.getLeft() + iconMargin, itemView.getTop() + iconMargin, itemView.getLeft() + iconMargin + iconDelete.getIntrinsicWidth(), itemView.getBottom() - iconMargin);
} else {
swipeBackgroundRight.setBounds(0, 0, 0, 0);
}
c.save();
swipeBackgroundRight.draw(c);
if (dX > 0) {
c.clipRect(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
} else {
c.clipRect(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
}
iconDelete.draw(c);
c.restore();
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}).attachToRecyclerView(recyclerViewToday);
return rootView;
}
#Override
public void onStart() {
super.onStart();
todayAdaptor.startListening();
}
#Override
public void onStop() {
super.onStop();
todayAdaptor.stopListening();
}
}
This is my adaptor:
public class TodayAdaptor extends FirestoreRecyclerAdapter<Task, TodayAdaptor.TodayViewHolder> {
public TodayAdaptor(#NonNull FirestoreRecyclerOptions<Task> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull TodayViewHolder holder, int position, #NonNull Task model) {
holder.todayCheckBox.setChecked(model.isCompleted());
holder.taskDescription.setText(model.getName());
}
#NonNull
#Override
public TodayViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.today_item, parent, false);
return new TodayViewHolder(view);
}
public void deleteTask(int position){
/* save the item to be
restored if the user want's so
*/
getSnapshots().getSnapshot(position).getReference().delete();
}
class TodayViewHolder extends RecyclerView.ViewHolder {
private CheckBox todayCheckBox;
private TextView taskDescription;
public TodayViewHolder(#NonNull View itemView) {
super(itemView);
todayCheckBox = itemView.findViewById(R.id.today_item_check_box);
taskDescription = itemView.findViewById(R.id.today_item_task_description);
}
}
}
I'm trying to implement the feature "Swipe to delete" item in recycleview. But the deleted item is can not restore correctly when invoke UNDO action on snackbar.
This is error.
https://i.imgur.com/hPfaBQX.png
I have tried to implement onChildDraw in different ways, but it does not work
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) {
// backup of removed item
final String deletedItem = adapter.arrIgnoreNumber.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
adapter.removeItem(viewHolder.getAdapterPosition());
// showing snack bar with Undo option
Snackbar snackbar = Snackbar.make(coordinatorLayout, "Removed from the list!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
adapter.restoreItem(deletedItem, deletedIndex);
}
});
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
}
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
Bitmap icon;
Paint p = new Paint();
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
View itemView = viewHolder.itemView;
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
if(dX > 0){
p.setColor(Color.parseColor("#388E3C"));
RectF background = new RectF((float) itemView.getLeft(), (float) itemView.getTop(), dX,(float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_delete);
RectF icon_dest = new RectF((float) itemView.getLeft() + width ,(float) itemView.getTop() + width,(float) itemView.getLeft()+ 2*width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,p);
} else {
p.setColor(Color.parseColor("#D32F2F"));
RectF background = new RectF((float) itemView.getRight() + dX, (float) itemView.getTop(),(float) itemView.getRight(), (float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_delete);
RectF icon_dest = new RectF((float) itemView.getRight() - 2*width ,(float) itemView.getTop() + width,(float) itemView.getRight() - width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,p);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
I expect the deleted item can restore in list
Update: I provide my adapter for more detail:
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.list_ignore_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
final int tmpPos = position;
viewHolder.phone.setText(arrIgnoreNumber.get(position));
String name = arrIgnoreNumber.get(position);
if (!name.isEmpty()) {
viewHolder.phone.setVisibility(View.VISIBLE);
viewHolder.name.setText(name);
} else {
viewHolder.phone.setVisibility(View.GONE);
viewHolder.name.setText(arrIgnoreNumber.get(position));
}
viewHolder.icon.setImageBitmap(Utils.getBitmapByContactNumber(mContext, arrIgnoreNumber.get(position), false));
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemCount() {
return arrIgnoreNumber.size();
}
public void removeItem(int position) {
arrIgnoreNumber.remove(position);
notifyItemRemoved(position);
}
public void restoreItem(String item, int position) {
arrIgnoreNumber.add(position, item);
notifyItemInserted(position);
}
The following solution works for me. Refer to https://www.androidhive.info/2017/09/android-recyclerview-swipe-delete-undo-using-itemtouchhelper/
In ItemTouchHelper.SimpleCallback:
#Override
public int getMovementFlags(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, ItemTouchHelper.LEFT);
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
}
#Override
public void onSelectedChanged(#Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((IgnoreCallAdapter.ViewHolder) viewHolder).foreground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(#NonNull Canvas c, #NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((IgnoreCallAdapter.ViewHolder) viewHolder).foreground;
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((IgnoreCallAdapter.ViewHolder) viewHolder).foreground;
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
#Override
public void clearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((IgnoreCallAdapter.ViewHolder) viewHolder).foreground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public float getSwipeThreshold(#NonNull RecyclerView.ViewHolder viewHolder) {
return 0.7f;
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
In item layout xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/row_view_height_ignore_list"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/ignore_item_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/ignore_item_bg">
</RelativeLayout>
<LinearLayout
android:id="#+id/ignore_item_foreground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_ignore_item_foreground"
android:orientation="horizontal"
android:visibility="visible">
</LinearLayout>
</LinearLayout>
</FrameLayout>
I'm trying to create a feature where if the user swipes LEFT on an item in the RecyclerView, the item will be deleted.
My RecyclerView is inside a Fragment which is inside a FrameLayout controlled by a BottomNavigation.
I have the code where it works when the RecyclerView is in its own Activity but when I transfer it into a Fragment, the swiping functionality breaks. I'm unable to swipe at all.
In my Fragment, I'm extending the RecyclerItemTouchHelperListener interface.
interface RecyclerItemTouchHelperListener {
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
}
Then I create a Callback
ItemTouchHelper.SimpleCallback ItemTouchHelperCallbackLeft = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this);
new ItemTouchHelper(ItemTouchHelperCallbackLeft).attachToRecyclerView(recyclerView);
Now I create a function called OnSwiped to handle the swiping.
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) {
if (viewHolder instanceof ListAdapter.ViewHolder) {
if (direction == ItemTouchHelper.LEFT) {
String cityName = stationList.get(viewHolder.getAdapterPosition()).getData().getCity();
//Create a backup of the deleted item in case user wants to undo delete
Station deletedStation = stationList.get(viewHolder.getAdapterPosition());
int deletedStationIndex = viewHolder.getAdapterPosition();
//Remove the item from RecyclerView
listAdapter.removeItem(deletedStationIndex);
Snackbar snackbar = Snackbar.make(coordinatorLayout, cityName + " removed from list!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
// undo is selected, restore the deleted item
listAdapter.restoreItem(deletedStation, position);
}
});
snackbar.show();
}
}
}
And here is the RecyclerItemTouchHelper class.
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 onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
final View foregroundView = ((ListAdapter.ViewHolder) viewHolder).listViewForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas canvas, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((ListAdapter.ViewHolder) viewHolder).listViewForeground;
getDefaultUIUtil().onDrawOver(canvas, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((ListAdapter.ViewHolder) viewHolder).listViewForeground;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas canvas, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((ListAdapter.ViewHolder) viewHolder).listViewForeground;
getDefaultUIUtil().onDraw(canvas, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive);
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
}
Keep in mind that everything works when the RecyclerView is inside its own Activity, but when I transfer my RecyclerView into a Fragment this swiping function does not work.
I've fixed my issue by moving the Callback after I initialize my RecyclerView.
recyclerView = itemView.findViewById(R.id.recyclerView);
ItemTouchHelper.SimpleCallback ItemTouchHelperCallbackLeft = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this);
new ItemTouchHelper(ItemTouchHelperCallbackLeft).attachToRecyclerView(recyclerView);
I want to swipe recyclerview both side left and right like below image:-
But I can't do I see many library but I find only one side swipe . I want both side swipe how I do that help me to do do this.
Thanks in advance
You can try below given one lib you just have to some modification
https://github.com/daimajia/AndroidSwipeLayout
Thanks!
It maybe late, but could help.
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_childs, container, false);
recyclerView = v.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false));
recyclerView.addItemDecoration(new VerticalItemDecoration());
recyclerView.setAdapter(new ChildCareAdapter());
touchHelper.attachToRecyclerView(recyclerView); // Attaching with RecyclerView
return v;
}
ItemTouchHelper touchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (i == ItemTouchHelper.LEFT) {
Toast.makeText(getContext(),"Swipe left",Toast.LENGTH_SHORT).show();
} else if (i == ItemTouchHelper.RIGHT) {
Toast.makeText(getContext(),"Swipe right",Toast.LENGTH_SHORT).show();
}
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
float alpha = 1 - (Math.abs(dX) / recyclerView.getWidth());
viewHolder.itemView.setAlpha(alpha);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
});
You need something like this:
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.LEFT){
Log.i("ItemSwipe", "LEFT");
}
else if (direction == ItemTouchHelper.RIGHT){
Log.i("ItemSwipe", "RIGHT");
}
}