Android 有没有办法让Snackbar在活动更改中保持不变?
虽然Android 有没有办法让Snackbar在活动更改中保持不变?,android,android-studio,Android,Android Studio,虽然Snackbar很漂亮,但它在更改活动时不会持久。如果我想在完成活动之前确认消息是使用Snackbar发送的,那么这种情况就很糟糕了。我曾考虑过在退出活动之前暂停代码,但我发现这是一种不好的做法 如果我所描述的不可能,是否有任何类型的材料设计信息?或者一种制作长方形祝酒词的方法;半径较小的圆边?更新:参见所选答案 我的问题的最佳解决方案是在显示Snackbar之后使用计时器,然后在计时器的run()方法中启动活动 Snackbar.show(); // Excluded make for b
Snackbar
很漂亮,但它在更改活动时不会持久。如果我想在完成活动之前确认消息是使用Snackbar
发送的,那么这种情况就很糟糕了。我曾考虑过在退出活动之前暂停代码,但我发现这是一种不好的做法
如果我所描述的不可能,是否有任何类型的材料设计信息?或者一种制作长方形祝酒词的方法;半径较小的圆边?更新:参见所选答案 我的问题的最佳解决方案是在显示
Snackbar
之后使用计时器,然后在计时器的run()
方法中启动活动
Snackbar.show(); // Excluded make for brevity.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
Intent chooseVideoIntent = new Intent(Intent.ACTION_GET_CONTENT); // Any type of content/file. Song, doc, video...
chooseVideoIntent.setType("video/*");
startActivityForResult(chooseVideoIntent, CHOOSE_VIDEO_REQUEST);
}
}, 2 * 1000);
更新:我发现通过使用findViewById(android.R.id.content)
作为Snackbar.make()
中的视图,Snackbar在片段更改中保持不变。要有一个矩形土司,为土司设置一个矩形背景,或者只为土司设置一个不同的背景颜色
请参考作为问题发布的位置。但这是一个可能的解决方案。如果我理解正确,您可以这样做:
活动A启动活动B以发送消息
消息发送后,您将显示一条确认消息
你回到活动A
您可以通过使用ActivityResult(是一个StackOverflow帖子,介绍了如何使用它)使用SnackBar来实现这一点
以下是步骤:
活动A使用startActivityForResult启动活动B
在活动B中完成你的任务
设置结果(查看上面的链接以了解)
完成活动
在活动A中,在OnActivityResult中获取该代码并显示
带有正确消息的SnackBar
这允许您在活动a中显示对应于活动B结果的Snackar
希望它能帮助您的问题创建一个包含应用程序上下文的Snackbar,该上下文在多个活动中可见:
将WindowManager
作为系统服务获取
创建并将类型为WindowManager.LayoutParams.type_TOAST
和WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
的FrameLayout
(rootView)添加到WindowManager
等待,直到在FrameLayout
(rootView)中调用onAttachedToWindow()
使用View.getWindowToken()
使用应用程序上下文和派生的@style/Theme.AppCompat
使用新上下文创建附加的框架布局
(snackbarContainer)
使用类型WindowManager.LayoutParams.type\u APPLICATION\u面板和标志WindowManager.LayoutParams.flag\u NOT\u TOUCH\u model添加此FrameLayout
(snackbarContainer)
等待,直到在FrameLayout
(snackbarContainer)中调用了onView.onAttachedToWindow()
使用FrameLayout
(snackbarContainer)像普通一样创建Snackbar
将View.onDismissed()
回调设置为Snackbar并删除框架布局(rootView和Snackbar容器)
显示snackbarsnackbar.Show()
这里有一个有效的包装器(注意:滑动关闭不起作用。可能其他人找到了正确的WindowManager。LayoutParams
标志接收由CoordinatorLayout修复的触摸事件):
编辑
定义了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>
以防万一有人需要在Xamarin这样做,我已经改编了,我发现这非常有用
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
using System;
public class SnackbarWrapper
{
private readonly string text;
private readonly int duration;
private readonly IWindowManager windowManager;
private readonly Context appplicationContext;
private Snackbar.Callback externalCallback;
private SnackbarAction action { get; set; }
public static SnackbarWrapper make(Context applicationContext, string text, int duration)
{
return new SnackbarWrapper(applicationContext, text, duration);
}
private SnackbarWrapper(Context appplicationContext, string text, int duration)
{
this.appplicationContext = appplicationContext;
var wm = appplicationContext.GetSystemService(Context.WindowService);
// We have to use JavaCast instead of a normal cast
this.windowManager = wm.JavaCast<IWindowManager>();
this.text = text;
this.duration = duration;
}
public void Show()
{
WindowManagerLayoutParams layoutParams = createDefaultLayoutParams(WindowManagerTypes.Toast, null);
var frameLayout = new FrameLayout(appplicationContext);
frameLayout.ViewAttachedToWindow += delegate
{
//this.onAttachedToWindow();
onRootViewAvailable(frameLayout);
};
windowManager.AddView(frameLayout, layoutParams);
}
private void onRootViewAvailable(FrameLayout rootView)
{
var ctw = new ContextThemeWrapper(appplicationContext, Resource.Style.Base_Theme_AppCompat);
CoordinatorLayout snackbarContainer = new CoordinatorLayout(ctw);
snackbarContainer.ViewAttachedToWindow += delegate
{
onSnackbarContainerAttached(rootView, snackbarContainer);
};
windowManager.AddView(snackbarContainer, createDefaultLayoutParams(WindowManagerTypes.ApplicationPanel, rootView.WindowToken));
}
private void onSnackbarContainerAttached(View rootView, CoordinatorLayout snackbarContainer)
{
Snackbar snackbar = Snackbar.Make(snackbarContainer, text, duration);
snackbar.SetCallback(new SnackbarCallbackImpl(rootView, snackbarContainer, windowManager));
if (action != null)
{
snackbar.SetAction(action.Text, action.Listener);
}
snackbar.Show();
}
private WindowManagerLayoutParams createDefaultLayoutParams(WindowManagerTypes type, IBinder windowToken)
{
WindowManagerLayoutParams layoutParams = new WindowManagerLayoutParams();
layoutParams.Format = Format.Translucent;
layoutParams.Width = ViewGroup.LayoutParams.MatchParent;
/* Si ponemos aqui WrapContent en alguna ocasion en la que haya un action largo y el texto tambien, el snackbar puede volverse como loco
* asi que usamos MatchParent. Aun asi sucede que a veces se puede mostrar en una linea o en dos el mismo texto, pero al menos no hace el temblor loco que de la otra forma*/
layoutParams.Height = ViewGroup.LayoutParams.MatchParent;
layoutParams.Gravity = GravityFlags.CenterHorizontal | GravityFlags.Bottom;
layoutParams.Flags = WindowManagerFlags.NotTouchModal;
layoutParams.Type = type;
layoutParams.Token = windowToken;
return layoutParams;
}
public SnackbarWrapper SetCallback(Snackbar.Callback callback)
{
this.externalCallback = callback;
return this;
}
public SnackbarWrapper SetAction(string text, Action<View> listener)
{
action = new SnackbarAction(text, listener);
return this;
}
}//class
internal class SnackbarAction
{
public string Text { get; set; }
public Action<View> Listener { get; set; }
public SnackbarAction(string text, Action<View> listener)
{
Text = text;
Listener = listener;
}
}
internal class SnackbarCallbackImpl : Snackbar.Callback
{
public Snackbar.Callback externalCallback { get; set; }
View rootView;
CoordinatorLayout snackbarContainer;
IWindowManager windowManager;
public SnackbarCallbackImpl(View rootView, CoordinatorLayout snackbarContainer, IWindowManager windowManager)
{
this.rootView = rootView;
this.snackbarContainer = snackbarContainer;
this.windowManager = windowManager;
}
public override void OnShown(Snackbar snackbar)
{
base.OnShown(snackbar);
externalCallback?.OnShown(snackbar);
}
public override void OnDismissed(Snackbar snackbar, int evt)
{
base.OnDismissed(snackbar, evt);
// Clean up (NOTE! This callback can be called multiple times)
if (snackbarContainer.Parent != null && rootView.Parent != null)
{
windowManager.RemoveView(snackbarContainer);
windowManager.RemoveView(rootView);
}
externalCallback?.OnDismissed(snackbar, evt);
}
}
使用Android.Content;
使用Android.Graphics;
使用Android.OS;
使用Android.Runtime;
使用Android.Support.Design.Widget;
使用Android.Views;
使用Android.Widget;
使用制度;
公共类SnackbarWrapper
{
私有只读字符串文本;
私有只读int持续时间;
专用只读iWindows管理器windowManager;
私有只读上下文AppApplicationContext;
私有Snackbar.callbackexternalcallback;
私有SnackbarAction操作{get;set;}
公共静态SnackbarWrapper生成(上下文应用程序上下文、字符串文本、int持续时间)
{
返回新的SnackbarWrapper(应用程序上下文、文本、持续时间);
}
专用SnackbarWrapper(上下文应用程序上下文、字符串文本、整型持续时间)
{
this.appapplicationcontext=appapplicationcontext;
var wm=appapplicationcontext.GetSystemService(Context.WindowService);
//我们必须使用JavaCast而不是普通的cast
this.windowManager=wm.JavaCast();
this.text=文本;
这个。持续时间=持续时间;
}
公开展览(
{
WindowManagerLayoutParams layoutParams=createDefaultLayoutParams(WindowManagerTypes.Toast,null);
var frameLayout=新的frameLayout(应用程序上下文);
frameLayout.ViewAttachedToWindow+=委托
{
//这个.onAttachedToWindow();
onRootViewAvailable(框架布局);
};
AddView(框架布局、布局参数);
}
私有void onRootView可用(FrameLayout rootView)
{
var ctw=new ContextThemeWrapper(appapplicationcontext,Resource.Style.Base\u Theme\u AppCompat);
CoordinatorLayout snackbarContainer=新的CoordinatorLayout(ctw);
snackbarContainer.ViewAttachedToWindow+=委托
{
OnNackBarContainerAttached(rootView、snackbarContainer);
};
AddView(snackbarContainer,createDefaultLayoutParams(WindowManagerTypes.ApplicationPanel,根目录
if(!Settings.canDrawOverlays(Activity.this){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, URI.parse("package:" + getPackageName()));
startActivityForResult(intent, REQ_CODE);
}
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
using System;
public class SnackbarWrapper
{
private readonly string text;
private readonly int duration;
private readonly IWindowManager windowManager;
private readonly Context appplicationContext;
private Snackbar.Callback externalCallback;
private SnackbarAction action { get; set; }
public static SnackbarWrapper make(Context applicationContext, string text, int duration)
{
return new SnackbarWrapper(applicationContext, text, duration);
}
private SnackbarWrapper(Context appplicationContext, string text, int duration)
{
this.appplicationContext = appplicationContext;
var wm = appplicationContext.GetSystemService(Context.WindowService);
// We have to use JavaCast instead of a normal cast
this.windowManager = wm.JavaCast<IWindowManager>();
this.text = text;
this.duration = duration;
}
public void Show()
{
WindowManagerLayoutParams layoutParams = createDefaultLayoutParams(WindowManagerTypes.Toast, null);
var frameLayout = new FrameLayout(appplicationContext);
frameLayout.ViewAttachedToWindow += delegate
{
//this.onAttachedToWindow();
onRootViewAvailable(frameLayout);
};
windowManager.AddView(frameLayout, layoutParams);
}
private void onRootViewAvailable(FrameLayout rootView)
{
var ctw = new ContextThemeWrapper(appplicationContext, Resource.Style.Base_Theme_AppCompat);
CoordinatorLayout snackbarContainer = new CoordinatorLayout(ctw);
snackbarContainer.ViewAttachedToWindow += delegate
{
onSnackbarContainerAttached(rootView, snackbarContainer);
};
windowManager.AddView(snackbarContainer, createDefaultLayoutParams(WindowManagerTypes.ApplicationPanel, rootView.WindowToken));
}
private void onSnackbarContainerAttached(View rootView, CoordinatorLayout snackbarContainer)
{
Snackbar snackbar = Snackbar.Make(snackbarContainer, text, duration);
snackbar.SetCallback(new SnackbarCallbackImpl(rootView, snackbarContainer, windowManager));
if (action != null)
{
snackbar.SetAction(action.Text, action.Listener);
}
snackbar.Show();
}
private WindowManagerLayoutParams createDefaultLayoutParams(WindowManagerTypes type, IBinder windowToken)
{
WindowManagerLayoutParams layoutParams = new WindowManagerLayoutParams();
layoutParams.Format = Format.Translucent;
layoutParams.Width = ViewGroup.LayoutParams.MatchParent;
/* Si ponemos aqui WrapContent en alguna ocasion en la que haya un action largo y el texto tambien, el snackbar puede volverse como loco
* asi que usamos MatchParent. Aun asi sucede que a veces se puede mostrar en una linea o en dos el mismo texto, pero al menos no hace el temblor loco que de la otra forma*/
layoutParams.Height = ViewGroup.LayoutParams.MatchParent;
layoutParams.Gravity = GravityFlags.CenterHorizontal | GravityFlags.Bottom;
layoutParams.Flags = WindowManagerFlags.NotTouchModal;
layoutParams.Type = type;
layoutParams.Token = windowToken;
return layoutParams;
}
public SnackbarWrapper SetCallback(Snackbar.Callback callback)
{
this.externalCallback = callback;
return this;
}
public SnackbarWrapper SetAction(string text, Action<View> listener)
{
action = new SnackbarAction(text, listener);
return this;
}
}//class
internal class SnackbarAction
{
public string Text { get; set; }
public Action<View> Listener { get; set; }
public SnackbarAction(string text, Action<View> listener)
{
Text = text;
Listener = listener;
}
}
internal class SnackbarCallbackImpl : Snackbar.Callback
{
public Snackbar.Callback externalCallback { get; set; }
View rootView;
CoordinatorLayout snackbarContainer;
IWindowManager windowManager;
public SnackbarCallbackImpl(View rootView, CoordinatorLayout snackbarContainer, IWindowManager windowManager)
{
this.rootView = rootView;
this.snackbarContainer = snackbarContainer;
this.windowManager = windowManager;
}
public override void OnShown(Snackbar snackbar)
{
base.OnShown(snackbar);
externalCallback?.OnShown(snackbar);
}
public override void OnDismissed(Snackbar snackbar, int evt)
{
base.OnDismissed(snackbar, evt);
// Clean up (NOTE! This callback can be called multiple times)
if (snackbarContainer.Parent != null && rootView.Parent != null)
{
windowManager.RemoveView(snackbarContainer);
windowManager.RemoveView(rootView);
}
externalCallback?.OnDismissed(snackbar, evt);
}
}