具有 Next/Previous 页面预览的 Xamarin iOS UIScrollView:缩放未按预期工作

Xamarin iOS UIScrollView With Next/Previous Page Preview: Zoom Not Working as Expected

我有一个分页的 UIScrollView,其中填充了一组 UIImageView。滚动视图显示上一页和下一页的预览。

我的目标是让滚动视图的每一页都可以缩放。这是我遇到的问题的 gif,其中其他页面似乎随着图像的缩放而改变了它们的坐标:

我相信缩放本身会导致滚动视图的 ContentSize 发生巨大变化,这会使其他所有内容都乱七八糟。

故事板层次结构

[控制器]

---- [UIView]

-------- [UIScrollView], 自定义 Class CapturedResultScrollView

我的 UIScrollView 对其父 UIView 有以下约束:

代码

这是 CapturedResultScrollView 实现以及委托:

public class CaptureResultScrollViewDelegate : UIScrollViewDelegate {
    public CaptureResultScrollViewDelegate(IHandlePaging pageHandler) {
        this.pageHandler = pageHandler ?? throw new ArgumentNullException(nameof(pageHandler));
    }

    private readonly IHandlePaging pageHandler;

    public override UIView ViewForZoomingInScrollView(UIScrollView scrollView) {
        var pageIndex = (int)Math.Round(scrollView.ContentOffset.X / scrollView.Frame.Size.Width);
        return pageHandler.Pages[pageIndex];
    }
}

public interface IHandlePaging {
    UIImageView[] Pages { get; set; }
}

public partial class CaptureResultScrollView : UIScrollView, IHandlePaging {
    public CaptureResultScrollView(IntPtr handle) : base(handle) {
        MinimumZoomScale = 1.0f;
        MaximumZoomScale = 3.0f;
        ZoomScale = 1.0f;
        PagingEnabled = true;
        ClipsToBounds = false;
        ShowsHorizontalScrollIndicator = false;
        ShowsVerticalScrollIndicator = false;
        Delegate = new CaptureResultScrollViewDelegate(this);
    }

    public UIImageView[] Pages { get; set; }

    public void Setup(IList<CapturedResultModel> capturedResults) {
        // setup called from another controller during segue
        Pages = new UIImageView[capturedResults.Count];

        var pageSize = Frame.Size;
        ContentSize = new CGSize(pageSize.Width * Pages.Length, pageSize.Height);

        for (int page = 0; page < capturedResults.Count; page++) {
            var imageView = new UIImageView() {
                // hardcoded value allow for preview of previous/next pages.
                Frame = new CGRect(pageSize.Width * page, 0, pageSize.Width - 30, pageSize.Height),
                ContentMode = UIViewContentMode.ScaleAspectFill,
                Image = UIImage.FromFile(capturedResults[page].ResultImagePath),
                ClipsToBounds = true
            };

            AddSubview(imageView);
            Pages[page] = imageView;
        }
    }
}

当包含控制器的ViewWillAppear事件被触发时,CaptureResultScrollViewSetup方法被调用如下:

public override void ViewWillAppear(bool animated) {
    base.ViewWillAppear(animated);

    CapturedResultScrollView.Setup(CapturedResults);
}

我做错了什么?

原因:

我认为你的问题是你为方法 ViewForZoomingInScrollView 设置了 imageView,当你缩放你选择的 imageview 时,只有 imageView 会缩放并且其他 imageView 将保持它们在其 superView 中的位置(这里是 ScrollerView),因此其他页面似乎会随着图像缩放而改变它们的坐标。

  public override UIView ViewForZoomingInScrollView(UIScrollView scrollView) {
        var pageIndex = (int)Math.Round(scrollView.ContentOffset.X / scrollView.Frame.Size.Width);
        return pageHandler.Pages[pageIndex];
    }

解法:

我的建议是您可以添加一个与 ScrollView 具有相同框架的视图作为您的 imageView 的超级视图。并将此视图设置为方法 ViewForZoomingInScrollView 的 return 值而不是 imageView,因此当您缩放此视图时,imageViews 将正确缩放。

这是我的代码:

1.Add backView in you IHandlePaging interface

 public interface IHandlePaging
    {
        UIImageView[] Pages { get; set; }

        UIView backView { get; set; }

    }

2.Add 这个 backView 到 ScrovllView 并将 ImageView 添加到这个 backView

 public void Setup(IList<CapturedResultModel> capturedResults)
        {

            Pages = new UIImageView[capturedResults.Count];
            var pageSize = Frame.Size;
            ContentSize = new CGSize(pageSize.Width * Pages.Length, pageSize.Height);

            backView = new UIView()
            {
               //set the backView's size same as scrollview's contentSize
                Frame = new CGRect(15,40,pageSize.Width * capturedResults.Count, pageSize.Height),                
                BackgroundColor = UIColor.Blue,
                ClipsToBounds = true
            };

            Add(backView);

            for (int page = 0; page < capturedResults.Count; page++)
            {       

                var imageView = new UIImageView()
                {

                    Frame = new CGRect( pageSize.Width * page, 0,pageSize.Width - 30, pageSize.Height),                    
                    Image = UIImage.FromBundle(capturedResults[page].ResultImagePath),
                    BackgroundColor = UIColor.Blue,
                    ClipsToBounds = true
                };

                backView.AddSubview(imageView);
                Pages[page] = imageView;

            }
        }

3.Set backView 到方法 ViewForZoomingInScrollView 的 return 值

  public class CaptureResultScrollViewDelegate : UIScrollViewDelegate
    {
        public CaptureResultScrollViewDelegate(IHandlePaging pageHandler)
        {
            this.pageHandler = pageHandler ?? throw new ArgumentNullException(nameof(pageHandler));
        }

        private readonly IHandlePaging pageHandler;

        public override UIView ViewForZoomingInScrollView(UIScrollView scrollView)
        {
            var pageIndex = (int)Math.Round(scrollView.ContentOffset.X / scrollView.Frame.Size.Width);
            return pageHandler.backView;

        }
    }

4.At最后,调用CaptureResultScrollView

Setup方法
public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            IList<CapturedResultModel> CapturedResults = new List< CapturedResultModel >{ new CapturedResultModel { ResultImagePath = "Images1" },
                                                                                          new CapturedResultModel { ResultImagePath = "Images2"},
                                                                                          new CapturedResultModel { ResultImagePath = "Images1" }
                                                                                          };

            CaptureResultScrollView CapturedResultScrollView = new CaptureResultScrollView();
            CapturedResultScrollView.Frame = new CGRect(15, 40, View.Frame.Size.Width - 30, View.Frame.Size.Height-80);
            CapturedResultScrollView.Setup(CapturedResults);
            Add(CapturedResultScrollView);
        }