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に登録する必要があることに注意してください。

これで、プロジェクトのどこからでもToastサービスにアクセスできます。

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

20
これは、この質問に対する最善の答えです。サードパーティのプラグインやライブラリは必要ありません。
Bret Faller 2017年

4
DependencyService行で、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というメッセージが表示されます。
Joyce de Lanna 2017

5
ええ、これはこれまでのところ最良の答えです、私は依存関係サービスが好きです
Lutaaya Huzaifah Idris 2017

1
勝利に満ちている。これのUWPバージョンもありますか?
ニエミネン

1
@MengTim毎回新しいアラートとタイマーを作成することで、スタックしたUIを修正したようです。両方をに渡す必要がありますDismissMessage
IanWarburton18年

13

これは、複数のメッセージが表示されたときにUIが動かなくなるのを回避するAlexChengalanの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

通常はEgorsToastsプラグインを使用しますが、現在のプロジェクトでは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ポップアップは2番目のスレッドで実行できるため、非常に便利です。確かに良いアイデアですが、Androidトーストのようにネイティブに見せたいです。
エミル

これまでのところ、これはクロスプラットフォームトーストを行うための最良の方法です。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 2018年

他の2つのバリアントとまったく同じように機能します。はい、依存関係サービスです。
ガーボル

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.UserDialogsNugetライブラリから

UserDialogs.Instance.ShowLoading("Loading");

それを上に移動する方法はありますか?倍数をカスタマイズして表示しますか?
G_Money

番号。このライブラリは、基本的なトーストメッセージのみをサポートします。bgとテキストの色、およびメッセージの長さを変更するだけです。
fkBey19年

4

@MengTimは、アレックス・chengalanのソリューション@で複数のトーストの問題を修正するために、私は単に内のすべてラップShowAlert()かどうかを確認するためにチェックしてをalertし、alertDelayその後、内、nullでDismissMessage、ゼロ化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 2018年

1

これは、ShowAlertポップアップページにもトーストが表示されるようにするためのIanWarburtonのバージョンの改良版です。さらに、ユーザーがトーストの外側をクリックすると、トーストは閉じられます。私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の回答は私にとってはうまくいきましたが、1つの小さな問題がありました-警告:ビューがウィンドウ階層にないUIAlertControllerを提示しようとしています!

いくつか検索した後、私は助けになったこの無関係な答えに出くわしました。ポスターは「これはばかげているように見えますが、うまくいきます」とコメントしました。これは両方の点で正しいです。

そこで、上記のShowAlert()関数を次の行で変更しました。これは機能しているようです。

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

ダン-@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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.