Ответ 1
Чтобы создать Snackbar с контекстом приложения, который отображается в нескольких действиях:
- Получить
WindowManager
как системную службу - Создайте и добавьте
FrameLayout
(rootView) с типомWindowManager.LayoutParams.TYPE_TOAST
иWindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
вWindowManager
- Подождите, пока в
FrameLayout
(rootView) не будет вызываетсяFrameLayout.onAttachedToWindow()
- Получить маркер окна
FrameLayout
(rootView) с помощьюView.getWindowToken()
- Создайте
ContextThemeWrapper
с контекстом приложения и производным@style/Theme.AppCompat
- Используйте новый контекст для создания дополнительного
FrameLayout
(snackbarContainer) - Добавьте
FrameLayout
(snackbarContainer) с типомWindowManager.LayoutParams.TYPE_APPLICATION_PANEL
и флагомWindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- Подождите, пока в
FrameLayout
(snackbarContainer) вызываетсяView.onAttachedToWindow()
- Создайте Snackbar, как обычно, с помощью
FrameLayout
(snackbarContainer) - Установите
View.onDismissed()
обратный вызов в Snackbar и удалите FrameLayouts (rootView и snackbarContainer). - Показать закусочную
Snackbar.show()
Здесь рабочая оболочка ( ПРИМЕЧАНИЕ: Прокрутка для отклонения не работает. Возможно, кто-то еще найдет правильные флаги Исправлено CoordinatorLayout)WindowManager.LayoutParams
для получения событий касания
public class SnackbarWrapper
{
private final CharSequence text;
private final int duration;
private final WindowManager windowManager;
private final Context appplicationContext;
@Nullable
private Snackbar.Callback externalCallback;
@Nullable
private Action action;
@NonNull
public static SnackbarWrapper make(@NonNull Context applicationContext, @NonNull CharSequence text, @Snackbar.Duration int duration)
{
return new SnackbarWrapper(applicationContext, text, duration);
}
private SnackbarWrapper(@NonNull final Context appplicationContext, @NonNull CharSequence text, @Snackbar.Duration int duration)
{
this.appplicationContext = appplicationContext;
this.windowManager = (WindowManager) appplicationContext.getSystemService(Context.WINDOW_SERVICE);
this.text = text;
this.duration = duration;
}
public void show()
{
WindowManager.LayoutParams layoutParams = createDefaultLayoutParams(WindowManager.LayoutParams.TYPE_TOAST, null);
windowManager.addView(new FrameLayout(appplicationContext)
{
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
onRootViewAvailable(this);
}
}, layoutParams);
}
private void onRootViewAvailable(final FrameLayout rootView)
{
final CoordinatorLayout snackbarContainer = new CoordinatorLayout(new ContextThemeWrapper(appplicationContext, R.style.FOL_Theme_SnackbarWrapper))
{
@Override
public void onAttachedToWindow()
{
super.onAttachedToWindow();
onSnackbarContainerAttached(rootView, this);
}
};
windowManager.addView(snackbarContainer, createDefaultLayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, rootView.getWindowToken()));
}
private void onSnackbarContainerAttached(final View rootView, final CoordinatorLayout snackbarContainer)
{
Snackbar snackbar = Snackbar.make(snackbarContainer, text, duration);
snackbar.setCallback(new Snackbar.Callback()
{
@Override
public void onDismissed(Snackbar snackbar, int event)
{
super.onDismissed(snackbar, event);
// Clean up (NOTE! This callback can be called multiple times)
if (snackbarContainer.getParent() != null && rootView.getParent() != null)
{
windowManager.removeView(snackbarContainer);
windowManager.removeView(rootView);
}
if (externalCallback != null)
{
externalCallback.onDismissed(snackbar, event);
}
}
@Override
public void onShown(Snackbar snackbar)
{
super.onShown(snackbar);
if (externalCallback != null)
{
externalCallback.onShown(snackbar);
}
}
});
if (action != null)
{
snackbar.setAction(action.text, action.listener);
}
snackbar.show();
}
private WindowManager.LayoutParams createDefaultLayoutParams(int type, @Nullable IBinder windowToken)
{
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.gravity = GravityCompat.getAbsoluteGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, ViewCompat.LAYOUT_DIRECTION_LTR);
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
layoutParams.type = type;
layoutParams.token = windowToken;
return layoutParams;
}
@NonNull
public SnackbarWrapper setCallback(@Nullable Snackbar.Callback callback)
{
this.externalCallback = callback;
return this;
}
@NonNull
public SnackbarWrapper setAction(CharSequence text, final View.OnClickListener listener)
{
action = new Action(text, listener);
return this;
}
private static class Action
{
private final CharSequence text;
private final View.OnClickListener listener;
public Action(CharSequence text, View.OnClickListener listener)
{
this.text = text;
this.listener = listener;
}
}
}
ИЗМЕНИТЬ
После определения SnackbarWrapper
вы можете использовать его следующим образом:
final SnackbarWrapper snackbarWrapper = SnackbarWrapper.make(getApplicationContext(),
"Test snackbarWrapper", Snackbar.LENGTH_LONG);
snackbarWrapper.setAction(R.string.snackbar_text,
new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Action",
Toast.LENGTH_SHORT).show();
}
});
snackbarWrapper.show();
Если у вас нет темы, вы можете быстро определить ее в styles.xml
:
<style name="FOL_Theme_SnackbarWrapper" parent="@style/Theme.AppCompat">
<!--Insert customization here-->
</style>