diff --git a/src/MauiNativePdfView/Platforms/iOS/PdfViewiOS.cs b/src/MauiNativePdfView/Platforms/iOS/PdfViewiOS.cs index 896b8ab..2ee3e5f 100644 --- a/src/MauiNativePdfView/Platforms/iOS/PdfViewiOS.cs +++ b/src/MauiNativePdfView/Platforms/iOS/PdfViewiOS.cs @@ -21,8 +21,12 @@ public class PdfViewiOS : IPdfView, IDisposable private bool _documentLoaded = false; private bool _enableAnnotationRendering = true; private bool _enableTapGestures = true; + private bool _enableZoom = true; + private float _minZoom = 1.0f; + private float _maxZoom = 3.0f; private FitPolicy _fitPolicy = FitPolicy.Width; private bool _needsFitReapply = false; + private bool _needsZoomConstraintsApply = false; private PageAlignment _pageAlignment = PageAlignment.Default; private Color? _backgroundColor; @@ -43,6 +47,9 @@ public PdfViewiOS() if (_needsFitReapply) ApplyFitPolicy(); + if (_needsZoomConstraintsApply) + ApplyZoomConstraints(); + ApplyPageAlignment(); }; @@ -89,20 +96,14 @@ public PdfSource? Source public bool EnableZoom { - get => _pdfView.MinScaleFactor < _pdfView.MaxScaleFactor; + get => _enableZoom; set { - if (value) - { - _pdfView.MinScaleFactor = MinZoom; - _pdfView.MaxScaleFactor = MaxZoom; - } - else - { - var currentScale = _pdfView.ScaleFactor; - _pdfView.MinScaleFactor = currentScale; - _pdfView.MaxScaleFactor = currentScale; - } + if (_enableZoom == value) + return; + + _enableZoom = value; + ApplyZoomConstraints(); } } @@ -146,9 +147,31 @@ public float Zoom set => _pdfView.ScaleFactor = value; } - public float MinZoom { get; set; } = 1.0f; + public float MinZoom + { + get => _minZoom; + set + { + if (Math.Abs(_minZoom - value) <= float.Epsilon) + return; + + _minZoom = value; + ApplyZoomConstraints(); + } + } + + public float MaxZoom + { + get => _maxZoom; + set + { + if (Math.Abs(_maxZoom - value) <= float.Epsilon) + return; - public float MaxZoom { get; set; } = 3.0f; + _maxZoom = value; + ApplyZoomConstraints(); + } + } public int PageSpacing { @@ -172,6 +195,9 @@ public FitPolicy FitPolicy private void ApplyFitPolicy() { + // Zoom constraints must be re-applied after the fit scale is (re-)computed. + _needsZoomConstraintsApply = true; + switch (_fitPolicy) { case FitPolicy.Width: @@ -237,6 +263,46 @@ private bool SetManualScale(bool fitWidth, bool fitHeight) return true; } + /// + /// Applies and as absolute scale-factor bounds + /// on the native PDFView. The values are treated as multipliers relative to the current + /// fit scale (i.e. the scale that was computed by the active ), so + /// a of 1.0 means "cannot zoom out below the fit scale", and + /// a of 3.0 means "can zoom in up to 3× the fit scale". + /// + /// The method defers via when the document has + /// not yet been loaded or the native view has not yet been laid out with non-zero bounds + /// (so that reflects the final fit scale). + /// + private void ApplyZoomConstraints() + { + if (!_documentLoaded) + return; + + var fitScale = (float)_pdfView.ScaleFactor; + if (fitScale <= 0 || _pdfView.Bounds.Width <= 0) + { + // Defer until the view has been laid out with a valid scale factor. + _needsZoomConstraintsApply = true; + return; + } + + _needsZoomConstraintsApply = false; + + if (!_enableZoom) + { + // Lock zoom completely at the current fit scale. + _pdfView.MinScaleFactor = fitScale; + _pdfView.MaxScaleFactor = fitScale; + } + else + { + _pdfView.MinScaleFactor = _minZoom * fitScale; + _pdfView.MaxScaleFactor = _maxZoom * fitScale; + } + } + + public Abstractions.PdfDisplayMode DisplayMode { get