when is Snackbar isQueued () used? (How to queue the snackbar) - android

If i call the snackbar multiple times in a row, only the last snackbar item is displayed.
e.g. with the codes below, only Item 3 would be shown. it seems that Snackbar.LENGTH_LONG is ignored (and set to zero?) for item 1 and 2.
Snackbar.make(view, "Item 1", Snackbar.LENGTH_LONG).show();
Snackbar.make(view, "Item 2", Snackbar.LENGTH_LONG).show();
Snackbar.make(view, "Item 3", Snackbar.LENGTH_LONG).show();
yet in the google documents, I see that it is possible to queue the messages.
public boolean isShownOrQueued ()
Returns whether this Snackbar is currently being shown,
or is queued to be shown next.
so how do we actually queue the snackbar?

Here is a partial snippet that solves your problem, although it might not
be the correct way to go about things:
//using a queue to pass string to the snackbar
Queue<String> myQueue = new LinkedList<String>();
myQueue.offer("item 1");
myQueue.offer("item 2");
myQueue.offer("item 3");
displaysnack(myQueue, view);
public void displaysnack(final Queue dQueue, final View view){
Snackbar.make(view, (String)dQueue.poll(), Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
switch (event) {
case Snackbar.Callback.DISMISS_EVENT_ACTION:
Toast.makeText(getApplicationContext(), "Clicked the action", Toast.LENGTH_LONG).show();
break;
//once the timeout expires, display the next one in the queue.
case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
Toast.makeText(getApplicationContext(), "Showing: "+ (dQueue.size()), Toast.LENGTH_SHORT).show();
if (dQueue.size()>0){displaysnack(dQueue, view);}
break;
case Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE:
//Toast.makeText(getApplicationContext(), "Multiple Shown", Toast.LENGTH_SHORT).show();
break;
}
}

I also needed to implement a queue of snackbars but did not find ready solution. So I decided to implement it on my own. You can try it https://github.com/AntonyGolovin/FluentSnackbar.
Just call important() on Builder and it will be added to the queue.

I also implemented my own, probably not the slickest but suited my needs. Its in C# for Xamarin though.
public class SnackbarManager : Snackbar.Callback
{
List<Snackbar> snackbarsWaiting;
List<Snackbar> snackbarsHolding;
public SnackbarManager()
{
snackbarsWaiting = new List<Snackbar>();
snackbarsHolding = new List<Snackbar>();
}
public void AddToQueue(Snackbar snackbar)
{
if (snackbar.Duration == Snackbar.LengthIndefinite) snackbar.SetDuration(Snackbar.LengthLong);
snackbar.SetCallback(this);
if (snackbarsWaiting.Count > 0 && snackbarsWaiting[0].IsShown) snackbarsHolding.Add(snackbar);
else snackbarsWaiting.Add(snackbar);
}
public void Show()
{
if (snackbarsWaiting.Count > 0 && !snackbarsWaiting[0].IsShown)
snackbarsWaiting[0].Show();
}
public override void OnDismissed(Snackbar snackbar, int evt)
{
base.OnDismissed(snackbar, evt);
snackbarsWaiting.Remove(snackbar);
if (snackbarsHolding.Count > 0)
{
snackbarsWaiting.AddRange(snackbarsHolding);
snackbarsHolding.Clear();
}
if (snackbarsWaiting.Count > 0) snackbarsWaiting[0].Show();
}
}

I met this problem too, this is my solution.
static List<Snackbar> snackBarList = new ArrayList<>();
public static void mySnackBar(CoordinatorLayout coordinatorLayout, String s,boolean queued) {
Snackbar snackbar = Snackbar.make(coordinatorLayout, s, Snackbar.LENGTH_SHORT);
if (queued) {
//if true set onDismiss CallBack
snackbar.setCallback(new Snackbar.Callback()
{
#Override
public void onDismissed(Snackbar currentSnackbar, int event) {
super.onDismissed(currentSnackbar, event);
//first remove current snackBar in List, then if List not empty show the first one
snackBarList.remove(currentSnackbar);
if (snackBarList.size() > 0)
snackBarList.get(0).show();
}
});
//add (set callback) snackBar to List
snackBarList.add(snackbar);
//the beginning
if (snackBarList.size() == 1)
snackBarList.get(0).show();
} else snackbar.show();
}

I've written a library that do just that. It also includes progressBar. Try it out https://github.com/tingyik90/snackprogressbar

Related

How to undo delete from Room database

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

How to use event onDismiss for Android Snackbar

It may be easier for those who are familiar with android code. I'am newbie here... I just working on to do an action after my snackbar dismissed. I read tutorial here but still not give me clear direction.
adapterTutorSubject.setOnClickListener(new AdapterTutorSubject.OnClickListener() {
#Override
public void onItemClick(View view, TutorSubject obj, int pos) {
Snackbar.make(parent_view, "Item " + obj.subjectName + " clicked", Snackbar.LENGTH_SHORT).show();
//On snackbar dismissed, then go to this page
Intent intent = new Intent(getApplicationContext(), ChapterListActivity.class);
startActivity(intent);
}
});
Thanks!
You could simply setCallback as shown here.
Modify the code like:
adapterTutorSubject.setOnClickListener(new AdapterTutorSubject.OnClickListener() {
#Override
public void onItemClick(View view, TutorSubject obj, int pos) {
Snackbar snack = Snackbar.make(parent_view, "Item " + obj.subjectName + " clicked", Snackbar.LENGTH_SHORT);
snack.setCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
if (event == Snackbar.Callback.DISMISS_EVENT_TIMEOUT) {
// Snackbar closed on its own
}
}
#Override
public void onShown(Snackbar snackbar) {
//Do something in shown
}
});
snack.show();
}
});
Hope it helps!!!

