烤面包等同于 Xamarin 表格

有没有办法使用 Xamarin 窗体(不是 Android 或 iOS 特有的)来弹出一个窗口,就像 Android 对 Toast 所做的那样,不需要用户交互,并在一段(短)时间后消失?

From searching around all I'm seeing are alerts that need user clicks to go away.

80807 次浏览

Forms 中没有内置的机制,但是这个 nuget 包提供了类似的东西

https://github.com/EgorBo/Toasts.Forms.Plugin

注意: 这些不是问题中要求的 Android 风格的祝酒词,而是 UWP 风格的祝酒词,是系统范围的通知。

下面是我在 Xamarin.iOS 中用来显示祝酒词的代码片段

  public void ShowToast(String message, UIView view)
{
UIView residualView = view.ViewWithTag(1989);
if (residualView != null)
residualView.RemoveFromSuperview();


var viewBack = new UIView(new CoreGraphics.CGRect(83, 0, 300, 100));
viewBack.BackgroundColor = UIColor.Black;
viewBack.Tag = 1989;
UILabel lblMsg = new UILabel(new CoreGraphics.CGRect(0, 20, 300, 60));
lblMsg.Lines = 2;
lblMsg.Text = message;
lblMsg.TextColor = UIColor.White;
lblMsg.TextAlignment = UITextAlignment.Center;
viewBack.Center = view.Center;
viewBack.AddSubview(lblMsg);
view.AddSubview(viewBack);
roundtheCorner(viewBack);
UIView.BeginAnimations("Toast");
UIView.SetAnimationDuration(3.0f);
viewBack.Alpha = 0.0f;
UIView.CommitAnimations();
}

有一个简单的解决办法。通过使用 依赖服务,你可以很容易地在 Android 和 iOS 中获得类似吐司的方法。

在公共包中创建接口。

public interface IMessage
{
void LongAlert(string message);
void ShortAlert(string message);
}

安卓部分

[assembly: Xamarin.Forms.Dependency(typeof(MessageAndroid))]
namespace Your.Namespace
{
public class MessageAndroid : IMessage
{
public void LongAlert(string message)
{
Toast.MakeText(Application.Context, message, ToastLength.Long).Show();
}
    

public void ShortAlert(string message)
{
Toast.MakeText(Application.Context, message, ToastLength.Short).Show();
}
}
}

IOS 版块

在 iOs 中没有像 Toast 这样的本地解决方案,所以我们需要实现我们自己的方法。

[assembly: Xamarin.Forms.Dependency(typeof(MessageIOS))]
namespace Your.Namespace
{
public class MessageIOS : IMessage
{
const double LONG_DELAY = 3.5;
const double SHORT_DELAY = 2.0;


NSTimer alertDelay;
UIAlertController alert;


public void LongAlert(string message)
{
ShowAlert(message, LONG_DELAY);
}
public void ShortAlert(string message)
{
ShowAlert(message, SHORT_DELAY);
}


void ShowAlert(string message, double seconds)
{
alertDelay = NSTimer.CreateScheduledTimer(seconds, (obj) =>
{
dismissMessage();
});
alert = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert);
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null);
}


void dismissMessage()
{
if (alert != null)
{
alert.DismissViewController(true, null);
}
if (alertDelay != null)
{
alertDelay.Dispose();
}
}
}
}

Please note that in each platform, we have to register our classes with DependencyService.

现在您可以访问吐司服务在我们的项目的任何地方。

DependencyService.Get<IMessage>().ShortAlert(string message);
DependencyService.Get<IMessage>().LongAlert(string message);

We'd normally use Egors Toasts plugin, but as it requires permissions on iOS for a current project we've gone a different route using Rg.Plugins.Popup nuget (https://github.com/rotorgames/Rg.Plugins.Popup).

我写了一个类型为 PopupPage 的基本 xaml/cs 页面,

<?xml version="1.0" encoding="utf-8" ?>
<popup:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:popup="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
x:Class="YourApp.Controls.ToastPage">
...

并让一个服务创建它,你在应用程序启动时注册的接口或者使用 Xamarin.Forms.DependencyService来获取服务也是可行的。

该服务在 PopupPage 派生页面上显示新闻,并且

await PopupNavigation.PushAsync(newToastPage);
await Task.Delay(2000);
await PopupNavigation.PopAllAsync();

用户可以通过在页面显示之外点击弹出页面(假设它还没有填满屏幕)来解除弹出页面。

这似乎在 iOS/Droid 上运行良好,但如果有人知道这是一种危险的做法,我愿意纠正。

@ MengTim,为了解决@alex-chengalan 的解决方案中的多重吐司问题,我简单地将所有内容包装在 ShowAlert()中,检查 alertalertDelay是否为空,然后在 DismissMessage中将 alertalertDelay为空。

void ShowAlert(string message, double seconds)
{
if(alert == null && alertDelay == null) {
alertDelay = NSTimer.CreateScheduledTimer(seconds, (obj) =>
{
DismissMessage();
});
alert = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert);
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null);
}
}


