Added a Flow Direction Property to action sheets and alert dialogs (#11679)

* added constructor actionsheet

* added flow direction to action sheets on Android

* added flow direction to alerts on Android

* added Android alert dialog flow direction

* UWP alert/actionsheet flow direction

* add alert dialog flow direction

* added flow direction to UWP alert and actionsheets

* fixes #2448

* fixes #2448

* fixes #2448

* fixes #2448

* fixes #2448

* fixes #2448

* fixes #2448

* Fix rebase errors

* - fix rebase

Co-authored-by: E.Z. Hart <hartez@gmail.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
This commit is contained in:
memu8 2020-12-03 14:19:07 -06:00 коммит произвёл GitHub
Родитель 2dfbf5f5b9
Коммит 0b74649bf3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 325 добавлений и 14 удалений

Просмотреть файл

@ -10,18 +10,18 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.Issues namespace Xamarin.Forms.Controls.Issues
{ {
#if APP
#if UITEST #if UITEST
[NUnit.Framework.Category(Core.UITests.UITestCategories.Github5000)] [NUnit.Framework.Category(Core.UITests.UITestCategories.Github5000)]
#endif #endif
[Preserve (AllMembers = true)] [Preserve(AllMembers = true)]
[Issue (IssueTracker.Github, 2447, "Force label text direction", PlatformAffected.Android)] [Issue(IssueTracker.Github, 2447, "Force label text direction", PlatformAffected.Android)]
public partial class Issue2447 : ContentPage public partial class Issue2447 : ContentPage
{ {
public Issue2447 () #if APP
public Issue2447()
{ {
InitializeComponent(); InitializeComponent();
} }
}
#endif #endif
}
} }

Просмотреть файл

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Controls.Issues.Issue2448"
FlowDirection="MatchParent">
<StackLayout>
<Button
Clicked="AlertNoFlow_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display Alert No Flow Direction"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="AlertMatchParent_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display Alert Flow Direction Match Parent"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="AlertRTL_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display Alert Flow Direction RTL"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="AlertLTR_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display Alert Flow Direction LTR"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="ActionsheetNoFlow_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display ActionSheet No Flow Direction"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="ActionsheetMatchParent_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display ActionSheet Flow Direction Match Parent"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="ActionsheetRTL_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display ActionSheet Flow Direction RTL"
VerticalOptions="CenterAndExpand" />
<Button
Clicked="ActionsheetLTR_Clicked"
HorizontalOptions="CenterAndExpand"
Text="Display ActionSheet Flow Direction LTR"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 2448, "Setting FlowDirection of Alerts and ActionSheets", PlatformAffected.iOS | PlatformAffected.Android)]
#if APP
[XamlCompilation(XamlCompilationOptions.Compile)]
#endif
public partial class Issue2448 : ContentPage
{
public Issue2448()
{
#if APP
InitializeComponent();
#endif
}
#if APP
void AlertNoFlow_Clicked(object sender, EventArgs args)
{
var alert = DisplayAlert("Alert", "You have been alerted", "OK");
}
void AlertMatchParent_Clicked(object sender, EventArgs args)
{
var alert = DisplayAlert("Alert", "You have been alerted", "OK", FlowDirection.MatchParent);
}
void AlertRTL_Clicked(object sender, EventArgs args)
{
var alert = DisplayAlert("Alert", "You have been alerted", "OK", FlowDirection.RightToLeft);
}
void AlertLTR_Clicked(object sender, EventArgs args)
{
var alert = DisplayAlert("Alert", "You have been alerted", "OK", FlowDirection.LeftToRight);
}
void ActionsheetNoFlow_Clicked(object sender, EventArgs args)
{
var alert = DisplayActionSheet("ActionSheet: SavePhoto?", "Cancel", "Delete", "Photo Roll", "Email");
}
void ActionsheetMatchParent_Clicked(object sender, EventArgs args)
{
var alert = DisplayActionSheet("ActionSheet: SavePhoto?", "Cancel", "Delete", FlowDirection.MatchParent, "Photo Roll", "Email");
}
void ActionsheetRTL_Clicked(object sender, EventArgs args)
{
var alert = DisplayActionSheet("ActionSheet: SavePhoto?", "Cancel", "Delete", FlowDirection.RightToLeft, "Photo Roll", "Email");
}
void ActionsheetLTR_Clicked(object sender, EventArgs args)
{
var alert = DisplayActionSheet("ActionSheet: SavePhoto?", "Cancel", "Delete", FlowDirection.LeftToRight, "Photo Roll", "Email");
}
#endif
}
}

