0

I have an issue with an image view I'm adding dynamically to my scrollview. I'm using iOS 8 and Size Classes and Auto Layout. The scrollview has been added via the storyboard and I have also added constraints to match the size of the View.

The challenge is, the dynamically added imageview starts centered, but after an orientation change, it gets displaced within the scrollview.

There are tons of solutions here, and most of them pointed to overriding the ViewWillLayoutSubviews() function and then setting the UIImageView's center to the scrollview's there. None of the suggestions have worked for me. Whenever I rotate the device, the imageview gets displaced.

Some suggestions I've tried

UIScrollView with centered UIImageView, like Photos app

Center UIImageView inside UIScrollView without contentInset?

Here's how I'm adding the UIImageView. This function is called in the ViewDidLoad().

public void AddImageInScrollView(int index)
    {
        try
        {
            //Setting up the imageView

            var imageUrl = Items.fetchImages[index]; 

            //Setting up the imageView
            imageView = new UIImageView(); 
       //call method to load the images
            imageView.SetImage(
                url: new NSUrl(imageUrl.AbsoluteUri),
                placeholder: UIImage.FromFile("sample.png"),
                completedBlock: (image, error, type, url) =>
                {
                    imageResizer = new ImageResizer(image);

                    imageResizer.RatioResize(100,100);

                    UIImage resizedImage = imageResizer.ModifiedImage;
                    //when download completes add it to the list
                    Car.images.Add(resizedImage);

                });
            //end method call

            imageView.UserInteractionEnabled = true;
            imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
            imageView.Center = ScrollViewMain.Center;


            //Adding the imageView to the scrollView as subView
            ScrollViewMain.AddSubview(imageView);

          //ScrollViewMain.ContentSize = imageView.Image.Size;
            ScrollViewMain.ContentSize = new CGSize(ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height);
           catch (Exception ex)
        {

            Console.WriteLine(ex.Message + ex.StackTrace);
        }
    }

The ViewWillLayoutSubviews function

    public override void ViewWillLayoutSubviews ()
    {
        base.ViewWillLayoutSubviews ();

        imageView.Frame = new CGRect(0,0,ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height);

        CenterScrollViewContents ();
    }

The CenterScrollViewContents function

   public void CenterScrollViewContents()
    {
        try
        {

        var boundsSize = ScrollViewMain.Bounds.Size;

        var contentsFrame = imageView.Frame;

        if (contentsFrame.Size.Width < boundsSize.Width) {

            contentsFrame.X = ((float)boundsSize.Width - (float)contentsFrame.Size.Width) / 2.0f;

        } else {
            contentsFrame.X = 0.0f;
        }

        if (contentsFrame.Size.Height < boundsSize.Height) {

            contentsFrame.Y = ((float)boundsSize.Height - (float)contentsFrame.Size.Height) / 2.0f;

        } else {
            contentsFrame.Y = 0.0f;
        }

        imageView.Frame = contentsFrame;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }

A sample screen shot of what it looks like after rotation

Screen shot of displaced image in land scape mode

Community
  • 1
  • 1
naffie
  • 679
  • 1
  • 12
  • 29
  • You are not updating the ContentSize of the ScrollView. I'd assume, that this is the problem. – Sven-Michael Stübe Feb 24 '16 at 08:31
  • I am already doing that in the AddImageToScrollView function which is called in the ViewDidLoad(). //ScrollViewMain.ContentSize = imageView.Image.Size; ScrollViewMain.ContentSize = new CGSize(ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height); – naffie Feb 25 '16 at 10:26
  • Yes but not in the Update `ViewWillLayoutSubviews`. Just try to copy `ScrollViewMain.ContentSize = new CGSize(ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height);` to this function. – Sven-Michael Stübe Feb 25 '16 at 10:48
  • Nothing changes. I added it above the other two lines inside that function. The image is still not centered whenever I rotate the device. – naffie Feb 25 '16 at 11:16
  • Hmm, ok. Have you got a small example project somewhere? – Sven-Michael Stübe Feb 25 '16 at 12:39
  • Here's a link to a sample project : https://drive.google.com/file/d/0Bwof42ToptGsT19TM2JZaVFfWVU/view?usp=sharing – naffie Feb 25 '16 at 19:31
  • To get to this view, click on the drawer then click on Tab A. On the list of of images, when you select a single image, it should load up a similar view. – naffie Feb 25 '16 at 20:06
  • @Sven-MichaelStübe did you manage to look at the sample project? – naffie Mar 02 '16 at 12:32
  • I wanted to but then I saw, that you already resolved the issue, so I went on with other stuff :) – Sven-Michael Stübe Mar 02 '16 at 12:39
  • I realize now that my solution was a temporary fix. Even with that slight modification, it still gets displaced. This bug is very annoying. Could you kindly look at it, if you don't mind? A second set of eyes might help. – naffie Mar 02 '16 at 12:42
  • Ok in a few hours :) – Sven-Michael Stübe Mar 02 '16 at 13:24
  • Thank you. I appreciate it :-) – naffie Mar 02 '16 at 13:32
  • Unfortunately, I can't really build it. Do you have a minimal example with just one viewcontroller and without all this binding stuff? – Sven-Michael Stübe Mar 02 '16 at 18:06
  • Give me a minute. Adding a link right now. – naffie Mar 02 '16 at 21:01
  • Okay, here's a link to a single view app : https://drive.google.com/file/d/0Bwof42ToptGsMkhHWExXWk4zeHc/view?usp=sharing – naffie Mar 02 '16 at 21:30

