Как обрабатывать поворот экрана / ориентацию в Xamarin.Forms/XLabs?
Я пытаюсь определить, когда экран поворачивается (в Android), используя метод XLabs, подробно описанный здесь. Как обрабатывать поворот / ориентацию экрана в формах Xamarin? и у меня проблемы с этим.
Я переопределяю метод OnConfigurationChanged в MainActivity
public override void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged (newConfig);
var xapp = Resolver.Resolve<IXFormsApp> ();
if (xapp == null)
return;
switch (newConfig.Orientation) {
case Android.Content.Res.Orientation.Landscape:
xapp.Orientation = XLabs.Enums.Orientation.Landscape;
break;
case Android.Content.Res.Orientation.Portrait:
//xapp.Orientation = XLabs.Enums.Orientation.Portrait;
break;
default:
break;
}
}
У меня возникли проблемы с переменной Orientation в IXFormsApp, т. Е. Xapp.Orientation. Документация XLabs перечисляет это как "защищенный набор", как и компилятор:
MainActivity.cs(109,5,109,21): error CS0200: Property or indexer 'XLabs.Platform.Mvvm.IXFormsApp.Orientation' cannot be assigned to -- it is read only
и он не устанавливается автоматически (когда я проверяю, где он используется, он всегда устанавливается на "Нет"), поэтому мне было интересно, как его использовать и, действительно, как использовать XLabs/IXFormsApp для определения вращение?
В связи с этим я также пытался установить обработчик вращения (не уверен почему, но думал, что попробую) с необычными результатами.
xapp.Rotation += (sender, args) =>
{
switch (args.Value)
{
case XLabs.Enums.Orientation.Landscape:
//xapp.Orientation = XLabs.Enums.Orientation.Landscape;
...
break;
case XLabs.Enums.Orientation.Portrait:
...
break;
default:
break;
}
};
Если я пытаюсь в коде Android, я получаю следующую ошибку:
MainActivity.cs(60,4,60,22): error CS0019: Operator '+=' cannot be applied to operands of type 'System.EventHandler<XLabs.EventArgs<XLabs.Enums.Orientation>>' and 'lambda expression'
однако, если я установлю его в коде форм (где используются результаты), это нормально (хотя кажется, что обработчик никогда не вызывается). Кто-нибудь знает, почему это так?
2 ответа
Есть два разных решения, которые я использовал в прошлом.
Первый заключается в создании класса PageBase, от которого наследуются все мои страницы, а PageBase - от обычной страницы.
У моей PageBase есть два абстрактных метода (поэтому его должны заполнить дочерние элементы), а именно UpdateLandscape и UpdatePortait. Дети заполняют эти методы для того, как расположить страницу в зависимости от того, выкладывается ли она в альбомном или портретном режиме.
У страниц есть метод OnSizeAllocated, как сказал Даниэль. Я сделал PageBase переопределить его и сделать так, чтобы он вызывал UpdateLandscape и UpdatePortait соответственно.
Если, как вы сказали, вы просто хотите проверить, когда он повернулся, вышеприведенное работает просто отлично, так как OnSizeAllocated вызывается для страницы при каждом повороте телефона.
Если вы проверяете landscape vs portait, потому что хотите, чтобы ваш код мог проверяться в любое время, то второе решение ниже также работает.
Второй способ, который я решил, - это использовать службы зависимостей для заполнения интерфейса IDeviceInfo и записывать все динамические вещи, проверяя, является ли DeviceInfo.IsPortait() истинным или ложным (и таким образом я также позволяю DeviceInfo иметь ширину и высоту, поэтому Я могу запросить размеры экрана в любой точке).
На Android я заполнил свой код Android так:
[assembly: Dependency (typeof(Namespace.DeviceInfoProvider))]
namespace Namespace
{
public class DeviceInfoProvider : IDeviceInfoProvider
{
public bool IsPortait () { return DeviceInfoManager.Width < DeviceInfoManager.Height; }
public int GetWidth () { return DeviceInfoManager.Width; }
public int GetHeight () { return DeviceInfoManager.Height; }
}
public static class DeviceInfoManager
{
public static MainActivity MainActivity { get; set; }
public static int Width { get { return MainActivity.GetWidth (); } }
public static int Height { get { return MainActivity.GetHeight (); } }
}
}
Затем в MainActivity я дал ему эти методы:
public int GetWidth() {
return (int)(Resources.DisplayMetrics.WidthPixels / Resources.DisplayMetrics.Density);
}
public int GetHeight() {
return (int)(Resources.DisplayMetrics.HeightPixels / Resources.DisplayMetrics.Density);
}
И на стороне iOS, я заполнил это так:
[assembly: Dependency (typeof(Namespace.DeviceInfoProvider))]
namespace Namespace {
public class DeviceInfoProvider : IDeviceInfoProvider {
public bool IsPortait() { return UIScreen.MainScreen.Bounds.Width < UIScreen.MainScreen.Bounds.Height; }
public int GetWidth() { return (int)UIScreen.MainScreen.Bounds.Width; }
public int GetHeight() { return (int)UIScreen.MainScreen.Bounds.Height; }
}
}
Лично я больше люблю писать это вторым способом и проверять, "если мы в режиме портрета, вот различия". Таким образом, те вещи, которые не отличаются между портретом и ландшафтом, должны быть написаны только один раз, только различия записываются дважды.
Вы можете использовать переопределение метода OnSizeAllocated для обнаружения изменения ориентации;
double previousWidth;
double previousHeight;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if (previousWidth != width || previousHeight != height)
{
previousWidth = width;
previousHeight = height;
if (width > height)
{
// landscape mode
}
else
{
// portrait mode
}
}
}