TPV fixes for landscape, WindowSpanModeStateTrigger, ContentArea calculation fixes (#9577)

This commit is contained in:
Shane Neuville 2020-02-18 10:26:11 -07:00 коммит произвёл GitHub
Родитель 3072ecdf4a
Коммит d4a67e40af
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 350 добавлений и 48 удалений

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

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:dualscreen="clr-namespace:Xamarin.Forms.DualScreen;assembly=Xamarin.Forms.DualScreen"
mc:Ignorable="d"
x:Class="Xamarin.Forms.Controls.GalleryPages.TwoPaneViewGalleries.DualScreenInfoGallery">
<ContentPage.Content>
<dualscreen:TwoPaneView x:Name="tpv">
<dualscreen:TwoPaneView.Pane1>
<StackLayout>
<Label FontAttributes="Bold" Text="Two Pane View Properties" HorizontalOptions="Center" />
<Label Text="SpanningBound 1" HorizontalOptions="Center" />
<Label x:Name="tpvSpanningBounds1" Text="" HorizontalOptions="Center" />
<Label Text="SpanningBound 2" HorizontalOptions="Center" />
<Label x:Name="tpvSpanningBounds2" Text="" HorizontalOptions="Center" />
<Label Text="HingeBounds" HorizontalOptions="Center" />
<Label x:Name="tpvHingeBounds" Text="" HorizontalOptions="Center" />
<Label Text="IsLandscape" HorizontalOptions="Center" />
<Label x:Name="tpvIsLandscape" Text="" HorizontalOptions="Center" />
<Label Text="SpanMode" HorizontalOptions="Center" />
<Label x:Name="tpvSpanMode" Text="" HorizontalOptions="Center" />
</StackLayout>
</dualscreen:TwoPaneView.Pane1>
<dualscreen:TwoPaneView.Pane2>
<StackLayout>
<Label FontAttributes="Bold" Text="Device Properties" HorizontalOptions="Center" />
<Label Text="SpanningBound 1" HorizontalOptions="Center" />
<Label x:Name="deviceSpanningBounds1" Text="" HorizontalOptions="Center" />
<Label Text="SpanningBound 2" HorizontalOptions="Center" />
<Label x:Name="deviceSpanningBounds2" Text="" HorizontalOptions="Center" />
<Label Text="HingeBounds" HorizontalOptions="Center" />
<Label x:Name="deviceHingeBounds" Text="" HorizontalOptions="Center" />
<Label Text="IsLandscape" HorizontalOptions="Center" />
<Label x:Name="deviceIsLandscape" Text="" HorizontalOptions="Center" />
<Label Text="SpanMode" HorizontalOptions="Center" />
<Label x:Name="deviceSpanMode" Text="" HorizontalOptions="Center" />
</StackLayout>
</dualscreen:TwoPaneView.Pane2>
</dualscreen:TwoPaneView>
</ContentPage.Content>
</ContentPage>

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

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.Controls.GalleryPages.TwoPaneViewGalleries
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class DualScreenInfoGallery : ContentPage
{
DualScreen.DualScreenInfo info;
public DualScreenInfoGallery()
{
InitializeComponent();
info = new DualScreen.DualScreenInfo(tpv);
}
protected override void OnAppearing()
{
base.OnAppearing();
DualScreen.DualScreenInfo.Current.PropertyChanged += OnCurrentPropertyChanged;
info.PropertyChanged += OnTPVPropertyChanged;
OnTPVPropertyChanged(null, null);
OnCurrentPropertyChanged(null, null);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
DualScreen.DualScreenInfo.Current.PropertyChanged -= OnCurrentPropertyChanged;
info.PropertyChanged -= OnTPVPropertyChanged;
}
void OnTPVPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (info.SpanningBounds.Length == 2)
{
tpvSpanningBounds1.Text = $"{info.SpanningBounds[0]}";
tpvSpanningBounds2.Text = $"{info.SpanningBounds[1]}";
}
else
{
tpvSpanningBounds1.Text = "Not Spanned";
tpvSpanningBounds2.Text = "Not Spanned";
}
tpvHingeBounds.Text = $"{info.HingeBounds}";
tpvIsLandscape.Text = $"{info.IsLandscape}";
tpvSpanMode.Text = $"{tpv.Mode}";
}
void OnCurrentPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (DualScreen.DualScreenInfo.Current.SpanningBounds.Length == 2)
{
deviceSpanningBounds1.Text = $"{DualScreen.DualScreenInfo.Current.SpanningBounds[0]}";
deviceSpanningBounds2.Text = $"{DualScreen.DualScreenInfo.Current.SpanningBounds[1]}";
}
else
{
deviceSpanningBounds1.Text = "Not Spanned";
deviceSpanningBounds2.Text = "Not Spanned";
}
deviceHingeBounds.Text = $"{DualScreen.DualScreenInfo.Current.HingeBounds}";
deviceIsLandscape.Text = $"{DualScreen.DualScreenInfo.Current.IsLandscape}";
deviceSpanMode.Text = $"{DualScreen.DualScreenInfo.Current.SpanMode}";
}
}
}

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