void DismissMessage()
{
if (alert != null)
{
alert.DismissViewController(true, null);
alert = null;
}
if (alertDelay != null)
{
alertDelay.Dispose();
alertDelay = null;
}
}

这似乎至少清除了 UI 挂起,如果您正在寻找一个快速修复。我试图在一个新页面的导航栏中显示这个祝酒词,并且认为 PresentViewController的设置实际上取消了我的导航栏。对不起,我没有在帖子里评论,我的名声太低了: (

下面是 Alex Cheng alan 的 iOS 密码的一个版本,它可以在显示多条消息时避免界面粘连..。

public class MessageIOS : IMessage
{
const double LONG_DELAY = 3.5;
const double SHORT_DELAY = 0.75;


public void LongAlert(string message)
{
ShowAlert(message, LONG_DELAY);
}


public void ShortAlert(string message)
{
ShowAlert(message, SHORT_DELAY);
}


void ShowAlert(string message, double seconds)
{
var alert = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert);


var alertDelay = NSTimer.CreateScheduledTimer(seconds, obj =>
{
DismissMessage(alert, obj);
});


UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null);
}


void DismissMessage(UIAlertController alert, NSTimer alertDelay)
{
if (alert != null)
{
alert.DismissViewController(true, null);
}


if (alertDelay != null)
{
alertDelay.Dispose();
}
}
}

为了补充 Alex 的回答,下面是 UWP 的变体:

public class Message : IMessage {
private const double LONG_DELAY = 3.5;
private const double SHORT_DELAY = 2.0;


public void LongAlert(string message) =>
ShowMessage(message, LONG_DELAY);


public void ShortAlert(string message) =>
ShowMessage(message, SHORT_DELAY);


private void ShowMessage(string message, double duration) {
var label = new TextBlock {
Text = message,
Foreground = new SolidColorBrush(Windows.UI.Colors.White),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
var style = new Style { TargetType = typeof(FlyoutPresenter) };
style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Windows.UI.Colors.Black)));
style.Setters.Add(new Setter(FrameworkElement.MaxHeightProperty, 1));
var flyout = new Flyout {
Content = label,
Placement = FlyoutPlacementMode.Full,
FlyoutPresenterStyle = style,
};


flyout.ShowAt(Window.Current.Content as FrameworkElement);


var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(duration) };
timer.Tick += (sender, e) => {
timer.Stop();
flyout.Hide();
};
timer.Start();
}
}

Coloring and styling is up to you, the MaxHeightis actually required to keep the height at the minimum.

这是我改进的 ShowAlert版本的伊恩沃伯顿的版本,以确保吐司是显示甚至在弹出页面。 此外,如果用户单击吐司外部,吐司将被解除。 I used UIAlertControllerStyle.ActionSheet that look likes toast but it also work with UIAlertControllerStyle.Alert

    void ShowAlert(string message, double seconds)
{
var alert = UIAlertController.Create(null, message, UIAlertControllerStyle.ActionSheet);


var alertDelay = NSTimer.CreateScheduledTimer(seconds, obj =>
{
DismissMessage(alert, obj);
});


var viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (viewController.PresentedViewController != null)
{
viewController = viewController.PresentedViewController;
}
viewController.PresentViewController(alert, true, () =>
{
UITapGestureRecognizer tapGesture = new UITapGestureRecognizer(_ => DismissMessage(alert, null));
alert.View.Superview?.Subviews[0].AddGestureRecognizer(tapGesture);
});
}

我希望这能帮到别人!

上面的 iOS 答案对我有用,但是有一个小问题——警告: 尝试显示 UIAlertController... 其视图不在窗口层次结构中!

After some search, I came across this unrelated answer which helped. The poster commented "This looks stupid but works", which is right on both counts.

因此,我用这些代码行修改了上面的 ShowAlert ()函数,它们似乎可以工作:

    var rootVC = UIApplication.SharedApplication.KeyWindow.RootViewController;
