Xamarin Forms에 해당하는 토스트


89

Android 또는 iOS 전용이 아닌 Xamarin Forms를 사용하여 Android가 Toast에서 수행하는 것처럼 사용자 상호 작용이 필요하지 않고 (짧은) 시간이 지나면 사라지는 팝업을 표시하는 방법이 있습니까?

주변을 검색하면 사용자가 클릭해야 사라지는 경고가 표시됩니다.

답변:


170

이에 대한 간단한 해결책이 있습니다. 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에 클래스를 등록해야합니다.

이제 프로젝트 어디에서나 토스트 서비스에 액세스 할 수 있습니다.

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

20
이것이이 질문에 대한 최선의 대답입니다. 타사 플러그인이나 라이브러리가 필요하지 않습니다.
Bret Faller

4
DependencyService 줄에서 "개체 참조가 개체의 인스턴스로 설정되지 않았습니다."라는 메시지가 나타납니다.
Joyce de Lanna

5
그래이 난 종속성 서비스처럼, 지금까지 가장 좋은 대답입니다
Lutaaya Huzaifah 이드리스

1
승리로 가득 차 있습니다. 이것의 UWP 버전도 가질 수 있습니까?
Nieminen

1
@MengTim 매번 새로운 경고와 타이머를 생성하여 멈춘 UI를 수정 한 것 같습니다. 둘 다에 전달되어야 DismissMessage합니다.
Ian Warburton

13

다음 은 여러 메시지가 표시 될 때 UI 고정을 방지하는 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

너겟과 아래와 같은 코드에서 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을 사용하여 다른 경로로 이동했습니다. ).

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

앱 시작시 등록하거나 Xamarin.Forms.DependencyService를 사용하여 서비스를 가져 오는 인터페이스도 사용할 수있는 서비스에 의해 생성됩니다.

서비스 소식은 PopupPage에서 파생 된 페이지로,

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

팝업 페이지는 사용자가 페이지 디스플레이 외부를 탭하여 닫을 수 있습니다 (화면을 채우지 않았다고 가정).

이것은 iOS / Droid에서 행복하게 작동하는 것처럼 보이지만, 이것이 위험한 방법 인 것을 아는 사람이 있다면 수정할 수 있습니다.


rg 팝업은 훌륭합니다. 전체 페이지에서 디스플레이 또는 활동 표시기를로드하는 것과 유사한 해결 방법을 수행합니다. 다른 플러그인의 문제는 비동기 함수 및 메인 스레드에 의존하지만 rg 팝업은 두 번째 스레드에서 실행될 수 있으므로 매우 유용합니다. 참으로 좋은 생각이지만 안드로이드 토스트처럼 네이티브처럼 보이고 싶습니다.
에밀

지금까지 이것이 크로스 플랫폼 토스트를 수행하는 가장 좋은 방법입니다. 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가 필요하지 않습니까?
Olorunfemi Ajibulu

다른 두 가지 변형과 똑같이 작동합니다. 예, 종속성 서비스입니다.
Gábor

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

아니. 이 라이브러리는 기본 토스트 메시지 만 지원합니다. bg 및 텍스트 색상과 메시지 기간을 변경할 수 있습니다.
Fk Bey

4

@MengTim은, 알렉스 - chengalan의 솔루션 @에 여러 토스트 문제를 해결하기 위해, 난 그저 내에서 모든 것을 감싸 ShowAlert()있는지 확인하기 위해 검사와을 alert하고 alertDelay다음 내에서 null이 DismissMessage, NULLed 아웃 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에는 기본 제공 메커니즘이 없지만이 너겟 패키지는 비슷한 것을 제공합니다.

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

참고 : 질문에서 요청한 Android 스타일 알림이 아니라 시스템 전체 알림 인 UWP 스타일 알림입니다.


5
Android Toast는 완전히 다른 의미로 팝업 메시지입니다. 이 라이브러리는 시스템 전체 알림 용입니다.
Vojtěch Sázel

내가 라이브러리를 설치하기 전에 주석을 읽어야 만한다면 이것이 안드로이드 스타일 토스트가 아니라는 것을 알아 차리기 위해 .. 대답에서 명확하게하십시오.
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 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>

그런 다음 basecontentpage에 다음 코드를 추가하여 잠시 후 "토스트"를 표시하거나 숨길 수 있습니다.

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

0

위의 iOS 답변은 저에게 효과적이지만 한 가지 작은 문제가 있습니다. 경고 : Attempt to present UIAlertController ... 그 뷰가 창 계층 구조에 없습니다!

몇 가지 검색 후 도움 이되는 관련없는 답변 을 발견했습니다. 포스터는 "이건 어리석은 것처럼 보이지만 효과가있다"라고 말했는데, 이는 두 가지 모두에 맞다.

따라서 위의 ShowAlert () 함수를 다음 줄로 수정했습니다.

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

Dang-@ 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.