@ -41,6 +41,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.TwoPaneViewGalleries
GalleryBuilder.NavButton("Open Picture in Picture Window", () => new OpenCompactWindow(), Navigation),
GalleryBuilder.NavButton("DualScreenInfo with non TwoPaneView", () => new GridUsingDualScreenInfo(), Navigation),
GalleryBuilder.NavButton("eReader Samples", () => new TwoPage(), Navigation),
GalleryBuilder.NavButton("Dual Screen Info Samples", () => new DualScreenInfoGallery(), Navigation),
}
};

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

@ -7,11 +7,15 @@
Title="DualScreenStateTrigger Gallery">
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="NotSpanned">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="SinglePane"/>
<dualScreen:WindowSpanModeStateTrigger SpanMode="SinglePane"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Red" />
@ -19,14 +23,54 @@
</VisualState>
<VisualState x:Name="Spanned">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="Wide" />
<dualScreen:WindowSpanModeStateTrigger SpanMode="Wide" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Tall">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="Tall" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Yellow" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Grid.Row="1" Text="SinglePane: Red, Wide: Green, Tall: Yellow"></Label>
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="GridSingle">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="SinglePane"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="GridWide">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="Wide" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Red" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="GridTall">
<VisualState.StateTriggers>
<dualScreen:SpanModeStateTrigger SpanMode="Tall" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Purple" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="SinglePane: Green, Wide: Red, Tall: Purple"></Label>
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>

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

@ -64,22 +64,6 @@
<ItemGroup>
<Folder Include="Fonts\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="GalleryPages\TwoPaneViewGalleries\GridUsingDualScreenInfo.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\TwoPaneViewGalleries\OpenCompactWindow.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\TwoPaneViewGalleries\TwoPage.xaml">
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\TwoPaneViewGalleries\TwoPanePropertiesGallery.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<Target Name="CreateControllGalleryConfig" BeforeTargets="Build">
<CreateItem Include="blank.config">
<Output TaskParameter="Include" ItemName="ConfigFile" />

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

