Тост, еквівалентний для форм Xamarin


89

Чи є спосіб використання Xamarin Forms (не для Android чи iOS) для створення спливаючого вікна, як це робить Android з Toast, яке не потребує взаємодії з користувачем і зникає через (короткий) проміжок часу?

Від пошуку навколо всього, що я бачу, є сповіщення, яким потрібні кліки користувачів, щоб зникнути.

Відповіді:


170

Для цього існує просте рішення. Використовуючи DependencyService, ви можете легко отримати підхід, схожий на тост, як на Android, так і на iOS.

Створіть інтерфейс у своєму загальному пакеті.

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.

Тепер ви можете отримати доступ до служби тостів у будь-якому місці нашого проекту.

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

20
Це, безумовно, найкраща відповідь на це питання. Не потрібні сторонні плагіни та бібліотеки.
Bret Faller

4
у рядку DependencyService я отримую "Посилання на об'єкт не встановлено як екземпляр об'єкта."
Джойс де Ланна,

5
Так, це найкраща відповідь на даний момент, мені подобається служба залежності
Lutaaya Huzaifah Idris

1
Повна перемоги. Ви також мали б версію UWP для цього?
Nieminen

1
@MengTim Здається, я виправив застряглий інтерфейс, створюючи щоразу нове сповіщення та таймер. І те, і інше потрібно передати DismissMessage.
Ян Уорбертон,

13

Ось версія коду 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

Ви можете використовувати пакет Acr.UserDialogs з nuget та коду, як показано нижче,

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

9

Зазвичай ми використовуємо плагін Egors Toasts, але оскільки він вимагає дозволів на iOS для поточного проекту, ми пішли іншим шляхом, використовуючи null Rg.Plugins.Popup ( 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 може працювати на другому потоці, що робить його дуже корисним. справді гарна ідея, але я хочу, щоб рідна мова була схожа на тости для Android.
Еміль,

Поки що це найкращий спосіб робити тост на різних платформах. Rg.Popup надзвичайно гнучкий, і я використовую його майже в кожному проекті. Не потрібно використовувати інші плагіни або код платформи для відображення тостів,
GiampaoloGabba

8

Додаючи до відповіді Алекса, ось варіант 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?
Olorunfemi Ajibulu

Це працює точно так само, як і інші два варіанти. Так, служба залежностей.
Габор,

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 libriary

UserDialogs.Instance.ShowLoading("Loading");

Чи є спосіб перенести його на вершину? Налаштувати та показати кратні?
G_Money

немає. ця бібліотека підтримує лише основні повідомлення тостів. ви просто можете змінити bg та колір тексту та тривалість повідомлення.
Фк Бей

4

@MengTim, щоб виправити проблему множинних тостів у рішенні @ alex-chengalan, я просто обернув усе всередині ShowAlert()перевіренням, чи є alertі alertDelayє нульовими, то всередині 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;
        }
    }

Здавалося, це принаймні прибрало зависання інтерфейсу, якщо ви шукаєте швидкого виправлення. Я намагався показати тост під час навігації на новій сторінці, і вважаю, PresentViewControllerщо встановлений по суті скасовував мою навігацію. На жаль, я не коментував цю тему, моя репутація занадто низька :(


1

У Forms немає вбудованого механізму, але цей nuget-пакет містить щось подібне

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

Примітка: Це не тости в стилі Android, як це вимагається у питанні, а тости в стилі UWP, які є загальносистемними сповіщеннями.


5
Android Toast означає зовсім інше - це спливаюче повідомлення. Ця бібліотека призначена для загальносистемних сповіщень.
Vojtěch Sázel

Потрібно було прочитати коментар до того, як я встановив бібліотеку, щоб лише тоді помітити, що це не тости в стилі android.
findusl

1

Це моя вдосконалена ShowAlertверсія версії Яна Уорбертона, щоб забезпечити відображення тостів навіть на спливаючій сторінці. Крім того, тост відхиляється, якщо користувач клацає поза тостом. Я використовував 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 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);   
    }

0

Відповіді на iOS вище працювали для мене, але для однієї невеликої проблеми - попередження: Спробуйте представити UIAlertController ... чий вигляд відсутній у ієрархії вікна!

Після деяких пошуків я натрапив на цю не пов’язану відповідь, яка допомогла. Плакат прокоментував "Це виглядає дурно, але працює", що є правильним за обома пунктами.

Отже, я змінив функцію ShowAlert () вище за допомогою цих рядків, які, здається, працюють:

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

Данг - я бачу ще кращу версію цього нижче від @ Pierre-Alexandre Flè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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.