Xamarin Forms的Toast等效物

问题描述 投票:49回答:13

是否有任何方法使用Xamarin Forms(不是Android或iOS特定的)来弹出,就像Android与Toast一样,不需要用户交互,并在一段(短)时间后消失?

从搜索所有我看到的是需要用户点击消失的警报。

c# xamarin xamarin.forms toast
13个回答
108
投票

有一个简单的解决方案。通过使用DependencyService,您可以轻松地在Android和iOS中获得Toast-Like方法。

在公共包中创建一个接口。

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

Android部分

[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 Bahwan.iOS
{
    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();
            }
        }
    }
}

请注意,在每个平台中,我们必须使用DependencyService注册我们的类。

现在,您可以在我们项目的任何位置访问Toast服务。

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

0
投票

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

经过一番搜索,我遇到了这个帮助的unrelated answer。海报评论说“这看起来很愚蠢而且很有效”,这两项都是正确的。

所以,我用这些行修改了上面的ShowAlert()函数,这似乎有效:

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

0
投票

对于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);
    }

0
投票

您可以使用nuget中的Acr.UserDialogs包和代码,如下所示,

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

0
投票

检查plugin.toast v 2.1.2可用于android,iOS和UWP


9
投票

这是Alex Chengalan的iOS code的一个版本,可以避免在显示多条消息时UI粘滞...

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();
            }
        }
    }

7
投票

添加到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();
  }
}

着色和造型取决于您,MaxHeightis实际上需要将高度保持在最低限度。


4
投票

这是我用来在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();
    }

3
投票

我们通常使用Egors Toasts插件,但由于它需要iOS上的当前项目权限,我们使用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">
...

并让它由服务创建,您在app开始注册的接口或使用Xamarin.Forms.DependencyService来获取服务也是可行的。

服务新闻PopupPage派生页面,并做

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

用户可以通过点击页面显示外部来取消弹出页面(假设它没有填满屏幕)。

这似乎在iOS / Droid上工作愉快,但如果有人知道这是一种冒险的方式,我愿意纠正。


3
投票

@MengTim,为了修复@ alex-chengalan解决方案中的多个Toast问题,我只是将ShowAlert()中的所有内容都包裹起来,检查alert和alertDelay是否为null,然后在DismissMessage中,取消alert和alertDelay。

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基本上取消了我的导航。对不起,我没有在帖子内发表评论,我的名声太低了:(


1
投票

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

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

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


1
投票

这是我改进的Iaz Warburton版本的ShowAlert版本,以确保即使在弹出页面上也能显示toast。此外,如果用户在吐司外面点击,则吐司被解雇。我使用看起来像烤面包的UIAlertControllerStyle.ActionSheet,但它也适用于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);
        });
    }

我希望这会对某人有所帮助!


1
投票

您可以使用IUserDialog Nuget并简单地使用它的toastAlert

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

UserDialogs.Instance.Toast(toastConfig);
© www.soinside.com 2019 - 2024. All rights reserved.