I'm trying to implement the undo delete on a snackbar when a recycler item is swiped by caching the item before its deleted and if undo is clicked, item should be added to recyclerview from cache.
or if there's a better way to achieve this.
Here's my current code
#Override
public void onSwiped(#NonNull final RecyclerView.ViewHolder viewHolder, int direction) {
viewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(ViewModel.class);
viewModel.getAllAppointments().observe(getViewLifecycleOwner(), new Observer<List<Appointments>>() {
#Override
public void onChanged(List<Appointments> appointments) {
mAdapter.submitList(appointments);
}
});
Snackbar.make(Objects.requireNonNull(getView()), "Appointment deleted", Snackbar.LENGTH_LONG)
.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
//undo delete
}
})
.setActionTextColor(getResources().getColor(R.color.colorPrimaryDark))
.addCallback(new Snackbar.Callback(){
#Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
if (event == DISMISS_EVENT_TIMEOUT || event == DISMISS_EVENT_SWIPE
|| event == DISMISS_EVENT_CONSECUTIVE || event == DISMISS_EVENT_MANUAL) {
viewModel.delete(mAdapter.getAppointAt(viewHolder.getAdapterPosition()));
}
}
})
.show();
}
For doing this work you can call show snackbar in onClick button, so when finish time snackbar invoke delete function (delete from adapter, list, and database or data source), so before this time use can remove item just from adapter temporally for only animat similar (not remove from list) and if user clicked on undo button doing refresh list from database or your data source
Related
I use RecyclerView for searching for users.
the search works fine, but the follow button in the ItemView is not.
Whenever I press the follow button, the text on the button is supposed to change from "follow" to "following". and and when I press it again it supposed to change from "following" to "follow". it was working just fine and suddenly it just stopped working!
Whenever I press the button it changes from "follow" to "following" for a sec and then it return to "follow". I couldn't figure out the reason!
Here is my code.
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final User user = mUsers.get(position);
isFollowing(user.getId(), holder.btn_follow);
holder.btn_follow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.btn_follow.getText().toString().equals("follow"))
{
FirebaseDatabase.getInstance().getReference().child("Follow").child(firebaseUser.getUid())
.child("following").child(user.getId()).setValue(true);
FirebaseDatabase.getInstance().getReference().child("Follow").child(user.getId())
.child("followers").child(firebaseUser.getUid()).setValue(true);
addNotifications(user.getId());
}
else
{
FirebaseDatabase.getInstance().getReference().child("Follow").child(firebaseUser.getUid())
.child("following").child(user.getId()).removeValue();
FirebaseDatabase.getInstance().getReference().child("Follow").child(user.getId())
.child("followers").child(firebaseUser.getUid()).removeValue();
// FirebaseDatabase.getInstance().getReference("Notifications").child(user.getId()).removeValue();
}
}
});
}
Here is the isFollowing function:
private void isFollowing(final String userid, final Button button) {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference()
.child("Follow").child(firebaseUser.getUid()).child("following");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.child(userid).exists()) {
button.setText("following");
button.setBackgroundResource(R.drawable.buttonafter);
} else {
button.setText("follow");
button.setBackgroundResource(R.drawable.buttonbefore);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
It keeps returning to the default "follow" text on the button, so it is not allowing me to follow anyone.
Please help if you know what's causing this problem.
Move your implementation of onClickListener() of your button from onBindViewHolder() method to your ViewHolder class of your RecyclerView. It's not a good idea to implement listeners in onBindViewHolder().
I have an activity with a Spinner (with his own adapter) and another Adapter that manages the recycler view with its list . I'm trying to implement the following logic : when the list of the recycler is empty the spinner should be enabled , otherwise it should be disabled until the list is empty again :
sGames.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (pokemonCardsGridAdapter.getItemCount() == 0) {
v.performClick();
v.setEnabled(true);
} else {
v.setEnabled(false);
Toast.makeText(PokemonTeambuilderEditorActivity.this, "The list is full", Toast.LENGTH_SHORT).show();
}
return false;
}
});
However , this only works the first time , once the spinner gets disabled , it never receive any touch events again . How can I fix this?
Solved using registerAdapterDataObserver:
pokemonCardsGridAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
public void onChanged() {
sGames.setEnabled(false);
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
if (pokemonCardsGridAdapter.getItemCount() == 0) {
sGames.setEnabled(true);
}
}
});
I can't handle clicks on recycerView body (NOT ITEMS),
but when I setOnClickListener on my recycler, it does not work.
I tried clickable="true" in xml, but does not work.
recycler.setOnClickListener {
Toast.makeText(context,"Click on recyclerView",Toast.LENGTH_SHORT).show()
}
Just use a Touch Listener :
recyclerView.setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
Toast.makeText(context, "Clicked", LENGTH_SHORT).show()
true
}
else -> false
}
}
You need to pass your click listener on "onBindViewHolder()"
That way you will be able to receive where the user clicked and perform something with it.
public void onBindViewHolder(LanguageAdapter.ViewHolder holder, final int position) {
final String name = names.get(position);
holder.main_item_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
}
And what you want to do is to set the click listener on your root layout from your items
I have a RecyclerView with post cards. So there is a like button in every post card. When I tap on a like button. Sometimes it works fine and updates on current item. But after some scroll when I tap on like button it updates on another item simultaneously.
It doesn't send that data to server. But, only the view is updated. Then when I scroll up and down again. The data goes back to normal.
Problem is in the following onClick method:-
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.child("like").exists()){
holder.like.setImageResource(R.drawable.ic_favorite_red_500_36dp);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").removeValue();
}
});
}else if(dataSnapshot.child("dislike").exists()) {
holder.like.setImageResource(R.drawable.brokenheart);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").removeValue();
}
});
}else{
holder.like.setImageResource(R.drawable.ic_favorite_border_red_500_36dp);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").removeValue();
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").setValue(true);
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
holder.like.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").removeValue();
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").setValue(true);
return true;
}
});
Full Adapter class https://pastebin.com/UnFGahWT
Try the following:-
Set Your on click listeners in the public ViewHolder(View itemView) method and make Your ViewHolder class implement the View.OnClickListener.
In Adapter add:
public Topic getItem(int position) {
return topics.get(position);
}
In ViewHolder's onClick method add:
int position = getAdapterPosition();
if (position == RecyclerView.NO_POSITION) return;
item = getItem(position);
Thus You will get the exact object You need to change or do something with it.
i facing a problem in recyclerview's item.
My Adapter's code :
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(viewable==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewable = true;
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
Like my code above, I want to hide mFormBookingan after mSendBooking has pressed. mFormBookingan never show anymore until user calls it again.
I have tried with a lot of ways but still can't find like what i need. After i press mSendBooking the form hide, but when i send new item to recyclerview, the from mFormBookingan that has been hide, appears again.
My Question, how to hide mFormBookingan forever? Until user call it again.
Thank in advance, i will appreciate anyone who help me for this one.
I not sure what the clear situation you want.
But if you want to set View invisible you can try this code then check it.
You need to add ismFormBookingVisible in viewHolder class as a boolean attribute.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(holder.ismFormBookingVisible==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.ismFormBookingVisible = false;
Log.d("TAG", "CEK 2 : " + viewable);
}
Try this :
Create a boolean in your model class "Profile" to keep track of visibility of button : say boolean isBookingVisible;
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
if(!item.isBookingVisible){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
item.isBookingVisible = false;
//Use notiyItemChanged(position); or notifyDataSetChanged(); here as per your selection criterion
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
You may have to call notifyDataSetChanged() after changing the value of viewable.
onBindViewHolder will be called when you notify your data set.
So you need to save the viewable in mListChatting. When you click the button, change the viewable in the mListChatting.
And then, change the code in onBindViewHolder
holder.mFormBookingan.setVisibility(item.getViewable() ? View.VISIBLE : View.GONE);
On refresh android will destroy the view and create new view with new adapter data. So you have to track the current state (visibility) of mFormBookingan. You can use a simple visibility list. When mFormBookingan state (visibility) change update it in visibility list so that whenever the list is refreshed, you can use it to check and set the last state (visibility) of your mFormBookingan. Here is an example
private ArrayList<Boolean> isVisible;
public MyAdapter(ArrayList<Boolean> isVisible){
// initial state list of mFormBookingan for each row of list
this.isVisible = isVisible;
}
public void onBindViewHolder(final MyViewHolder holder, final int position) {
if (isVisible.get(position)) {
holder.mFormBookingan.setVisibility(View.VISIBLE);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
}
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.mFormBookingan.getVisibility() == View.GONE){
holder.mFormBookingan.setVisibility(View.VISIBLE);
isVisible.set(position, true);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
isVisible.set(position, false);
}
}
});
}
when you click mSendBooking the mFormBookingan visibility will change and it will remain same after sending new item to recyclerview.