Toastäquivalent für Xamarin Forms

85

Gibt es eine Möglichkeit, mit Xamarin Forms (nicht Android- oder iOS-spezifisch) ein Popup zu erstellen, wie es Android mit Toast tut, das keine Benutzerinteraktion erfordert und nach einer (kurzen) Zeitspanne verschwindet?

Wenn ich mich umschaue, sehe ich nur Warnungen, bei denen Benutzerklicks erforderlich sind, um zu verschwinden.

Jimmy
quelle

Antworten:

165

Hierfür gibt es eine einfache Lösung. Mit dem DependencyService können Sie den Toast-ähnlichen Ansatz sowohl in Android als auch in iOS problemlos erhalten.

Erstellen Sie eine Schnittstelle in Ihrem gemeinsamen Paket.

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

Android-Bereich

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

In iOs gibt es keine native Lösung wie Toast, daher müssen wir unseren eigenen Ansatz implementieren.

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

Bitte beachten Sie, dass wir auf jeder Plattform unsere Klassen bei DependencyService registrieren müssen.

Jetzt können Sie überall in unserem Projekt auf unseren Toast-Service zugreifen.

DependencyService.Get<IMessage>().ShortAlert(string message); 
DependencyService.Get<IMessage>().LongAlert(string message);
Alex Chengalan
quelle
18
Dies ist bei weitem die beste Antwort auf diese Frage. Keine Plugins oder Bibliotheken von Drittanbietern erforderlich.
Bret Faller
4
In der Zeile DependencyService wird "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt" angezeigt.
Joyce de Lanna
5
Ja, das ist die beste Antwort bisher, ich mag Abhängigkeitsdienst
Lutaaya Huzaifah Idris
1
Voller Sieg. Hätten Sie zufällig auch eine UWP-Version davon?
Nieminen
1
@MengTim Ich habe anscheinend die festgefahrene Benutzeroberfläche behoben, indem ich jedes Mal eine neue Warnung und einen neuen Timer erstellt habe. Beide müssen weitergegeben werden DismissMessage.
Ian Warburton
13

Hier ist eine Version von Alex Chengalans iOS- Code , die verhindert, dass die Benutzeroberfläche hängen bleibt, wenn mehrere Nachrichten angezeigt werden ...

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();
            }
        }
    }
Ian Warburton
quelle
8

Normalerweise verwenden wir das Egors Toasts-Plugin, aber da für ein aktuelles Projekt Berechtigungen unter iOS erforderlich sind, haben wir mit Rg.Plugins.Popup nuget ( https://github.com/rotorgames/Rg.Plugins.Popup) einen anderen Weg eingeschlagen ).

Ich habe eine grundlegende xaml / cs-Seite vom Typ PopupPage geschrieben.

<?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">
...

und lassen Sie es von einem Dienst erstellen, dessen Schnittstelle Sie beim Start der App registrieren oder Xamarin.Forms.DependencyService zum Abrufen des Dienstes verwenden.

Der Dienst aktualisiert die von PopupPage abgeleitete Seite und tut dies

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

Die Popup-Seite kann vom Benutzer durch Tippen außerhalb der Seitenanzeige geschlossen werden (vorausgesetzt, sie hat den Bildschirm nicht ausgefüllt).

Dies scheint unter iOS / Droid gut zu funktionieren, aber ich bin offen für Korrekturen, wenn jemand weiß, was dies eine riskante Methode ist.

Allister
quelle
RG-Popups sind großartig. Ich mache eine ähnliche Problemumgehung für das Laden der Anzeige oder der Aktivitätsanzeige auf der ganzen Seite. Problem mit anderen Plugins sind, dass sie von asynchronen Funktionen und dem Hauptthread abhängen, aber das rg-Popup kann auf dem 2. Thread ausgeführt werden, was es sehr nützlich macht. Gute Idee, aber ich möchte, dass native wie auf Android Toast aussehen.
Batmaci
Bisher ist dies die beste Methode, um plattformübergreifenden Toast zu machen. Rg.Popup ist super flexibel und ich benutze es in fast jedem Projekt. Keine Notwendigkeit, andere Plugins oder Plattformcode zu verwenden, um Toast anzuzeigen,
GiampaoloGabba
8

Sie können das Acr.UserDialogs-Paket aus Nuget und Code wie unten verwenden.

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

Neben Alex 'Antwort ist hier die UWP-Variante:

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

Das Färben und Stylen liegt bei Ihnen, das MaxHeightist tatsächlich erforderlich, um die Höhe auf einem Minimum zu halten.

Gábor
quelle
Die Registrierung als Abhängigkeitsdienst ist für das UWP also nicht erforderlich?
Olorunfemi Ajibulu
Es funktioniert genau wie die beiden anderen Varianten. Ja, ein Abhängigkeitsdienst.
Gábor
7

Sie können IUserDialog NuGet verwenden und einfach toastAlert verwenden

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

UserDialogs.Instance.Toast(toastConfig);
mohammad kamali
quelle
4

Hier ist ein Code-Snippet, mit dem ich den Toast in Xamarin.iOS zeige

  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();
    }
