简体   繁体   中英

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

I have a paged UIScrollView that's populated with a collection of UIImageViews. The scroll view shows a preview of the previous and next page.

My goal is to make each page of the scroll view zoomable. Here's a gif of the problem I'm experiencing, where the other pages appear to change their coordinates as the image is zoomed:

在此处输入图片说明

I believe the zoom itself is causing the ContentSize of the scroll view to change drastically, which throws everything else out of sorts.

StoryBoard Hierarchy

[Controller]

---- [UIView]

-------- [UIScrollView], Custom Class CapturedResultScrollView

My UIScrollView has the following constraints to its parent UIView:

在此处输入图片说明

Code

Here's the CapturedResultScrollView implementation, as well as the delegate:

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

The Setup method of CaptureResultScrollView is called when the containing controller's ViewWillAppear event is triggered as follows:

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

    CapturedResultScrollView.Setup(CapturedResults);
}

What am I doing wrong here?

Cause:

I think your problem is that you set your imageView for the method ViewForZoomingInScrollView , when you zoom the imageview you selected, only that imageView will zoom and the other imageViews will keep their positions in their superView(here is ScrollerView ),so the other pages appear to change their coordinates as the image is zoomed.

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

Solution:

My advice is that you can add a view who has the same frame with the ScrollView as your imageView's superview. And set this view to the method ViewForZoomingInScrollView 's return value instead of the imageView,so when you zoom this view, imageViews will zoom correctly.

Here is my code:

1.Add a backView in you IHandlePaging interface

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

        UIView backView { get; set; }

    }

2.Add this backView to the ScrovllView and Add the ImageViews to this 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 the backView to the method ViewForZoomingInScrollView 's return Value

  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 last, call the Setup method of CaptureResultScrollView

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM