我想在xamarin表单应用程序(iOS / Android PCL)中显示一个小弹出窗口
我实际上正在使用ContentPage(XAML + C#代码)
我正在使用以下内容显示此弹出窗口:
await Navigation.PushModalAsync(mypopupinstance)
它运行正常,但弹出窗口是全屏的。我只想要一个小弹出窗口,我想看看背后是什么。
由于
答案 0 :(得分:4)
您需要在其他地方寻找此类功能。一个这样的库是Rotorgames的Popup插件:https://github.com/rotorgames/Rg.Plugins.Popup
答案 1 :(得分:2)
模态页面无法像这样呈现。
对于小弹出窗口,您可以使用
DisplayAlert()
在页面内。
如果您想要更具可自定义的内容,只需将页面内容包装在相对布局或网格内,并在普通内容的基础上添加弹出窗口。
答案 2 :(得分:0)
我正在处理同一问题,到目前为止,我已经能够创建一个可以容纳内容页面的弹出窗口。 我很高兴分享我的当前状态。请注意,我将使代码示例尽可能简短,从而将其简化为简单的加载和文本提示对话框。
方法
使用Acr.UserDialogs库一段时间后,由于个人需求,我感到需要自定义对话框。我也想尽量减少必须依赖插件的必要性。 理想情况下,这样的对话框应该通过简单的调用来调用,例如:
Dialogs.ShowLoading();
或
string result = Dialogs.ShowPrompt();
与Xamarin.Forms一样,很明显,我们将需要依赖服务实现才能使它工作。
共享代码库
我们创建一个基本界面“ IDialogs.cs”:
public interface IDialogs
{
bool IsDialogOpen();
void ShowLoading(LoadingDialog dialog);
void ShowPrompt(PromptDialog dialog);
void HideDialog();
}
接下来要做的是拥有一个静态对话框类,可以在需要对话框的每个页面中调用它。 “ Dialogs.cs”:
public static class Dialogs
{
private static IDialogs dialogService = DependencyService.Get<IDialogs>();
public static bool IsDialogOpen()
{
return dialogService.IsDialogOpen();
}
public static void ShowLoading()
{
LoadingDialog dlg = new LoadingDialog();
dialogService.ShowLoading(dlg);
}
public static Task<string> ShowPromptText()
{
TaskCompletionSource<string> dialogCompletion = new TaskCompletionSource<string>();
PromptDialog dialog = new PromptDialog();
dialog.Canceled += (object sender, object result) => { dialogService.HideDialog(); dialogCompletion.SetResult((string)result); };
dialog.Confirmed += (object sender, object result) => { dialogService.HideDialog(); dialogCompletion.SetResult((string)result); };
dialogService.ShowPrompt(dialog);
return dialogCompletion.Task;
}
public static void HideDialog()
{
dialogService.HideDialog();
}
}
您会注意到,我们在ShowPromptText方法中将TaskCompletionSource与自定义事件处理程序一起使用。这样一来,我们就可以显示对话框,并等待用户按下“确定”或“取消”按钮并使用返回的结果。
截至目前,对话框尽可能简单。我使用了一些其他的样式和主题代码,但是为了使答案简短而简单,我将省略这些代码。
正在加载对话框:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Dialogs.LoadingDialog" BackgroundColor="Transparent">
<ContentPage.Content>
<Grid BackgroundColor="#bb000000">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Frame BackgroundColor="Black" CornerRadius="15" Grid.Row="1" x:Name="ContentGrid" Margin="100,0,100,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ActivityIndicator Grid.Row="0" Color="White" IsRunning="True" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label x:Name="LoadingLabel" Text="Loading ..." VerticalOptions="End" HorizontalOptions="Center" Grid.Row="1" TextColor="White" />
</Grid>
</Frame>
</Grid>
</ContentPage.Content>
(此操作无需发布xaml.cs代码,因为与加载屏幕没有交互)
提示对话框
PromptDialog.Xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:dialogs="clr-namespace:BetterUI.Dialogs"
x:Class="MyApp.Dialogs.PromptDialog" BackgroundColor="Transparent">
<ContentPage.Content>
<ScrollView>
<Grid BackgroundColor="#bb000000">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Frame x:Name="ContentGrid" Grid.Row="1" CornerRadius="15" BackgroundColor="White" Margin="50,0,50,0" Padding="0">
<Grid Grid.Row="1" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid x:Name="HeadingGrid" Padding="10, 5, 10, 5" Margin="-15,0,-15,0" Grid.Row="0" BackgroundColor="Black">
<Label x:Name="HeadingLabel" Text="Enter text" TextColor="White" Margin="20,0,20,0"/>
</Grid>
<Label l x:Name="DescriptionLabel" Text="Enter your text" Grid.Row="1" Margin="15,0,15,0"/>
<Entry x:Name="DialogResultText" Placeholder="Text" PlaceholderColor="LightGray" TextColor="Black" Grid.Row="2" Margin="15,0,15,0"/>
<Grid Grid.Row="3" ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="CancelButton" Text="Cancel" Clicked="OnCancelClick" Grid.Column="0" CornerRadius="0"/>
<Button x:Name="ConfirmButton" Text="Okay" Clicked="OnOkayClick" Grid.Column="1" CornerRadius="0"/>
</Grid>
</Grid>
</Frame>
</Grid>
</ScrollView>
</ContentPage.Content>
PromptDialog.xaml.cs:
public partial class PromptDialog : ContentPage
{
public event EventHandler<object> Confirmed;
public event EventHandler<object> Canceled;
public PromptDialog()
{
InitializeComponent();
}
private void OnCancelClick(object sender, EventArgs e)
{
Canceled?.Invoke(this, string.Empty);
}
private void OnOkayClick(object sender, EventArgs e)
{
Confirmed?.Invoke(this, DialogResultText.Text);
}
}
Android实现
首先,我们将在前面的共享代码中创建IDialogs接口的android实现:
[assembly: Dependency(typeof(DialogService))]
namespace MyApp.Droid.Services
{
/// <summary>
/// Handles displaying dialog items on screen
/// </summary>
public class DialogService : IDialogs
{
private static DialogFragment currentDialog;
/// <summary>
/// returns if a dialog is already open
/// </summary>
/// <returns></returns>
public bool IsDialogOpen()
{
return (currentDialog != null && currentDialog.IsVisible);
}
/// <summary>
/// Initialize Dialog Service with activity
/// </summary>
/// <param name="activity">activity</param>
public static void Init(Activity activity)
{
Activity = activity;
}
public static Activity Activity { get; set; }
/// <summary>
/// Displays a loading dialog
/// </summary>
/// <param name="dialog">Instance of progress dialog (xamarin.forms)</param>
public void ShowLoading(Dialogs.LoadingDialog dialog)
{
if (Activity == null)
return;
DialogFragment frag = dialog.CreateDialogFragment(Activity);
frag.SetStyle(DialogFragmentStyle.NoTitle, Resource.Style.DialogFrame);
frag.Show(Activity.FragmentManager, "dialog");
currentDialog = frag;
}
/// <summary>
/// Displays a prompt dialog
/// </summary>
/// <param name="dialog"></param>
public void ShowPrompt(Dialogs.PromptDialog dialog)
{
if (Activity == null)
return;
DialogFragment frag = dialog.CreateDialogFragment(Activity);
frag.SetStyle(DialogFragmentStyle.NoTitle, Resource.Style.DialogFrame);
frag.Show(Activity.FragmentManager, "dialog");
currentDialog = frag;
}
/// <summary>
/// Hides loading dialog
/// </summary>
public void HideDialog()
{
if (Activity == null)
return;
if (currentDialog != null)
{
currentDialog.Dismiss();
currentDialog = null;
}
}
}
}
请注意,您必须在调用实际方法以显示对话框之前设置对话框服务的活动,因此在MainActivity.cs中请确保调用
DialogService.Init(this);
初始化Xamarin.Forms之后。
最后,这是一些黑魔法:
通常,可以通过将片段容器放入主布局并在其中放入片段来在Android中实现这种对话框。不幸的是,由于使用Xamarin.Forms,因此默认情况下不提供这样的主布局。
即使Xamarin.Forms提供了视图扩展,该视图扩展允许将ContentPage转换为片段(ContentPage.CreateFragment),但由于需要将目标片段容器放入其中,因此使用它不会成功。 / p>
但是,android提供了一个称为DialogFragment的东西,可以将其扔到屏幕上,而无需定义的片段容器。
不幸的是,没有任何现成的解决方案可以从Xamarin Forms创建DialogFragment。好消息是,可以通过使用System.Reflection(;)来解决此问题,因此我们创建了自己的扩展方法以及内部类xamarin.forms的某些修改版本。为了实现这一点,我从Xamarin.Platform.Android中的Xamarin.Forms中获取了代码,并对其进行了修改以从ContentPage创建DialogFragment:
public static class PageExtensions
{
public static DialogFragment CreateDialogFragment(this ContentPage view, Context context)
{
if (!Forms.IsInitialized)
throw new InvalidOperationException("call Forms.Init() before this");
// Get Platform constructor via reflection and call it to create new platform object
Platform platform = (Platform)typeof(Platform).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Context), typeof(bool) }, null)
?.Invoke(new object[] { context, true });
// Set the page to the platform
if (platform != null)
{
platform.GetType().GetMethod("SetPage", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(platform, new object[] { view });
// Finally get the view group
ViewGroup vg = (Android.Views.ViewGroup)platform.GetType().GetMethod("GetViewGroup", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(platform, null);
return new EmbeddedDialogFragment(vg, platform);
}
return null;
}
public class DefaultApplication : Xamarin.Forms.Application
{
}
class EmbeddedDialogFragment : DialogFragment
{
readonly ViewGroup _content;
readonly Platform _platform;
bool _disposed;
public EmbeddedDialogFragment()
{
}
public EmbeddedDialogFragment(ViewGroup content, Platform platform)
{
_content = content;
_platform = platform;
}
public override global::Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.Dialog.Window.SetSoftInputMode(SoftInput.AdjustResize);
return _content;
}
public override void OnDestroy()
{
this.Dialog?.Window.SetSoftInputMode(SoftInput.AdjustPan);
base.OnDestroy();
}
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
_disposed = true;
if (disposing)
{
(_platform as IDisposable)?.Dispose();
}
base.Dispose(disposing);
}
}
}
iOS实现
幸运的是,对于iOS实现,无需深入研究Xamarin.Forms代码:
Here is the iOS implementation of DialogService:
[assembly: Dependency(typeof(DialogService))]
namespace BetterUI.iOS.Services
{
public class DialogService : IDialogs
{
private UIViewController currentDialog;
private UIWindow popupWindow = null;
public void HideLoading()
{
if (currentDialog != null)
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissModalViewController(false);
currentDialog.Dispose();
currentDialog = null;
}
}
public bool IsDialogOpen()
{
return (currentDialog != null && currentDialog.IsBeingPresented);
}
public void ShowLoading(LoadingDialog dialog)
{
UIViewController dialogController = dialog.CreateViewController();
ShowDialog(dialogController);
currentDialog = dialogController;
}
public void ShowPrompt(PromptDialog dialog)
{
UIViewController dialogController = dialog.CreateViewController();
ShowDialog(dialogController);
currentDialog = dialogController;
}
private void ShowDialog(UIViewController dialogController)
{
var bounds = UIScreen.MainScreen.Bounds;
dialogController.View.Frame = bounds;
UIApplication.SharedApplication.KeyWindow.RootViewController.ModalPresentationStyle = UIModalPresentationStyle.CurrentContext;
UIApplication.SharedApplication.KeyWindow.RootViewController.AddChildViewController(dialogController);
UIApplication.SharedApplication.KeyWindow.RootViewController.View.Opaque = false;
UIApplication.SharedApplication.KeyWindow.RootViewController.View.Layer.AllowsGroupOpacity = true;
UIApplication.SharedApplication.KeyWindow.RootViewController.View.Layer.BackgroundColor = new CGColor(Color.White.ToCGColor(), 0.0f);
UIApplication.SharedApplication.KeyWindow.RootViewController.View.BackgroundColor = UIColor.Clear;
UIApplication.SharedApplication.KeyWindow.RootViewController.View.AddSubview(dialogController.View);
dialogController.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
dialogController.View.Opaque = false;
dialogController.View.BackgroundColor = UIColor.Clear.ColorWithAlpha(0.0f);
}
}
}
等等,现在,每当我们使用本文中“方法”部分的调用时,都会出现一个包含自定义Xamarin.Forms ContentPage的漂亮弹出对话框。
答案 3 :(得分:0)
使用Plugins.Popup之类的包来实现此目的比较容易,没有自定义渲染器,就不可能将图像添加到默认的AlertDialog中,这将限制您的工作。
使用弹出插件,您只需将其添加到解决方案中,即可在iOS和Android中初始化:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init ();
LoadApplication (new App ());
return base.FinishedLaunching (app, options);
}
}
Android:
namespace HelloXamarinFormsWorld.Android
{
[Activity(Label = "HelloXamarinFormsWorld", MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Rg.Plugins.Popup.Popup.Init(this, bundle);
Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication (new App ());
}
}
}
创建弹出页面
<pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="400"
DurationOut="300"
EasingIn="SinOut"
EasingOut="SinIn"
HasBackgroundAnimation="True"/>
</pages:PopupPage.Animation>
<!--You can use any elements here which are extended from Xamarin.Forms.View-->
<StackLayout
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="20, 20, 20, 20">
<Label
Text="Test"/>
</StackLayout>
而且,要显示在您的页面中:
await Navigation.PushPopupAsync(page);
答案 4 :(得分:0)
使用名为“ Rg.Plugin.Popup”的软件包。它将为您提供帮助。