Toast equivalente per Xamarin Forms


90

Esiste un modo per utilizzare Xamarin Forms (non specifico per Android o iOS) per avere un pop-up, come Android fa con Toast, che non necessita dell'interazione dell'utente e scompare dopo un (breve) periodo di tempo?

Dalla ricerca in giro, vedo solo avvisi che richiedono clic dell'utente per scomparire.

Risposte:


171

C'è una soluzione semplice per questo. Utilizzando DependencyService puoi ottenere facilmente l'approccio Toast-Like sia su Android che su iOS.

Crea un'interfaccia nel tuo pacchetto comune.

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

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

sezione iOS

In iOs non esiste una soluzione nativa come Toast, quindi dobbiamo implementare il nostro approccio.

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

Tieni presente che in ogni piattaforma dobbiamo registrare le nostre classi con DependencyService.

Ora puoi accedere al servizio Toast ovunque nel nostro progetto.

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

20
Questa è di gran lunga la migliore risposta a questa domanda. Non sono necessari plugin o librerie di terze parti.
Bret Faller

4
nella riga DependencyService ottengo "Riferimento oggetto non impostato su un'istanza di un oggetto".
Joyce de Lanna

5
Sì, questa è la migliore risposta finora, mi piace il servizio di dipendenza
Lutaaya Huzaifah Idris

1
Pieno di vittorie. Ti capiterà di avere anche una versione UWP di questo?
Nieminen

1
@ MengTim Mi sembra di aver corretto l'interfaccia utente bloccata creando ogni volta un nuovo avviso e un nuovo timer. Entrambi devono essere passati a DismissMessage.
Ian Warburton

14

Ecco una versione del codice iOS di Alex Chengalan che evita il blocco dell'interfaccia utente quando vengono visualizzati più messaggi ...

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

11

Puoi usare Acr.UserDialogs Package da nuget e codice come sotto,

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

9

Normalmente useremmo il plugin Egors Toasts, ma poiché richiede le autorizzazioni su iOS per un progetto corrente, abbiamo seguito un percorso diverso utilizzando Rg.Plugins.Popup nuget ( https://github.com/rotorgames/Rg.Plugins.Popup ).

Ho scritto una pagina xaml / cs di base di tipo 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">
...

e farlo creare da un servizio, la cui interfaccia si registra all'avvio dell'app o si usa Xamarin.Forms.DependencyService per recuperare il servizio sarebbe anche fattibile.

Le notizie di servizio sulla pagina derivata di PopupPage e lo fanno

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

La pagina Popup può essere chiusa dall'utente toccando al di fuori della visualizzazione della pagina (supponendo che non abbia riempito lo schermo).

Questo sembra funzionare bene su iOS / Droid, ma sono aperto alla correzione se qualcuno sa quale sia un modo rischioso di farlo.


I popup rg sono fantastici. Faccio una soluzione simile per il caricamento del display o dell'indicatore di attività sulla pagina intera. problema con altri plugin sono che dipendono dalle funzioni asincrone e dal thread principale, ma il popup rg può essere eseguito sul secondo thread, il che lo rende molto utile. buona idea in effetti, ma desidero avere l'aspetto nativo dei toast Android.
Emil

Finora questo è il metodo migliore per fare toast multipiattaforma. Rg.Popup è super flessibile e lo uso in quasi tutti i progetti. Non è necessario utilizzare altri plugin o codice piattaforma per visualizzare i toast,
GiampaoloGabba

8

Aggiungendo alla risposta di Alex, ecco la variante 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();
  }
}

La colorazione e lo styling dipendono da te, in MaxHeightrealtà è necessario mantenere l'altezza al minimo.


Quindi registrarlo come servizio di dipendenza non è necessario per la piattaforma UWP?
Olorunfemi Ajibulu

Funziona esattamente come le altre due varianti. Sì, un servizio di dipendenza.
Gábor

7

Puoi usare IUserDialog NuGet e usarlo semplicemente toastAlert

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

UserDialogs.Instance.Toast(toastConfig);

4

Ecco uno snippet di codice che sto usando per mostrare l'avviso popup in 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

Consiglierei la Plugin.Toastlibreria di nuget. Funziona bene.

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

o dalla libreria ACR.UserDialogs Nuget

UserDialogs.Instance.ShowLoading("Loading");

C'è un modo per spostarlo all'inizio? Personalizzare e mostrare i multipli?
G_Money

no. questa libreria supporta solo messaggi di tipo avviso popup di base. puoi solo cambiare bg e colore del testo e la durata del messaggio.
Fk Bey

4

@ MengTim, per risolvere il problema di più toast nella soluzione di @ alex-chengalan, ho semplicemente avvolto tutto all'interno ShowAlert()con un controllo per vedere se alerte alertDelaysono nulli, quindi all'interno DismissMessage, annullati alerte 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;
        }
    }

Questo sembrava almeno chiarire il blocco dell'interfaccia utente, se stai cercando una soluzione rapida. Stavo cercando di visualizzare il brindisi durante la navigazione in una nuova pagina e credo che l' PresentViewControllerimpostazione impostata stesse essenzialmente annullando la mia navigazione. Scusa se non ho commentato nel thread, la mia reputazione è troppo bassa :(


2

Questa è la mia ShowAlertversione migliorata della versione di Ian Warburton per garantire che il brindisi venga visualizzato anche nella pagina popup. Inoltre, il messaggio di avviso viene ignorato se l'utente fa clic all'esterno del messaggio di avviso. Ho usato UIAlertControllerStyle.ActionSheetquell'aspetto come il pane tostato, ma funziona anche conUIAlertControllerStyle.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);
        });
    }

Spero che questo possa aiutare qualcuno!


1

Non esiste un meccanismo integrato in Forms, ma questo pacchetto nuget fornisce qualcosa di simile

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

Nota: non si tratta di toast in stile Android come richiesto nella domanda, ma di toast in stile UWP che sono notifiche a livello di sistema.


5
Android Toast significa una cosa completamente diversa: è un messaggio popup. Questa libreria è per le notifiche a livello di sistema.
Vojtěch Sázel

Avrei dovuto leggere il commento prima di installare la libreria solo per notare che non si tratta di toast in stile Android .. Per favore, chiariscilo nella risposta.
findusl


1

Ho personalizzato un popup personalizzato con Rg.Plugins.Popup NuGet questo è un esempio:

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

quindi nella tua basecontentpage puoi aggiungere il seguente codice, per mostrare e nascondere il "brindisi" dopo un po ':

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

0

Le risposte iOS sopra hanno funzionato per me, ma per un piccolo problema: un avvertimento: prova a presentare UIAlertController ... la cui vista non è nella gerarchia della finestra!

Dopo alcune ricerche, mi sono imbattuto in questa risposta non correlata che ha aiutato. Il poster ha commentato "Sembra stupido ma funziona", il che è giusto su entrambi i fronti.

Quindi, ho modificato la funzione ShowAlert () sopra con queste righe, che sembrano funzionare:

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

Dang - Vedo una versione ancora migliore di questo di seguito da @ Pierre-Alexandre Flèche. Come l'ho perso prima?
bobwki

0

Per 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

Puoi usare DisplayAlert("", "", "", "" );


1
Questo non reagisce affatto come un brindisi, ha bisogno di un'azione per continuare.
CennoxX
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.