Просмотреть файл

@ -51,6 +51,12 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue12246.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue12246.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12652.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue12652.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12714.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue12714.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2447.xaml.cs">
<DependentUpon>Issue2447.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue2448.xaml.cs">
<DependentUpon>Issue2448.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue8613.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8613.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue9137.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue9137.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8691.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8691.cs" />
@ -2500,4 +2506,14 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator> <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
</Project> <ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue2447.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue2448.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>

Просмотреть файл

@ -15,6 +15,7 @@ namespace Xamarin.Forms.Internals
Destruction = destruction; Destruction = destruction;
Buttons = buttons?.Where(c => c != null); Buttons = buttons?.Where(c => c != null);
Result = new TaskCompletionSource<string>(); Result = new TaskCompletionSource<string>();
FlowDirection = FlowDirection.MatchParent;
} }
/// <summary> /// <summary>
@ -40,6 +41,8 @@ namespace Xamarin.Forms.Internals
/// </summary> /// </summary>
public string Title { get; private set; } public string Title { get; private set; }
public FlowDirection FlowDirection { get; set; }
public void SetResult(string result) public void SetResult(string result)
{ {
Result.TrySetResult(result); Result.TrySetResult(result);

Просмотреть файл

@ -13,6 +13,7 @@ namespace Xamarin.Forms.Internals
Accept = accept; Accept = accept;
Cancel = cancel; Cancel = cancel;
Result = new TaskCompletionSource<bool>(); Result = new TaskCompletionSource<bool>();
FlowDirection = FlowDirection.MatchParent;
} }
/// <summary> /// <summary>
@ -32,6 +33,8 @@ namespace Xamarin.Forms.Internals
public TaskCompletionSource<bool> Result { get; } public TaskCompletionSource<bool> Result { get; }
public FlowDirection FlowDirection { get; set; }
/// <summary> /// <summary>
/// Gets the title for the alert. Can be null. /// Gets the title for the alert. Can be null.
/// </summary> /// </summary>

Просмотреть файл