2 Answers2

1

Move your code from ViewWillLayoutSubviews to ViewDidLayoutSubviews. The difference is that ViewWillLayoutSubviews is "Called to notify the view controller that its view is about to layout its subviews." and ViewDidLayoutSubviews is "Called to notify the view controller that its view has just laid out its subviews."

The problem is, that ScrollViewMain.Frame is

{X=0,Y=0,Width=375,Height=667} in ViewWillLayoutSubviews

but

{X=0,Y=0,Width=667,Height=375} in ViewDidLayoutSubviews

The Function looks like

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();
    ScrollViewMain.ContentSize = new CGSize(ScrollViewMain.Frame.Size.Width, ScrollViewMain.Frame.Size.Height);
    imageView.Frame = new CGRect(0, 0, ScrollViewMain.Frame.Size.Width, ScrollViewMain.Frame.Size.Height);
    CenterScrollViewContents();
}

Bonus Protip:

You can use imageView.Center = ScrollViewMain.Center; to center views.

And if you have some more time, have a look at Autolayout constraints. They save you Frame calculation pains.

Community
  • 1
  • 1
Sven-Michael Stübe
  • 14,560
  • 4
  • 52
  • 103
  • I moved the code from ViewWillLayoutSubviews to ViewDidLayoutSubviews as you suggested, but there's no change. The ViewDidLayoutSubviews is not being called and the image is still not centered. Sometimes even before rotating the device and also gets displaced after rotation. I'm also using AutoLayout constraints for every other screen. This is the only view where I needed dynamic UIImageViews. I'm downloading the images from a server, so I've noticed that only the very first image gets displaced, before and after rotation because the frame size is 600x600. After swiping, the frame is smaller. – naffie Mar 03 '16 at 07:11
  • Your real app or the sample? Have you debgugged it and looked at the frame size? Try `imageView.BackgroundColor = UIColor.Red` to see if the Frame of the image fits. Are you testing on the simulator or the device? I'll have a look if I have changed something else, this afternoon. – Sven-Michael Stübe Mar 03 '16 at 07:19
  • It works!!..It works. I just had to clean the project and build it again. ViewDidLayoutSubviews is now being called. Thanks a lot. You saved my life :-) I've accepted this answer. – naffie Mar 03 '16 at 07:51
0

I managed to solve this using a simple solution. I realized that while initializing the imageView, I didn't pass the frame size into it's constructor. There are multiple ways to do it, but for my case, after a screen rotation,it seems the size was not being updated.

Before:

        imageView = new UIImageView(); 
        imageView.Frame = new CGRect(0,0,ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height);

Solution:

        var frame = new CGRect(0,0,ScrollViewMain.Frame.Size.Width,ScrollViewMain.Frame.Size.Height);
   //Setting up the imageView
        imageView = new UIImageView(frame); 

The image inside the scrollView now is always centered even after orientation changes.

naffie
  • 679
  • 1
  • 12
  • 29