Durai Amuthan.H
quelle
4

@MengTim, um das Problem mit mehreren Toasts in der Lösung von @ alex-chengalan zu beheben, habe ich einfach alles ShowAlert()mit einer Prüfung versehen, um zu sehen, ob alertund alertDelaynull sind, dann innerhalb DismissMessage, null alertund 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;
        }
    }

Das schien zumindest den UI-Hang zu klären, wenn Sie nach einer schnellen Lösung suchen. Ich habe versucht, den Toast bei der Navigation zu einer neuen Seite anzuzeigen, und glaube, dass das PresentViewControllerFestlegen meine Navigation im Wesentlichen aufhebt. Entschuldigung, ich habe nicht innerhalb des Threads kommentiert, mein Ruf ist zu niedrig :(

Gunnar
quelle
3

Ich würde Plugin.ToastBibliothek von empfehlen nuget. Es funktioniert gut.

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

oder vom ACR.UserDialogs Nuget-Bibliothekar

UserDialogs.Instance.ShowLoading("Loading");
Fk Bey
quelle
Gibt es eine Möglichkeit, es nach oben zu verschieben? Vielfache anpassen und anzeigen?
G_Money
Nein. Diese Bibliothek unterstützt nur grundlegende Toastnachrichten. Sie können nur die Hintergrund- und Textfarbe sowie die Dauer der Nachricht ändern.
Fk Bey
1

In Forms ist kein Mechanismus integriert, aber dieses Nuget-Paket bietet etwas Ähnliches

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

Hinweis: Hierbei handelt es sich nicht um Toasts im Android-Stil, wie in der Frage gefordert, sondern um Toasts im UWP-Stil, bei denen es sich um systemweite Benachrichtigungen handelt.

Jason
quelle
5
Android Toast bedeutet etwas ganz anderes - es ist eine Popup-Nachricht. Diese Bibliothek ist für systemweite Benachrichtigungen vorgesehen.
Vojtěch Sázel
Hätte den Kommentar lesen sollen, bevor ich die Bibliothek installiert habe, nur um dann zu bemerken, dass es sich nicht um Toasts im Android-Stil handelt. Bitte machen Sie dies in der Antwort deutlich.
Findusl
1

Dies ist meine verbesserte ShowAlertVersion von Ian Warburtons Version, um sicherzustellen, dass der Toast auch auf der Popup-Seite angezeigt wird. Außerdem wird der Toast verworfen, wenn der Benutzer außerhalb des Toasts klickt. Ich habe UIAlertControllerStyle.ActionSheetdiesen Look wie Toast benutzt, aber er funktioniert auch mitUIAlertControllerStyle.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);
        });
    }

Ich hoffe das hilft jemandem!

Pierre-Alexandre Flèche
quelle
0

Die obigen iOS-Antworten haben bei mir funktioniert, aber bei einem kleinen Problem - einer Warnung: Versuchen Sie, UIAlertController zu präsentieren ... dessen Ansicht nicht in der Fensterhierarchie enthalten ist!

Nach einiger Suche stieß ich auf diese nicht verwandte Antwort, die half. Das Poster kommentierte "Das sieht dumm aus, funktioniert aber", was in beiden Punkten richtig ist.

Also habe ich die ShowAlert () -Funktion oben mit diesen Zeilen geändert, die zu funktionieren scheinen:

    var rootVC = UIApplication.SharedApplication.KeyWindow.RootViewController;
    while ( rootVC.PresentedViewController != null) {
        rootVC = rootVC.PresentedViewController;
    }
    rootVC.PresentViewController( alert, true, null);
Bobwki
quelle
Dang - Ich sehe unten eine noch bessere Version von @ Pierre-Alexandre Flèche. Wie habe ich es vorher vermisst?
Bobwki
0

Für 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);
    }
Fabien Richard
quelle
0

Ich habe ein benutzerdefiniertes Popup mit Rg.Plugins.Popup NuGet angepasst. Dies ist ein Beispiel:

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

Dann können Sie auf Ihrer Basisinhaltsseite den folgenden Code hinzufügen, um den "Toast" nach einer Weile ein- und auszublenden:

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

Sie können verwenden DisplayAlert("", "", "", "" );

O. Ahmadpoor
quelle
1
Dies reagiert überhaupt nicht wie ein Toast, es braucht eine Aktion, um fortzufahren.
CennoxX