while ( rootVC.PresentedViewController != null) {
rootVC = rootVC.PresentedViewController;
}
rootVC.PresentViewController( alert, true, null);

您可以使用 IUserDialogNuGet并简单地使用 toastAlert

var toastConfig = new ToastConfig("Toasting...");
toastConfig.SetDuration(3000);
toastConfig.SetBackgroundColor(System.Drawing.Color.FromArgb(12, 131, 193));


UserDialogs.Instance.Toast(toastConfig);

UWP 的

public void ShowMessageFast(string message)
{
ToastNotifier ToastNotifier = ToastNotificationManager.CreateToastNotifier();
Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
Windows.Data.Xml.Dom.XmlNodeList toastNodeList = toastXml.GetElementsByTagName("text");
toastNodeList.Item(0).AppendChild(toastXml.CreateTextNode("Test"));
toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(message));
Windows.Data.Xml.Dom.IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
Windows.Data.Xml.Dom.XmlElement audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-winsoundevent:Notification.SMS");


ToastNotification toast = new ToastNotification(toastXml);
toast.ExpirationTime = DateTime.Now.AddSeconds(4);
ToastNotifier.Show(toast);
}

You can use 用户对话框 Package from nuget and code like below,

Acr.UserDialogs.UserDialogs.Instance.Toast(Message, new TimeSpan(3));

你可以使用 DisplayAlert("", "", "", "" );

I would recommend Plugin.Toast library from nuget. It works well.

CrossToastPopUp.Current.ShowToastMessage("my toast message");

或者来自 ACR.UserDialogs Nuget 库

UserDialogs.Instance.ShowLoading("Loading");

我用过 Https://github.com/ishrakland/toast/ 进去 Https://www.nuget.org/packages/plugin

Example:

CrossToastPopUp.Current.ShowToastMessage ("Loading", Plugin.Toast.Abstractions.ToastLength.Short);

试试看。

我定制了一个自定义的弹出窗口与 Rg。插件。弹出 NuGet 这是一个例子:

 <pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="600"
DurationOut="600"
EasingIn="Linear"
EasingOut="Linear"/>
</pages:PopupPage.Animation>


<Frame CornerRadius="10"
HeightRequest="30"
VerticalOptions="End"
HorizontalOptions="Fill"
HasShadow="False"
Padding="0" Margin="40,50"
OutlineColor="LightGray">
<StackLayout
Opacity="0.4"
BackgroundColor="White">
<Label
x:Name="lbl"
LineBreakMode="WordWrap"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"


VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" TextColor="Black" FontSize="12">
<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="NewJuneMedium" />
</OnPlatform>
</Label.FontFamily>
</Label>
</StackLayout>
</Frame>

然后在你的基本内容页面中,你可以添加以下代码,显示和隐藏一段时间后的“吐司”:

public async void showpopup(string msg)
{
await Navigation.PushPopupAsync(new Toast(msg));
await Task.Delay(3000);
await Navigation.PopPopupAsync(true);
}

您可以从 Xamarin 社区工具包包中使用 SnackBar,它在本地支持的平台中使用本地实现,因为在 API 级别30中不推荐使用 Toast,没有 Action 的 SnackBar相当于 Toast。

此方法在 API 级别30中已被弃用。 不推荐使用自定义敬酒视图。应用程序可以使用 makText (android.content)创建一个标准的文本吐司。语境,java.lang。方法,或者在前台使用 Snackbar。从 Android Build.VERION _ CODES # R 开始,针对 API 级别 Build.VERION _ CODES # R 或更高级别的后台应用程序将不会显示自定义吐司视图。(来源).

从 Xamarin 社区工具包开始

  1. 在所有项目上安装软件包
  2. 包括名称空间 using Xamarin.CommunityToolkit.Extensions;
  3. 在页面代码隐藏中,在事件上显示 SnackBar
await this.DisplayToastAsync("This is a Toast Message");
await this.DisplayToastAsync("This is a Toast Message for 5 seconds", 5000);

您可以指定 SnackBar 消失的持续时间(以毫秒为单位) ,或者保留默认的持续时间(等于3秒)。

enter image description here


资源

SnackBar Sample

官方回购 < a href = “ https://github.com/xamarin/XamarinCommunityToolkit”rel = “ norefrer”> https://github.com/xamarin/xamarincommunitytoolkit

官方文档 < a href = “ https://Learn.microsoft.com/en-us/xamarin/community-toolkit/”rel = “ norefrer”> https://learn.microsoft.com/en-us/xamarin/community-toolkit/


