Як мені повідомити, коли Snackbar відмовився?


82

Я використовую Snackbar з com.android.support:design:22.2.0бібліотеки. Я використовую його, щоб скасувати видалення. Щоб полегшити своє життя, я збираюся зробити так, щоб користувальницький інтерфейс здавався таким, що речі насправді видаляються з джерела даних, і якщо кнопку скасування на панелі перекусів не натиснуто, фактично виконайте видалення з джерела даних. Отже, я хочу знати, коли Snackbar більше не видно, тому безпечно видаляти елементи.

Я можу зателефонувати getView () на Snackbar, але я не впевнений, який слухач я повинен використовувати. Я намагався, setOnSystemUiVisibilityChangeListener()але це не спрацювало, я вважаю, що це лише для системного рядка стану.

Крім того, Snackbar не можна розширити, оскільки він має приватний конструктор.


1
Ця функція буде в наступному випуску бібліотеки дизайну підтримки
Тайлер Пфафф

Відповіді:


179

Бібліотека дизайну Google підтримує зворотні виклики Snackbar у версії 23. Див. Документи Snackbar та Документи зворотного виклику . Потім ви отримаєте сповіщення, коли Snackbar буде звільнено (а також коли буде показано), а також тип звільнення, якщо це корисно для вас:

snackbar.addCallback(new Snackbar.Callback() {

    @Override
    public void onDismissed(Snackbar snackbar, int event) {
      //see Snackbar.Callback docs for event details
      ...  
    }

    @Override
    public void onShown(Snackbar snackbar) {
       ...
    }
  });

13
setCallback () тепер застарілий. Замість цього використовуйте addCallback ()
jds17,

41
snackbar.addCallback(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) {
        ...
    }
});

4
приємно згадати подію, тому що onDismissed також викликається при натисканні на actionText
Amro elaswar

2
У більшості випадків, мабуть, найкраще перевірити if (event != Snackbar.Callback.DISMISS_EVENT_ACTION)замість цього, інакше ваша логіка відхилення не запускатиметься, якщо користувач відмовляється вручну або закусочна відхиляється іншою послідовною закусочною.
shyamal

Дякую за цей рядокevent == Snackbar.Callback.DISMISS_EVENT_TIMEOUT
Пратік Бутані

18

Snackbar.addCallback у kotlin

val snackBar = Snackbar
                .make(view, "Text Snackbar", Snackbar.LENGTH_LONG)
                .addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
                    override fun onShown(transientBottomBar: Snackbar?) {
                        super.onShown(transientBottomBar)
                    }

                    override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
                        super.onDismissed(transientBottomBar, event)
                    }
                })

        val snackBarView = snackBar.view
        snackBarView.setBackgroundColor(Color.RED)
        snackBar.show()

16

Нещодавно я сам натрапив на це питання, коли для прокрутки та показу Snackback було показано занадто багато, перш ніж перший навіть зник. Мені довелося знайти спосіб дізнатись, чи мала програма встановлювати Snackbar.

Я особисто знайшов це рішення.

Це правда, що сама Snackbar не пропонує жодного прослуховувача для свого стану / видимості, але ви все одно можете отримати об'єкт перегляду із Snackbar (getView ();). З об’єкта перегляду ви можете використовувати широкий спектр методів для додавання слухачів.

Для його реалізації вам слід вийти із загального використання "все в одному рядку" Toast / Snackbar, оскільки додавання слухачів повертає void .

Я особисто знайшов OnAttachStateChangeListener, щоб задовольнити мої потреби.

Видалення снайпера з моїм кодом на випадок, якщо це може стати для вас корисним.

Snackbar snack = Snackbar.make(getView(), "My Placeholder Text", Snackbar.LENGTH_LONG);

snack.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
    @Override
        public void onViewAttachedToWindow(View v) {
            canDisplaySnackbar = false;
        }

    @Override
    public void onViewDetachedFromWindow(View v) {

        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                canDisplaySnackbar = true;

                }
        }, 1000);
    }
});
snack.show();

Зверніть увагу, що це лише моя реалізація для власної проблеми, обробник із postDelayed Runnable може навіть не відповідати вашому випадку. Це було лише для того, щоб дати загальне уявлення про реалізацію, яку я запропонував, використовуючи фрагмент, яким я вже володію.


4
and_dev's andswer - зараз найкраща відповідь.
Іслам А. Хасан,

12