@ -179,9 +179,16 @@ namespace Xamarin.Forms
public event EventHandler Disappearing; public event EventHandler Disappearing;
public Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons) public Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons)
{
return DisplayActionSheet(title, cancel, destruction, FlowDirection.MatchParent, buttons);
}
public Task<string> DisplayActionSheet(string title, string cancel, string destruction, FlowDirection flowDirection, params string[] buttons)
{ {
var args = new ActionSheetArguments(title, cancel, destruction, buttons); var args = new ActionSheetArguments(title, cancel, destruction, buttons);
args.FlowDirection = flowDirection;
if (IsPlatformEnabled) if (IsPlatformEnabled)
MessagingCenter.Send(this, ActionSheetSignalName, args); MessagingCenter.Send(this, ActionSheetSignalName, args);
else else
@ -192,15 +199,27 @@ namespace Xamarin.Forms
public Task DisplayAlert(string title, string message, string cancel) public Task DisplayAlert(string title, string message, string cancel)
{ {
return DisplayAlert(title, message, null, cancel); return DisplayAlert(title, message, null, cancel, FlowDirection.MatchParent);
} }
public Task<bool> DisplayAlert(string title, string message, string accept, string cancel) public Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
{
return DisplayAlert(title, message, accept, cancel, FlowDirection.MatchParent);
}
public Task DisplayAlert(string title, string message, string cancel, FlowDirection flowDirection)
{
return DisplayAlert(title, message, null, cancel, flowDirection);
}
public Task<bool> DisplayAlert(string title, string message, string accept, string cancel, FlowDirection flowDirection)
{ {
if (string.IsNullOrEmpty(cancel)) if (string.IsNullOrEmpty(cancel))
throw new ArgumentNullException("cancel"); throw new ArgumentNullException("cancel");
var args = new AlertArguments(title, message, accept, cancel); var args = new AlertArguments(title, message, accept, cancel);
args.FlowDirection = flowDirection;
if (IsPlatformEnabled) if (IsPlatformEnabled)
MessagingCenter.Send(this, AlertSignalName, args); MessagingCenter.Send(this, AlertSignalName, args);
else else

Просмотреть файл

@ -96,7 +96,7 @@ namespace Xamarin.Forms.Platform.Android
builder.SetTitle(arguments.Title); builder.SetTitle(arguments.Title);
string[] items = arguments.Buttons.ToArray(); string[] items = arguments.Buttons.ToArray();
builder.SetItems(items, (o, args) => arguments.Result.TrySetResult(items[args.Which])); builder.SetItems(items, (o, args) => arguments.Result.TrySetResult(items[args.Which]));
if (arguments.Cancel != null) if (arguments.Cancel != null)
builder.SetPositiveButton(arguments.Cancel, (o, args) => arguments.Result.TrySetResult(arguments.Cancel)); builder.SetPositiveButton(arguments.Cancel, (o, args) => arguments.Result.TrySetResult(arguments.Cancel));
@ -107,9 +107,23 @@ namespace Xamarin.Forms.Platform.Android
builder.Dispose(); builder.Dispose();
//to match current functionality of renderer we set cancelable on outside //to match current functionality of renderer we set cancelable on outside
//and return null //and return null
if (arguments.FlowDirection == FlowDirection.MatchParent && sender is IVisualElementController ve)
dialog.Window.DecorView.UpdateFlowDirection(ve);
else if (arguments.FlowDirection == FlowDirection.LeftToRight)
dialog.Window.DecorView.LayoutDirection = LayoutDirection.Ltr;
else if (arguments.FlowDirection == FlowDirection.RightToLeft)
dialog.Window.DecorView.LayoutDirection = LayoutDirection.Rtl;
dialog.SetCanceledOnTouchOutside(true); dialog.SetCanceledOnTouchOutside(true);
dialog.SetCancelEvent((o, e) => arguments.SetResult(null)); dialog.SetCancelEvent((o, e) => arguments.SetResult(null));
dialog.Show(); dialog.Show();
dialog.GetListView().TextDirection = GetTextDirection(sender, arguments.FlowDirection);
LayoutDirection layoutDirection = GetLayoutDirection(sender, arguments.FlowDirection);
if (arguments.Cancel != null)
((dialog.GetButton((int)DialogButtonType.Positive).Parent) as global::Android.Views.View).LayoutDirection = layoutDirection;
if (arguments.Destruction != null)
((dialog.GetButton((int)DialogButtonType.Negative).Parent) as global::Android.Views.View).LayoutDirection = layoutDirection;
} }
void OnAlertRequested(Page sender, AlertArguments arguments) void OnAlertRequested(Page sender, AlertArguments arguments)
@ -120,7 +134,15 @@ namespace Xamarin.Forms.Platform.Android
return; return;
} }
int messageID = 16908299;
var alert = new DialogBuilder(Activity).Create(); var alert = new DialogBuilder(Activity).Create();
if (arguments.FlowDirection == FlowDirection.MatchParent && sender is IVisualElementController ve)
alert.Window.DecorView.UpdateFlowDirection(ve);
else if (arguments.FlowDirection == FlowDirection.LeftToRight)
alert.Window.DecorView.LayoutDirection = LayoutDirection.Ltr;
else if (arguments.FlowDirection == FlowDirection.RightToLeft)
alert.Window.DecorView.LayoutDirection = LayoutDirection.Rtl;
alert.SetTitle(arguments.Title); alert.SetTitle(arguments.Title);
alert.SetMessage(arguments.Message); alert.SetMessage(arguments.Message);
if (arguments.Accept != null) if (arguments.Accept != null)
@ -128,6 +150,42 @@ namespace Xamarin.Forms.Platform.Android
alert.SetButton((int)DialogButtonType.Negative, arguments.Cancel, (o, args) => arguments.SetResult(false)); alert.SetButton((int)DialogButtonType.Negative, arguments.Cancel, (o, args) => arguments.SetResult(false));
alert.SetCancelEvent((o, args) => { arguments.SetResult(false); }); alert.SetCancelEvent((o, args) => { arguments.SetResult(false); });
alert.Show(); alert.Show();
TextView textView = (TextView)alert.findViewByID(messageID);
textView.TextDirection = GetTextDirection(sender, arguments.FlowDirection);
((alert.GetButton((int)DialogButtonType.Negative).Parent) as global::Android.Views.View).LayoutDirection = GetLayoutDirection(sender, arguments.FlowDirection);
}
private LayoutDirection GetLayoutDirection(Page sender, FlowDirection flowDirection)
{
if (flowDirection == FlowDirection.LeftToRight)
return LayoutDirection.Ltr;
else if (flowDirection == FlowDirection.RightToLeft)
return LayoutDirection.Rtl;
else
{
if ((sender as IVisualElementController).EffectiveFlowDirection.IsRightToLeft())
return LayoutDirection.Rtl;
else if ((sender as IVisualElementController).EffectiveFlowDirection.IsLeftToRight())
return LayoutDirection.Ltr;
}
return LayoutDirection.Ltr;
}
private TextDirection GetTextDirection(Page sender, FlowDirection flowDirection)
{
if (flowDirection == FlowDirection.LeftToRight)
return TextDirection.Ltr;
else if (flowDirection == FlowDirection.RightToLeft)
return TextDirection.Rtl;
else
{
if ((sender as IVisualElementController).EffectiveFlowDirection.IsRightToLeft())
return TextDirection.Rtl;
else if ((sender as IVisualElementController).EffectiveFlowDirection.IsLeftToRight())
return TextDirection.Ltr;
}
return TextDirection.Ltr;
} }
void OnPromptRequested(Page sender, PromptArguments arguments) void OnPromptRequested(Page sender, PromptArguments arguments)
@ -357,6 +415,30 @@ namespace Xamarin.Forms.Platform.Android
} }
} }
public global::Android.Widget.Button GetButton(int whichButton)
{
if (_useAppCompat)
{
return _appcompatAlertDialog.GetButton(whichButton);
}
else
{
return _legacyAlertDialog.GetButton(whichButton);
}
}
public global::Android.Views.View GetListView()
{
if (_useAppCompat)
{
return _appcompatAlertDialog.ListView;
}
else
{
return _legacyAlertDialog.ListView;
}
}
public void SetCancelEvent(EventHandler cancel) public void SetCancelEvent(EventHandler cancel)
{ {
if (_useAppCompat) if (_useAppCompat)
@ -393,6 +475,18 @@ namespace Xamarin.Forms.Platform.Android
} }
} }
public global::Android.Views.View findViewByID(int id)
{
if (_useAppCompat)
{
return _appcompatAlertDialog.FindViewById(id);
}
else
{
return _legacyAlertDialog.FindViewById(id);
}
}
public Window Window => _useAppCompat ? _appcompatAlertDialog.Window : _legacyAlertDialog.Window; public Window Window => _useAppCompat ? _appcompatAlertDialog.Window : _legacyAlertDialog.Window;
public void Show() public void Show()

