เทียบเท่าขนมปังสำหรับ Xamarin Forms


90

มีวิธีใดบ้างที่ใช้ Xamarin Forms (ไม่ใช่เฉพาะ Android หรือ iOS) เพื่อให้มีป๊อปอัปเช่น Android ทำกับ Toast ที่ไม่ต้องใช้การโต้ตอบกับผู้ใช้และหายไปหลังจากช่วงเวลาสั้น ๆ

จากการค้นหารอบ ๆ ทั้งหมดที่ฉันเห็นคือการแจ้งเตือนที่ต้องการให้ผู้ใช้คลิกจึงจะหายไป

คำตอบ:


171

มีวิธีง่ายๆสำหรับเรื่องนี้ ด้วยการใช้DependencyServiceคุณสามารถรับวิธีการ Toast-Like ได้อย่างง่ายดายทั้งใน 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

4
ในสาย DependencyService ฉันได้รับ "การอ้างอิงวัตถุไม่ได้ตั้งค่าเป็นอินสแตนซ์ของวัตถุ"
Joyce de Lanna

5
ใช่นี่เป็นคำตอบที่ดีที่สุดจนถึงตอนนี้ฉันชอบบริการพึ่งพา
Lutaaya Huzaifah Idris

1
เต็มไปด้วยชัยชนะ คุณจะมีเวอร์ชัน UWP นี้ด้วยหรือไม่?
Nieminen

1
@MengTim ดูเหมือนว่าฉันจะแก้ไข UI ที่ค้างอยู่ด้วยการสร้างการแจ้งเตือนใหม่และตัวจับเวลาทุกครั้ง DismissMessageทั้งสองจะต้องมีการส่งผ่านไปยัง
Ian Warburton

14

นี่คือรหัส iOS ของ Alex Chengalan ที่หลีกเลี่ยงการติด UI เมื่อมีการแสดงข้อความหลายข้อความ ...

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

คุณสามารถใช้ Acr.UserDialogs Package จาก nuget และรหัสด้านล่าง

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

9

โดยปกติเราจะใช้ปลั๊กอิน Egors Toasts แต่เนื่องจากต้องใช้สิทธิ์บน iOS สำหรับโปรเจ็กต์ปัจจุบันเราจึงใช้เส้นทางอื่นโดยใช้ Rg.Plugins.Popup nuget ( 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 นั้นยอดเยี่ยมมาก ฉันใช้วิธีแก้ปัญหาที่คล้ายกันสำหรับการโหลดการแสดงผลหรือตัวบ่งชี้กิจกรรมบนหน้าเต็ม ปัญหากับปลั๊กอินอื่น ๆ ขึ้นอยู่กับฟังก์ชัน async และเธรดหลัก แต่ป๊อปอัป rg สามารถทำงานบนเธรดที่ 2 ซึ่งทำให้มีประโยชน์มาก เป็นความคิดที่ดีจริงๆ แต่ฉันหวังว่าจะมีหน้าตาแบบเนทีฟเหมือนบนขนมปังปิ้งของ Android
Emil

จนถึงตอนนี้เป็นวิธีที่ดีที่สุดในการทำขนมปังข้ามแพลตฟอร์ม Rg.Popup เป็น super flexibile และฉันใช้ในเกือบทุกโครงการ ไม่จำเป็นต้องใช้ปลั๊กอินหรือรหัสแพลตฟอร์มอื่น ๆ เพื่อแสดงขนมปังปิ้ง
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จำเป็นต้องรักษาความสูงให้ต่ำที่สุด


ดังนั้นการลงทะเบียนเป็น Dependency Service จึงไม่จำเป็นต้องมี UWP?
Olorunfemi Ajibulu

มันทำงานเหมือนกับอีกสองตัวแปร ใช่บริการพึ่งพา
Gábor


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 และสีข้อความและระยะเวลาของข้อความได้
Fk Bey

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

ดูเหมือนว่าอย่างน้อยจะล้าง UI ค้างหากคุณกำลังมองหาการแก้ไขอย่างรวดเร็ว ฉันพยายามแสดงขนมปังปิ้งบนการนำทางไปยังหน้าใหม่และเชื่อว่าPresentViewControllerการตั้งค่านั้นกำลังยกเลิกการนำทางของฉันเป็นหลัก ขออภัยฉันไม่ได้แสดงความคิดเห็นในกระทู้ชื่อเสียงของฉันต่ำเกินไป :(


2

นี่เป็น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

ไม่มีกลไกในตัวในฟอร์ม แต่แพ็กเกจนักเก็ตนี้ให้สิ่งที่คล้ายกัน

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

หมายเหตุ: นี่ไม่ใช่โทสต์สไตล์ Android ตามที่ร้องขอในคำถาม แต่เป็นโทสต์สไตล์ UWP ซึ่งเป็นการแจ้งเตือนทั้งระบบ


5
Android Toast หมายถึงสิ่งที่แตกต่างอย่างสิ้นเชิงนั่นคือข้อความป๊อปอัป ไลบรารีนี้มีไว้สำหรับการแจ้งเตือนทั้งระบบ
VojtěchSázel

ควรอ่านความคิดเห็นก่อนที่ฉันจะติดตั้งไลบรารีเพียงเพื่อสังเกตว่าสิ่งเหล่านี้ไม่ใช่ขนมปังปิ้งสไตล์ Android .. โปรดระบุคำตอบให้ชัดเจน
findusl


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.