Show snackbar after popping fragment backstack

I'm trying to perform an action in one fragment, then move to the previous fragment and show a snackbar with a message, confirming the action from the first fragment. However, I'm creating and showing the snackbar in the first fragment (the one I'm moving from), and the snackbar does not appear in the fragment I'm changing to, probably because it's shown in the fragment I'm moving from.
I'm executing the code inside an alertdialog:
builder.setPositiveButton(positiveText, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dbHandler.deleteExercise(exercise.getId());
// Making the snackbar here did not work, either.
getFragmentManager().popBackStack();
Snackbar snack = Snackbar.make(mainLayout, "Exercise deleted", Snackbar.LENGTH_SHORT);
snack.show();
}
});
Any idea how I could go about achieving this?
Thanks!
EDIT:
I made this incredibly crude drawing of the flow to make it clearer what I'm trying to achieve.
I ended up implementing messaging between Fragments via the main Activity and checking for messages in the fragment's onResume() method:
MainActivity:
private String fragmentTransactionMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Snip
// Initialize fragment transaction message
fragmentTransactionMessage = null;
// Snip
}
// Three methods used to send information (text) between fragments
public void setFragmentTransactionMessage(String message) {
this.fragmentTransactionMessage = message;
}
public String getFragmentTransactionMessage() {
return fragmentTransactionMessage;
}
public void resetFragmentTransactionMessage() {
this.fragmentTransactionMessage = null;
}
Fragment 2:
// Remove exercise from database
dbHandler.deleteExercise(exercise.getId());
// Update message in main activity
((MainActivity)getActivity()).setFragmentTransactionMessage("Item deleted");
// Move to previous fragment
getFragmentManager().popBackStack();
Fragment 1:
#Override
public void onResume() {
super.onResume();
// Check for messages in main activity
String message = ((MainActivity)getActivity()).getFragmentTransactionMessage();
// If any, display as snackbar
if(message != null) {
Snackbar snack = Snackbar.make(mainLayout, message, Snackbar.LENGTH_SHORT);
snack.show();
// Reset message in activity
((MainActivity)getActivity()).resetFragmentTransactionMessage();
}
}
Another suggestion is to wrap getFragmentManager().popBackStack(); in a method which takes a Runnable Obj which will run after a chosen delay
For Example:
public void goBack(Runnable runAfterBack, long delay) {
mFragmentActivity.onBackPressed();
if (runAfterBack != null) {
(new Handler(Looper.getMainLooper())).postDelayed(runAfterBack, delay);
}
}
Usage:
goBack(new Runnable() {
#Override
public void run() {
Toast.makeText(mActivity, "STRING", Toast.LENGTH_SHORT).show();}
}, 1500);

