Xamarin QLPreviewController + NavigationPage не работает на iOS 10
После обновления устройства до iOS 10, QLPreviewController перестал корректно отображать документы. Это показывает белый экран. Я извлек пример сценария из приложения.
Он содержит одну страницу с двумя кнопками, которые должны загрузить два разных документа:
<?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:local="clr-namespace:QuickLookIOS10Test"
x:Class="QuickLookIOS10Test.QuickLookIOS10TestPage">
<StackLayout Orientation="Vertical">
<Button Text="Load first doc" Clicked="OnLoadFirstClicked"/>
<Button Text="Load second doc" Clicked="OnLoadSecondClicked"/>
<Button Text="Navigate forward" Clicked="OnForwardClicked"/>
<local:QLDocumentView
x:Name="DocumentView"
BackgroundColor="Silver"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"/>
</StackLayout>
</ContentPage>
где:
public class QLDocumentView : View
{
public static readonly BindableProperty FilePathProperty =
BindableProperty.Create(nameof(FilePath), typeof(string), typeof(QLDocumentView), null);
public string FilePath
{
get { return (string)GetValue(FilePathProperty); }
set { SetValue(FilePathProperty, value); }
}
}
Там участвует пользовательский рендер:
public class QLDocumentViewRenderer : ViewRenderer<QLDocumentView, UIView>
{
private QLPreviewController controller;
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
//This is a fix to prevent incorrect scaling after rotating from portrait to landscape.
//No idea why does this work :( Bug #101639
return new SizeRequest(Size.Zero, Size.Zero);
}
protected override void OnElementChanged(ElementChangedEventArgs<QLDocumentView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
controller = new QLPreviewController();
SetNativeControl(controller.View);
}
RefreshView();
}
protected override void OnElementPropertyChanged(object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == QLDocumentView.FilePathProperty.PropertyName)
{
RefreshView();
}
}
private void RefreshView()
{
DisposeDataSource();
if (Element?.FilePath != null)
{
controller.DataSource = new DocumentQLPreviewControllerDataSource(Element.FilePath);
}
controller.ReloadData();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
DisposeDataSource();
DisposeController();
}
}
private void DisposeDataSource()
{
var dataSource = controller.DataSource;
controller.DataSource = null;
dataSource?.Dispose();
}
private void DisposeController()
{
controller?.Dispose();
controller = null;
}
private class DocumentQLPreviewControllerDataSource : QLPreviewControllerDataSource
{
private readonly string fileName;
public DocumentQLPreviewControllerDataSource(string fileName)
{
this.fileName = fileName;
}
public override nint PreviewItemCount(QLPreviewController controller)
{
return 1;
}
public override IQLPreviewItem GetPreviewItem(QLPreviewController controller, nint index)
{
NSUrl url = NSUrl.FromFilename(fileName);
return new QlItem(url);
}
private sealed class QlItem : QLPreviewItem
{
private readonly NSUrl itemUrl;
public QlItem(NSUrl uri)
{
itemUrl = uri;
}
public override string ItemTitle { get { return string.Empty; } }
public override NSUrl ItemUrl { get { return itemUrl; } }
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
this.itemUrl?.Dispose();
}
}
}
}
}
Если приложение настраивает главную страницу, как показано ниже:
MainPage = new NavigationPage(new QuickLookIOS10TestPage());
он работает на iOS 9.3, но не на iOS 10. Если я удаляю NavigationPage:
MainPage = new QuickLookIOS10TestPage();
это работает на обеих версиях iOS.
Код для нажатия кнопки просто устанавливает свойство FilePath элемента управления.
Пример приложения, демонстрирующего проблему
Xamarin Forms 2.3.2.127
Xamarin Studio 6.1.1 (сборка 15)
1 ответ
Я столкнулся с той же проблемой. Похоже, что- то было изменено или даже сломано в QuickLook в iOS10, но решение довольно простое:
public class PdfViewerControlRenderer : ViewRenderer<PdfViewerControl, UIView>
{
private readonly bool IsOniOS10;
private UIViewController _controller;
private QLPreviewController _qlPreviewController;
public PdfViewerControlRenderer()
{
IsOniOS10 = UIDevice.CurrentDevice.CheckSystemVersion(10, 0);
}
protected override void OnElementChanged(ElementChangedEventArgs<PdfViewerControl> e)
{
if (e.NewElement != null)
{
_controller = new UIViewController();
_qlPreviewController = new QLPreviewController();
//...
// Set QuickLook datasource here
//...
if (!IsOniOS10)
{
_controller.AddChildViewController(_qlPreviewController);
_controller.View.AddSubview(_qlPreviewController.View);
_qlPreviewController.DidMoveToParentViewController(_controller);
}
SetNativeControl(_controller.View);
}
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
_controller.View.Frame = Bounds;
_controller.View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
_qlPreviewController.View.Frame = Bounds;
if (IsOniOS10)
{
_controller.View.AddSubview(_qlPreviewController.View);
_qlPreviewController.DidMoveToParentViewController(_controller);
}
}
}
Результат: