相当于Xamarin形式的吐司


89

是否可以使用Xamarin Forms(非Android或iOS专用)弹出窗口,就像Android与Toast一样,不需要用户交互,并且会在短时间内消失?

通过搜索,我发现所有警报都需要用户单击才能消失。

Answers:


170

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

在通用包中创建一个接口。

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部分

在iO中,没有像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);

20
到目前为止,这是对该问题的最佳答案。无需第三方插件或库。
Bret Faller

4
在DependencyService行中,我得到“对象引用未设置为对象的实例”。
乔伊斯·德兰纳

5
是的,这是迄今为止最好的答案,我喜欢依赖服务
Lutaaya Huzaifah Idris 17/11/1

1
充满胜利。您是否还会有该版本的UWP版本?
Nieminen

1
@MengTim我似乎已经通过每次创建一个新的警报和计时器来修复了卡住的UI。两者都需要传递给DismissMessage
伊恩·沃伯顿

13

这是Alex Chengalan的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();
            }
        }
    }

10

您可以从nuget和以下代码中使用Acr.UserDialogs包,

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

9

我们通常会使用Egors Toasts插件,但是由于它需要当前项目在iOS上的权限,因此我们使用Rg.Plugins.Popup nuget(https://github.com/rotorgames/Rg.Plugins.Popup)。

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

<?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上愉快地工作,但是如果有人知道这是一种冒险的方式,我愿意接受更正。


RG弹出窗口很棒。我为在整页上加载显示或活动指示器做了类似的解决方法。其他插件的问题是它们依赖于异步功能和主线程,但是rg popup可以在第二个线程上运行,这使其非常有用。确实是个好主意,但我希望本机看起来像android Toast。
埃米尔(Emil)

到目前为止,这是跨平台吐司的最佳方法。Rg.Popup是超级灵活的,我几乎在每个项目中都使用它。无需使用其他插件或平台代码来展示面包,
GiampaoloGabba,

8

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

颜色和样式取决于您,MaxHeight实际上需要将高度保持在最低水平。


因此,UWP不需要将其注册为依赖服务吗?
奥洛伦费米·阿吉布卢

它与其他两个变体完全一样。是的,依赖服务。
加博(Gábor)'18

7

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

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

UserDialogs.Instance.Toast(toastConfig);

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

4

我建议Plugin.Toast从图书馆nuget。它运作良好。

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

或来自ACR.UserDialogs Nuget库

UserDialogs.Instance.ShowLoading("Loading");

有没有办法将其移到顶部?自定义并显示倍数?
G_Money

没有。该库仅支持基本的Toast消息。您可以更改背景色和文本颜色以及消息的持续时间。
Fk Bey

4

@MengTim,要解决@ alex-chengalan解决方案中的多敬酒问题,我只是将所有内容包裹在ShowAlert()其中,检查以查看alertalertDelay,如果为null,然后将其包含在DismissMessage,null中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被设置本质上是在取消我的导航。抱歉,我没有在主题中发表评论,我的声誉太低了:(


1

Forms中没有内置机制,但是此nuget包提供了类似的功能

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

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


5
Android Toast的含义完全不同-这是一条弹出消息。该库用于系统范围的通知。
VojtěchSázel

在安装库之前,应该已经读过注释,只是为了注意这些不是android样式的敬酒。。请在答案中明确指出。
findusl

1

这是我ShowAlert对伊恩·沃伯顿(Ian Warburton)的改进版本,以确保甚至在弹出页面上也可以显示吐司。此外,如果用户在烤面包上单击,则将删除该烤面包。我用过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

我使用Rg.Plugins.Popup Nu自定义了自定义弹出窗口,这是一个示例:

 <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>

然后在您的basecontentpage中,可以添加以下代码,以在一段时间后显示和隐藏“ toast”:

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

0

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

经过一番搜索,我遇到了这个不相关的答案,这很有帮助。张贴者评论说“这看起来很愚蠢,但行得通”,这两种说法都正确。

因此,我用这些行修改了上面的ShowAlert()函数,这些行似乎起作用了:

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

Dang-我在@ Pierre-AlexandreFlèche的下面看到了更好的版本。我以前是怎么想念它的?
bobwki

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

-5

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


1
这根本不像吐司那样反应,它需要采取措施才能继续。
CennoxX
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.