@ -6,7 +6,7 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms.DualScreen
{
internal interface IDualScreenService : IDisposable
internal interface IDualScreenService
{
event EventHandler OnScreenChanged;
bool IsSpanned { get; }

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

@ -21,11 +21,11 @@ namespace Xamarin.Forms.DualScreen
IDualScreenService DualScreenService =>
_dualScreenService ?? DependencyService.Get<IDualScreenService>() ?? NoDualScreenServiceImpl.Instance;
public DualScreenInfo(Layout layout) : this(layout, null)
public DualScreenInfo(VisualElement layout) : this(layout, null)
{
}
internal DualScreenInfo(Layout layout, IDualScreenService dualScreenService)
internal DualScreenInfo(VisualElement layout, IDualScreenService dualScreenService)
{
_dualScreenService = dualScreenService;
if (layout == null)

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

@ -23,7 +23,7 @@ namespace Xamarin.Forms.DualScreen
DualScreenServiceImpl.Init(activity);
}
internal class DualScreenServiceImpl : IDualScreenService, IDisposable
internal class DualScreenServiceImpl : IDualScreenService, Platform.Android.DualScreen.IDualScreenService
{
public event EventHandler OnScreenChanged;
ScreenHelper _helper;
@ -32,7 +32,6 @@ namespace Xamarin.Forms.DualScreen
static Activity _mainActivity;
static DualScreenServiceImpl _HingeService;
bool _isDisposed;
bool _isLandscape;
Size _pixelScreenSize;
object _hingeAngleLock = new object();
@ -116,19 +115,6 @@ namespace Xamarin.Forms.DualScreen
OnScreenChanged?.Invoke(this, e);
}
public void Dispose()
{
if (_isDisposed)
return;
_isDisposed = true;
// make sure the one shot task is cleared out if it's running
SetHingeAngle(0);
StopListeningForHingeChanges();
}
public Size ScaledScreenSize
{
get;
@ -207,7 +193,13 @@ namespace Xamarin.Forms.DualScreen
get
{
if (!_isDuo || _helper == null)
return false;
{
if (_mainActivity == null)
return false;
var orientation = _mainActivity.Resources.Configuration.Orientation;
return orientation == global::Android.Content.Res.Orientation.Landscape;
}
var rotation = ScreenHelper.GetRotation(_helper.Activity);

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

@ -18,7 +18,7 @@ using Xamarin.Forms.Platform.UWP;
[assembly: Dependency(typeof(DualScreenService))]
namespace Xamarin.Forms.DualScreen
{
internal partial class DualScreenService : IDualScreenService
internal partial class DualScreenService : IDualScreenService, Platform.UWP.DualScreen.IDualScreenService
{
public event EventHandler OnScreenChanged;

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

@ -4,6 +4,8 @@ namespace Xamarin.Forms.DualScreen
{
public sealed class SpanModeStateTrigger : StateTriggerBase
{
VisualElement _visualElement;
DualScreenInfo _info;
public SpanModeStateTrigger()
{
UpdateState();
@ -24,14 +26,32 @@ namespace Xamarin.Forms.DualScreen
((SpanModeStateTrigger)bindable).UpdateState();
}
void AttachToVisualElement()
{
var visualElement = VisualState?.VisualStateGroup?.VisualElement;
if (visualElement == null || visualElement == _visualElement)
{
return;
}
if(_info != null)
_info.PropertyChanged -= OnDualScreenInfoPropertyChanged;
_visualElement = visualElement;
_info = new DualScreenInfo(_visualElement);
}
internal override void OnAttached()
{
base.OnAttached();
if (!DesignMode.IsDesignModeEnabled)
{
AttachToVisualElement();
UpdateState();
DualScreenInfo.Current.PropertyChanged += OnDualScreenInfoPropertyChanged;
if (_info != null)
_info.PropertyChanged += OnDualScreenInfoPropertyChanged;
}
}
@ -39,7 +59,8 @@ namespace Xamarin.Forms.DualScreen
{
base.OnDetached();
DualScreenInfo.Current.PropertyChanged -= OnDualScreenInfoPropertyChanged;
if (_info != null)
_info.PropertyChanged -= OnDualScreenInfoPropertyChanged;
}
void OnDualScreenInfoPropertyChanged(object sender, PropertyChangedEventArgs e)
@ -49,7 +70,10 @@ namespace Xamarin.Forms.DualScreen
void UpdateState()
{
var spanMode = DualScreenInfo.Current.SpanMode;
if (_info == null)
return;
var spanMode = _info.SpanMode;
switch (SpanMode)
{

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

@ -20,7 +20,7 @@ namespace Xamarin.Forms.DualScreen
Rectangle _leftPage;
Rectangle _rightPane;
TwoPaneViewMode _mode;
Layout _layout;
VisualElement _layout;
readonly IDualScreenService _dualScreenService;
bool _isLandscape;
public event PropertyChangedEventHandler PropertyChanged;
@ -33,12 +33,12 @@ namespace Xamarin.Forms.DualScreen
}
public TwoPaneViewLayoutGuide(Layout layout) : this(layout, null)
public TwoPaneViewLayoutGuide(VisualElement layout) : this(layout, null)
{
}
internal TwoPaneViewLayoutGuide(Layout layout, IDualScreenService dualScreenService)
internal TwoPaneViewLayoutGuide(VisualElement layout, IDualScreenService dualScreenService)
{
_layout = layout;
_dualScreenService = dualScreenService;
@ -48,6 +48,7 @@ namespace Xamarin.Forms.DualScreen
UpdateLayouts();
_layout.PropertyChanged += OnLayoutPropertyChanged;
_layout.PropertyChanging += OnLayoutPropertyChanging;
WatchForChanges();
}
}
@ -70,6 +71,7 @@ namespace Xamarin.Forms.DualScreen
if (_layout != null)
{
_watchHandle = DualScreenService.WatchForChangesOnLayout(_layout, () => OnScreenChanged(DualScreenService, EventArgs.Empty));
if (_watchHandle == null)
return;
}
@ -334,7 +336,7 @@ namespace Xamarin.Forms.DualScreen
TwoPaneViewMode GetTwoPaneViewMode()
{
if (!IsInMultipleRegions(GetContainerArea()))
if (!IsInMultipleRegions(GetScreenRelativeBounds()))
return TwoPaneViewMode.SinglePane;
if (DualScreenService.IsLandscape)

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

@ -0,0 +1,68 @@
using System.ComponentModel;
namespace Xamarin.Forms.DualScreen
{
public sealed class WindowSpanModeStateTrigger : StateTriggerBase
{
public WindowSpanModeStateTrigger()
{
UpdateState();
}
public TwoPaneViewMode SpanMode
{
get => (TwoPaneViewMode)GetValue(SpanModeProperty);
set => SetValue(SpanModeProperty, value);
}
public static readonly BindableProperty SpanModeProperty =
BindableProperty.Create(nameof(SpanMode), typeof(TwoPaneViewMode), typeof(WindowSpanModeStateTrigger), default(TwoPaneViewMode),
propertyChanged: OnSpanModeChanged);
static void OnSpanModeChanged(BindableObject bindable, object oldvalue, object newvalue)
{
((WindowSpanModeStateTrigger)bindable).UpdateState();
}
internal override void OnAttached()
{
base.OnAttached();
if (!DesignMode.IsDesignModeEnabled)
{
UpdateState();
DualScreenInfo.Current.PropertyChanged += OnDualScreenInfoPropertyChanged;
}
}
internal override void OnDetached()
{
base.OnDetached();
DualScreenInfo.Current.PropertyChanged -= OnDualScreenInfoPropertyChanged;
}
void OnDualScreenInfoPropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateState();
}
void UpdateState()
{
var spanMode = DualScreenInfo.Current.SpanMode;
switch (SpanMode)
{
case TwoPaneViewMode.SinglePane:
SetActive(spanMode == TwoPaneViewMode.SinglePane);
break;
case TwoPaneViewMode.Tall:
SetActive(spanMode == TwoPaneViewMode.Tall);
break;
case TwoPaneViewMode.Wide:
SetActive(spanMode == TwoPaneViewMode.Wide);
break;
}
}
}
}

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

@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;
namespace Xamarin.Forms.Platform.Android.DualScreen
{
internal interface IDualScreenService
{
event EventHandler OnScreenChanged;
bool IsSpanned { get; }
bool IsLandscape { get; }
Rectangle GetHinge();
Size ScaledScreenSize { get; }
Point? GetLocationOnScreen(VisualElement visualElement);
object WatchForChangesOnLayout(VisualElement visualElement, Action action);
void StopWatchingForChangesOnLayout(VisualElement visualElement, object handle);
Task<int> GetHingeAngleAsync();
}
}

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

@ -493,6 +493,7 @@ namespace Xamarin.Forms
double _scalingFactor;
Orientation _previousOrientation = Orientation.Undefined;
Platform.Android.DualScreen.IDualScreenService DualScreenService => DependencyService.Get<Platform.Android.DualScreen.IDualScreenService>();
public AndroidDeviceInfo(Context formsActivity)
{
@ -555,7 +556,16 @@ namespace Xamarin.Forms
void CheckOrientationChanged(Context formsActivity)
{
var orientation = formsActivity.Resources.Configuration.Orientation;
Orientation orientation;
if (DualScreenService?.IsSpanned == true)
{
orientation = (DualScreenService.IsLandscape) ? Orientation.Landscape : Orientation.Portrait;
}
else
{
orientation = formsActivity.Resources.Configuration.Orientation;
}
if (!_previousOrientation.Equals(orientation))
CurrentOrientation = orientation.ToDeviceOrientation();

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

@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;
namespace Xamarin.Forms.Platform.UWP.DualScreen
{
internal interface IDualScreenService
{
event EventHandler OnScreenChanged;
bool IsSpanned { get; }
bool IsLandscape { get; }
Rectangle GetHinge();
Size ScaledScreenSize { get; }
Point? GetLocationOnScreen(VisualElement visualElement);
object WatchForChangesOnLayout(VisualElement visualElement, Action action);
void StopWatchingForChangesOnLayout(VisualElement visualElement, object handle);
Task<int> GetHingeAngleAsync();
}
}

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

@ -62,4 +62,6 @@ using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer))]
//Fonts
[assembly: ExportRenderer(typeof(EmbeddedFont), typeof(EmbeddedFontLoader))]
[assembly: ExportRenderer(typeof(EmbeddedFont), typeof(EmbeddedFontLoader))]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Xamarin.Forms.DualScreen")]

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

@ -10,6 +10,7 @@ namespace Xamarin.Forms.Platform.UWP
{
DisplayInformation _information;
bool _isDisposed;
DualScreen.IDualScreenService DualScreenService => DependencyService.Get<DualScreen.IDualScreenService>();
public WindowsDeviceInfo()
{
@ -67,6 +68,7 @@ namespace Xamarin.Forms.Platform.UWP
static DeviceOrientation GetDeviceOrientation(DisplayOrientations orientations)
{
switch (orientations)
{
case DisplayOrientations.Landscape:
@ -85,7 +87,14 @@ namespace Xamarin.Forms.Platform.UWP
void OnOrientationChanged(DisplayInformation sender, object args)
{
CurrentOrientation = GetDeviceOrientation(sender.CurrentOrientation);
if (DualScreenService?.IsSpanned == true)
{
CurrentOrientation = (DualScreenService.IsLandscape) ? DeviceOrientation.Landscape : DeviceOrientation.Portrait;
}
else
{
CurrentOrientation = GetDeviceOrientation(sender.CurrentOrientation);
}
}
}
}