Просмотреть файл

@ -20,15 +20,39 @@ namespace Xamarin.Forms.Platform.UWP
TitleBlock.Text = options.Title ?? string.Empty; TitleBlock.Text = options.Title ?? string.Empty;
OptionsList.ItemsSource = options.Buttons.ToList(); OptionsList.ItemsSource = options.Buttons.ToList();
if (options.Cancel != null) if (options.FlowDirection == Xamarin.Forms.FlowDirection.RightToLeft)
{ {
RightBtn.Content = options.Cancel; TitleBlock.FlowDirection = Windows.UI.Xaml.FlowDirection.RightToLeft;
OptionsList.FlowDirection = Windows.UI.Xaml.FlowDirection.RightToLeft;
}
else if (options.FlowDirection == Xamarin.Forms.FlowDirection.LeftToRight)
{
TitleBlock.FlowDirection = Windows.UI.Xaml.FlowDirection.LeftToRight;
OptionsList.FlowDirection = Windows.UI.Xaml.FlowDirection.LeftToRight;
}
if (options.Destruction != null) if (options.FlowDirection == Xamarin.Forms.FlowDirection.RightToLeft)
{
if (options.Cancel != null)
{
LeftBtn.Content = options.Cancel;
if (options.Destruction != null)
RightBtn.Content = options.Destruction;
}
else if (options.Destruction != null)
LeftBtn.Content = options.Destruction; LeftBtn.Content = options.Destruction;
} }
else if (options.Destruction != null) else
RightBtn.Content = options.Destruction; {
if (options.Cancel != null)
{
RightBtn.Content = options.Cancel;
if (options.Destruction != null)
LeftBtn.Content = options.Destruction;
}
else if (options.Destruction != null)
RightBtn.Content = options.Destruction;
}
LeftBtn.Visibility = LeftBtn.Content == null ? Visibility.Collapsed : Visibility.Visible; LeftBtn.Visibility = LeftBtn.Content == null ? Visibility.Collapsed : Visibility.Visible;
RightBtn.Visibility = RightBtn.Content == null ? Visibility.Collapsed : Visibility.Visible; RightBtn.Visibility = RightBtn.Content == null ? Visibility.Collapsed : Visibility.Visible;

