Xamarin QLPreviewController + NavigationPage 在 iOS 10 上损坏

Posted

技术标签:

【中文标题】Xamarin QLPreviewController + NavigationPage 在 iOS 10 上损坏【英文标题】:Xamarin QLPreviewController + NavigationPage broken on iOS 10 【发布时间】:2017-02-13 20:06:57 【问题描述】:

将设备更新到 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 属性。

Sample app demonstrating the problem

Xamarin 表单 2.3.2.127

Xamarin Studio 6.1.1(内部版本 15)

【问题讨论】:

如果您认为这曾经在 iOS 9 上工作,而现在在 iOS 10 上不再适用,您应该在 bugreport.apple.com 上告诉他们! 我仍然不知道是 iOS、Xamarin 还是我的渲染器代码问题。我无法使用 Swift 和 XCode 重现它 【参考方案1】:

我也遇到过同样的问题。在 iOS10 的 QuickLook 中看起来像 something was changed or even broken,但解决方法很简单:

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);
        
    

结果:

【讨论】:

以上是关于Xamarin QLPreviewController + NavigationPage 在 iOS 10 上损坏的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Form与Xamarin.Android或Xamarin.IOS的区别简述

Xamarin.forms(或)xamarin.ios/xamarin.android(或)本机

Xamarin挖墙脚系列:Xamarin的核心

Xamarin.Forms 和 Xamarin Native 有啥区别? [关闭]

Xamarin SQLite教程Xamarin.iOS项目添加引用

新的 Xamarin 项目不使用最新的 Xamarin 版本