剪辑

  1. 锚定吐司: 你可以通过简单地从视图(锚定)对象而不是页面实例(this)调用扩展方法 DisplayToastAsync()来锚定视图(如上面的屏幕截图)上方的吐司:
<Button x:name="floatingButton" .../>


await floatingButton.DisplayToastAsync("This is a Toast Message for 5 seconds", 5000);
  1. 填充和角半径: (从 xct 版本1.3.0预览 -1开始)

你可以像下面的例子一样设置 Toast 的角半径和填充:

var messageOptions = new MessageOptions
{
Message = "Toast with Padding and round corner",
Foreground = Color.White,
Font = Font.SystemFontOfSize(16),
Padding = new Thickness(20)
};


var options = new ToastOptions
{
MessageOptions = messageOptions,
CornerRadius = new Thickness(40, 40, 0, 0),
BackgroundColor = Color.FromHex("#CC0000")
};


await this.DisplayToastAsync(options);

enter image description here

enter image description here

PS: 同样的属性也可以应用于 SnackBar视图。


编辑2

如果 xct SnackBar提供的内容不能满足您的要求,或者您希望不仅显示文本,还要显示一些复杂的视图,那么您可能不得不使用 popup

安装螺母 翻译: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对:。 它包含的 干杯正是你要找的。

ToastEvent toastEvent = new ToastEvent();
var toastConfig = new ToastConfig(toastEvent,"Toasting...","");
toastConfig.SetDuration(2000);


UserDialogs.Instance.Toast(toastConfig);

目前在 android 中使用 xamarin:

//access mainthread
MainThread.BeginInvokeOnMainThread(() =>
{
Toast.MakeText(Application.Context, message, ToastLength.Short).Show();
});

为 UWP 变体添加 Alex 的代码,我在这里发现了一个很棒的实现 Https://www.c-sharpcorner.com/article/xamarin/

只要来给他留下掌声:)

[assembly:Xamarin.Forms.Dependency(typeof(Toast_UWP))]
namespace ToastMessage.UWP
{
class Toast_UWP : Toast
{
public void Show(string message)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
  

XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(message));
              

XmlNodeList toastImageAttributes = toastXml.GetElementsByTagName("image");
((XmlElement)toastImageAttributes[0]).SetAttribute("src", "ms-appx:///Assets/Logo.scale-240.png");
((XmlElement)toastImageAttributes[0]).SetAttribute("alt", "logo");
  

IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("duration", "short");
  

var toastNavigationUriString = "#/MainPage.xaml?param1=12345";
var toastElement = ((XmlElement)toastXml.SelectSingleNode("/toast"));
toastElement.SetAttribute("launch", toastNavigationUriString);
  

ToastNotification toast = new ToastNotification(toastXml);
  

ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}

默认情况下,您的消息将排队并一个接一个地通知,并根据消息持续时间延迟。如果您想立即用新的消息替换现有的消息,只需添加更多的代码,如下所示

ToastNotificationManager.History.Remove("YOUR_TAG");


// Code to create Toast message, like the above method


toast.Tag = "YOUR_TAG";

If you want to add audio to your toast message, add this to your code

var audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-winsoundevent:Notification.Default");

您可以使用 Xamarin.Toolkit 并按照 MS 提供的信息进行操作。 Https://learn.microsoft.com/en-us/xamarin/community-toolkit/views/popup

在我的应用程序中,我可以通过在视图模型、视图和名为 DismissThisPopup ()的方法之间放置每个代码来管理它。因此,可以从当前 Mainpage 外部控制它。

来完成你的要求。 您可以调用 wait Task。延迟(5000) ;//作为例子5秒 在你打电话给你的弹出窗口之后,打开() ; 所以看起来就像:

    ...
var vm = new MyPopUpViewModel()
vm.DisplayText = "this could be your text";
vm.DelayTimeForDismiss = 5000;
vm.IsLightDismissAllowed = false; //used that you can not close the popup by clicking around
await vm.OpenPopupAsync();

然后在您的 vm OpenPopUpAsync ()中

...other properties and stuff
internal PopUpLoadingView popup = new PopUpLoadingView();//this is the view created with the informations from MS


public async Task OpenPopUp()
{
popup.BindingContext = this;
Application.Current.MainPage.Navigation.ShowPopup(popup: popup);
await Task.Delay(DelayTimeForDismiss);
popup.DismissThisPopup();
}

并在 PopUpLoadingView 中插入以下方法:

...other stuff
public void DismissThisPopup()
{
Dismiss(this);
}