Просмотреть файл

@ -12,6 +12,7 @@ using Windows.UI.Xaml.Controls;
using Xamarin.Forms.Internals; using Xamarin.Forms.Internals;
using NativeAutomationProperties = Windows.UI.Xaml.Automation.AutomationProperties; using NativeAutomationProperties = Windows.UI.Xaml.Automation.AutomationProperties;
using WImage = Windows.UI.Xaml.Controls.Image; using WImage = Windows.UI.Xaml.Controls.Image;
using WFlowDirection = Windows.UI.Xaml.FlowDirection;
namespace Xamarin.Forms.Platform.UWP namespace Xamarin.Forms.Platform.UWP
{ {
@ -572,9 +573,22 @@ namespace Xamarin.Forms.Platform.UWP
MessagingCenter.Subscribe<Page, PromptArguments>(Window.Current, Page.PromptSignalName, OnPagePrompt); MessagingCenter.Subscribe<Page, PromptArguments>(Window.Current, Page.PromptSignalName, OnPagePrompt);
} }
static void OnPageActionSheet(object sender, ActionSheetArguments options) static void OnPageActionSheet(Page sender, ActionSheetArguments options)
{ {
bool userDidSelect = false; bool userDidSelect = false;
if (options.FlowDirection == FlowDirection.MatchParent)
{
if ((sender as IVisualElementController).EffectiveFlowDirection.IsRightToLeft())
{
options.FlowDirection = FlowDirection.RightToLeft;
}
else if ((sender as IVisualElementController).EffectiveFlowDirection.IsLeftToRight())
{
options.FlowDirection = FlowDirection.LeftToRight;
}
}
var flyoutContent = new FormsFlyout(options); var flyoutContent = new FormsFlyout(options);
var actionSheet = new Flyout var actionSheet = new Flyout
@ -658,6 +672,26 @@ namespace Xamarin.Forms.Platform.UWP
VerticalScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto VerticalScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto
}; };
if (options.FlowDirection == FlowDirection.RightToLeft)
{
alertDialog.FlowDirection = Windows.UI.Xaml.FlowDirection.RightToLeft;
}
else if (options.FlowDirection == FlowDirection.LeftToRight)
{
alertDialog.FlowDirection = Windows.UI.Xaml.FlowDirection.LeftToRight;
}
else
{
if ((sender as IVisualElementController).EffectiveFlowDirection.IsRightToLeft())
{
alertDialog.FlowDirection = WFlowDirection.RightToLeft;
}
else if ((sender as IVisualElementController).EffectiveFlowDirection.IsLeftToRight())
{
alertDialog.FlowDirection = WFlowDirection.LeftToRight;
}
}
if (options.Cancel != null) if (options.Cancel != null)
alertDialog.SecondaryButtonText = options.Cancel; alertDialog.SecondaryButtonText = options.Cancel;