android toggle button state always true

Been trying to use a ToggleButton to act as a bookmark kind of thing in my application. I am using this for the first time. I have declared my toggle button under onCreateView() as below:
bmark = (ToggleButton) v.findViewById(R.id.bmark);
bmark.setChecked(false);
I am trying to just toggle the state and show a Toast message! I tried the below:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
bmark.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean status;
if (bmark.isChecked()) status = true;
else status = false;
Log.w("Bmark status",String.valueOf(status));
if (status) {
bmark.setChecked(false);
Log.w("Bmark after true",String.valueOf(bmark.isChecked()));
Toast.makeText(getActivity(), "Bookmark removed!", Toast.LENGTH_SHORT).show();
} else {
bmark.setChecked(true);
Log.w("Bmark after false",String.valueOf(bmark.isChecked()));
Toast.makeText(getActivity(), "Post Bookmarked..!", Toast.LENGTH_SHORT).show();
}
}
});
Every time I press the button, the status is initially read "true", although I've set it to "false". After I call setChecked(false), it also becomes false. But when I click it again, it again reads "true" and instead of "false"
I dont know why its happening like this. I just want to toggle it every time I click it. Pls help me out! Thanks in advance :)
Change code to:
if (bmark.isChecked()){
status = true;
Toast.makeText(getActivity(), "Post Bookmarked..!",Toast.LENGTH_SHORT).show();
}
else {
status = false;
Toast.makeText(getActivity(), "Bookmark removed!", Toast.LENGTH_SHORT).show();
}
Toggle changes self checked status, You done that again so status was changed two times.
The problem is you're inverting the state of your button by the setChecked() calls in onClick().
Use an OnCheckedChangeListener instead of an OnClickListener, so you don't have to bother with keeping track of the status:
bmark.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// checked
Toast.makeText(getActivity(), "Post Bookmarked!", Toast.LENGTH_SHORT).show();
} else {
// not checked
Toast.makeText(getActivity(), "Bookmark removed!", Toast.LENGTH_SHORT).show();
}
}
});
You seem to be switching the button back to what it was previously in your statements. If you stop changing the button's state in the onClickListener, it should work just fine.
private boolean bmarkStatus = false;
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
bmark.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bmarkStatus = bmark.isChecked();
if (bmark.isChecked()) Toast.makeText(getActivity(), "Bookmark removed!", Toast.LENGTH_SHORT).show();
else Toast.makeText(getActivity(), "Bookmark added!", Toast.LENGTH_SHORT).show();
}
});
}

How to wait to Snackbar ? I want to know when it is closed

I want to get informed when Snackbar is closed. In an activity I use Snackbar and then I call another activity and I want to show Snackbar and when it has been already closed want to startActivity(NextActivity). How could I manage it?
Snackbar.make(view, "Some text", Snackbar.LENGTH_SHORT)
.setCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
startActivity(this, NextActivity.class);
}
}).show();
Define an action
.setAction("Go To Next Activity", mOnClickListener);
define onClickListenet as follows:
mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
snackBar.dismiss(); // to close the snackbar
// startActivity(nextActivityIntent)
}
};
More Info Here
I'm late but I hope it works for you
Scaffold.of(thisContext).showSnackBar(snackBar).closed.then((value){
print('snackbar closed');
});

Categories

Resources