Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIPageViewController Second View Goes Blank

I'm experiencing some very odd behavior when using UIPageViewController in my app. On the first swipe to the next view or anytime the direction of swiping changes (i.e. at the end of the list and going back), the resulting view is blank and I am required to swipe the same direction again for the appropriate view to show.

Example workflow with 3 views:

  1. First view presented
  2. Swipe to the right
  3. Second view blinks in and out
  4. Swipe to the right
  5. Second view presented
  6. Swipe to the right
  7. Third view presented
  8. Swipe to the left
  9. Second view blinks in and out
  10. Swipe to the left
  11. Second view presented

I noticed via logging when the blinking happens (2 & 3 above), the sequence of events is as follows:

  1. GetNextViewController is called
  2. GetPreviousViewController is called
  3. GetNextViewController is called

Then when I swipe again GetNextViewController is appropriately called and the view is shown.

My problem is, obviously, the second view should show without the blinking in and out. I have tried various things but nothing fruitful.

UPDATE

Here is a sample single-controller app that reproduces the problem:

using System;
using System.Drawing;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Collections.Generic;

namespace TestPageView
{
    public partial class TestPageViewViewController : UIViewController
    {
        public TestPageViewViewController () : base ("TestPageViewViewController", null)
        {
        }

        public override void DidReceiveMemoryWarning ()
        {
            // Releases the view if it doesn't have a superview.
            base.DidReceiveMemoryWarning ();

            // Release any cached data, images, etc that aren't in use.
        }

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

            var controllers = new List<UIViewController>
            {
                new TestViewController(View, 1),
                new TestViewController(View, 2),
                new TestViewController(View, 3),
                new TestViewController(View, 4)
            };

            var _pageViewController = new UIPageViewController(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal);
            var dataSource = new ViewDataSource(controllers);
            _pageViewController.DataSource = dataSource;
            //ViewDataSource has an indexer that returns it's controllers
            _pageViewController.SetViewControllers(new[] { controllers[0] }, UIPageViewControllerNavigationDirection.Forward, false, null);
            View.AddSubview(_pageViewController.View);
        }

        public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
        {
            // Return true for supported orientations
            return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
        }
    }

    public class TestViewController : UIViewController
    {
        private readonly UIView _parent;
        private readonly int _number;
        public TestViewController(UIView parent, int number)
        {
            _parent = parent;
            _number = number;
        }

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

            var textView = new UITextView(_parent.Bounds);
            textView.TextAlignment = UITextAlignment.Center;
            textView.AttributedText = new NSAttributedString(_number.ToString(), UIFont.BoldSystemFontOfSize(18));
            View.Add(textView);
        }
    }

    public class ViewDataSource : UIPageViewControllerDataSource
    {
        private LinkedListNode<UIViewController> current;

        public ViewDataSource(IEnumerable<UIViewController> controllers)
        {
            var controllerLiist = new LinkedList<UIViewController>(controllers);
            current = controllerLiist.First;
        }

        public override UIViewController GetPreviousViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
        {
            if(current.Previous == null){
                Console.WriteLine("returning previous nothing");
                return null;
            }
            Console.WriteLine("returning previous something");
            current = current.Previous;
            return current.Value;
        }

        public override UIViewController GetNextViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
        {
            if(current.Next == null){
                Console.WriteLine("returning next nothing");
                return null;
            }
            Console.WriteLine("returning next something");
            current = current.Next;
            return current.Value;
        }
    }
}
like image 250
Benny Avatar asked Apr 15 '13 18:04

Benny


1 Answers

iOS will call GetPreviousViewController and GetNextViewController twice: first for current controller and second for backflip of current controller.

You should do that

current = current.Previous;

only at first call.

Check referenceViewController to do that:

public override UIViewController GetPreviousViewController (UIPageViewController pageViewController, UIViewController referenceViewController)
    {
        var __c = Pages.Find(referenceViewController);

        if (__c.Previous != null)
            return __c.Previous.Value;
        else
            return null;
    }
    public override UIViewController GetNextViewController (UIPageViewController pageViewController, UIViewController referenceViewController)
    {
        var __c = Pages.Find(referenceViewController);

        if (__c.Next != null)
            return __c.Next.Value;
        else
            return null;
    }
like image 79
Northern Poet Avatar answered Oct 30 '22 10:10

Northern Poet