Щоб отримати сповіщення, коли закусочна буде показана або відхилена, ви можете надати Snackbar.Callback через setCallback (Callback).


setCallBack зараз застарілий, замість нього використовуйте addCallBack
mjn42

5

onDismissed також викликається, коли натискається дія Текст, з цієї причини потрібно поставити одну умову типу

event == Snackbar.Callback.DISMISS_EVENT_TIMEOUT

А тепер новий код виглядає як нижче.

final Snackbar snackBar = Snackbar.make(findViewById(R.id.root_layout), result, Snackbar.LENGTH_LONG);

snackbar.addCallback(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) {
...
}
});
snackBar.show();

Відповіді лише на код не заохочуються, оскільки вони не надають багато інформації для майбутніх читачів, будь ласка, надайте деякі пояснення того, що ви написали
WhatsThePoint

У більшості випадків, мабуть, найкраще перевірити if (event != Snackbar.Callback.DISMISS_EVENT_ACTION)замість цього, інакше ваша логіка відхилення не запускатиметься, якщо користувач відмовляється вручну або закусочна відхиляється іншою послідовною закусочною.
shyamal


3

Наразі неможливо отримати сповіщення, коли Snackbar закінчив відображення.

У цьому потоці обговорюється обхідний шлях на основі таймера на час відображення Snackbar. Снек-бар у бібліотеці підтримки не включає OnDismissListener ()?

Одне питання, яке слід врахувати з цим обхідним шляхом, - це можливість перезапуску тривалості Snackbar. Специфікація дизайну матеріалу для Snackbar говорить, що це станеться, якщо відобразиться не пов'язане діалогове вікно або спливаюче вікно.


1

В даний час ви не можете цього досягти.

Немає слухача, якому зателефонували, коли закусочна зменшена.

Найпростіший спосіб це зробити - тимчасово зберегти запис в іншому місці (навіть локальну змінну), а потім знову вставити його, якщо вони випадково натиснули кнопку скасування.


1
    snackbar.addCallback(new Snackbar.Callback() {
        public void onShown(Snackbar snackbar) {
           //  on show  
        }
 public void onDismissed(Snackbar snackbar, int event) {
          //  on dismiss  
        }
      });

Будь ласка, надайте опис / пояснення разом із фрагментом коду.
Janis F

1

У мене точно така ж проблема, як і у вас. Моє рішення - ...

              final Snackbar povrati_obrisani_unos = Snackbar.make (coordinatorLayout, "Ponisti brisanje", Snackbar.LENGTH_INDEFINITE)
                    .addCallback (new Snackbar.Callback (){
                        @Override
                        public void onDismissed(Snackbar transientBottomBar, int event) {
                            super.onDismissed (transientBottomBar, event);
                            if(event==DISMISS_EVENT_SWIPE){//here we detect if snackbar is swipped away and not cliked (which is undo in my case)
                                Uri uriDelete = Uri.parse (obrisano.getImageuri ());
                                ContentResolver contentResolver = getContentResolver();
                                contentResolver.delete (uriDelete, null, null);
                                Toast.makeText (MainActivity.this,
                                        "Ocitavanje i slika su trajno obrisani", Toast.LENGTH_SHORT).show ();
                            }

Це все, не потрібно копіювати-вставляти snackbar.action, який скасовується. Хочу бути зрозумілим, як я, можливо, можу тут.

З повагою Ненад


0

Завдяки @SergeyMilakov в Котлин це:

@SuppressLint("WrongConstant") // Suppress an error when set duration.
private fun showSnackbar() {
    val DURATION = 5000

    Snackbar.make(view!!, "Remove item?"), DURATION).apply {
        setAction("Undo") {
            // Your action when a button is clicked.
        }
        addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
            /* override fun onShown(transientBottomBar: Snackbar?) {
                super.onShown(transientBottomBar)
                Timber.d("*** onShown")
            }*/

            override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
                super.onDismissed(transientBottomBar, event)
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    // Your action when the Snackbar is closed and the button was not clicked.
                }

            }
        })
        view.setBackgroundColor(ContextCompat.getColor(context, R.color.black))
        setActionTextColor(ContextCompat.getColor(context, R.color.yellow))
        show()
    }
}

Зауважте, що Snackbar відображається, навіть якщо ви переходите на інші екрани (наприклад, назад). Тож, не забудьте перевірити, чи виконуєте ви дії на правому екрані.

Також Snackbarне відновлюється після обертання екрана.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.