c# - open - Tostada equivalente para formularios de Xamarin
xamarin forms themes (14)
¿Hay alguna forma de usar los formularios de Xamarin (no específicos de Android o iOS) para tener una ventana emergente, como Android hace con Toast, que no necesita interacción del usuario y desaparece después de un período de tiempo (corto)?
Al buscar en todo lo que veo, hay alertas que necesitan clics de usuario para desaparecer.
@MengTim, para solucionar el problema de múltiples tostadas en la solución de @ alex-chengalan, simplemente envolví todo dentro de ShowAlert () con una verificación para ver si alert y alertDelay son nulos, luego dentro de DismissMessage, anulé alert y 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;
}
}
Eso parecía al menos aclarar el bloqueo de la interfaz de usuario, si está buscando una solución rápida. Estaba tratando de mostrar el brindis en la navegación a una nueva página, y creo que el PresentViewController que se estaba configurando estaba esencialmente cancelando mi navegación. Lo siento, no hice comentarios en el hilo, mi reputación es demasiado baja :(
Agregando a la respuesta de Alex, aquí está 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();
}
}
El color y el estilo
MaxHeight
usted, el
MaxHeight
es realmente necesario para mantener la altura al mínimo.
Aquí hay un fragmento de código que estoy usando para mostrar el brindis en 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();
}
Aquí hay una versión del code iOS de Alex Chengalan que evita que la UI se pegue cuando se muestran varios mensajes ...
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();
}
}
}
Esta es mi versión mejorada de
ShowAlert
versión de Ian Warburton para garantizar que la tostada se muestre incluso en la página emergente.
Además, la tostada se descarta si el usuario hace clic fuera de la tostada.
Utilicé
UIAlertControllerStyle.ActionSheet
que parece tostada pero también funciona con
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);
});
}
Espero que esto ayude a alguien !
Hay una solución simple para esto. Al utilizar DependencyService , puede obtener fácilmente el enfoque Toast-Like tanto en Android como en iOS.
Crea una interfaz en tu paquete común.
public interface IMessage
{
void LongAlert(string message);
void ShortAlert(string message);
}
Sección de 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();
}
}
}
sección de iOS
En iOs no hay una solución nativa como Toast, por lo que debemos implementar nuestro propio enfoque.
[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();
}
}
}
}
Tenga en cuenta que en cada plataforma, tenemos que registrar nuestras clases con DependencyService.
Ahora puede acceder al servicio Toast en cualquier parte de nuestro proyecto.
DependencyService.Get<IMessage>().ShortAlert(string message);
DependencyService.Get<IMessage>().LongAlert(string message);
Las respuestas de iOS anteriores funcionaron para mí, pero por un pequeño problema: una advertencia: Intente presentar UIAlertController ... ¡cuya vista no está en la jerarquía de ventanas!
Después de una búsqueda, me encontré con esta respuesta no relacionada que me ayudó. El cartel comentaba "Esto parece estúpido pero funciona", lo cual es correcto en ambos sentidos.
Entonces, modifiqué la función ShowAlert () anterior con estas líneas, que parecen funcionar:
var rootVC = UIApplication.SharedApplication.KeyWindow.RootViewController;
while ( rootVC.PresentedViewController != null) {
rootVC = rootVC.PresentedViewController;
}
rootVC.PresentViewController( alert, true, null);
No hay un mecanismo incorporado en Formularios, pero este paquete Nuget proporciona algo similar
https://github.com/EgorBo/Toasts.Forms.Plugin
Nota: Estas no son tostadas de estilo Android como se solicitó en la pregunta, sino tostadas de estilo UWP que son notificaciones de todo el sistema.
Normalmente usamos el complemento Egors Toasts, pero como requiere permisos en iOS para un proyecto actual, hemos tomado una ruta diferente usando Rg.Plugins.Popup nuget ( https://github.com/rotorgames/Rg.Plugins.Popup )
Escribí una página xaml / cs básica del 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">
...
y que lo cree un servicio, cuya interfaz que registres al iniciar la aplicación o que uses Xamarin.Forms.DependencyService para buscar el servicio también sería viable.
El servicio presenta la página derivada de PopupPage, y lo hace
await PopupNavigation.PushAsync(newToastPage);
await Task.Delay(2000);
await PopupNavigation.PopAllAsync();
El usuario puede cerrar la página emergente tocando fuera de la pantalla (suponiendo que no haya llenado la pantalla).
Esto parece funcionar bien en iOS / Droid, pero estoy dispuesto a corregirlo si alguien sabe qué es una forma arriesgada de hacerlo.
Para 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);
}
Puede usar
DisplayAlert("", "", "", "" );
Puede usar Acr.UserDialogs Package desde nuget y el código como se muestra a continuación,
Acr.UserDialogs.UserDialogs.Instance.Toast(Message, new TimeSpan(3));
Puede usar IUserDialog Nuget y simplemente usar it''s toastAlert
var toastConfig = new ToastConfig("Toasting...");
toastConfig.SetDuration(3000);
toastConfig.SetBackgroundColor(System.Drawing.Color.FromArgb(12, 131, 193));
UserDialogs.Instance.Toast(toastConfig);
Verifique plugin.toast v 2.1.2 disponible para Android, iOS y UWP