Im getting this very odd behaviour with my scroll view. Its a paging scroll view set up in iOS 8 using auto layout. The screen so far is very simple, just some labels and a scroll view. There are three pages.
The set up is a 'container view' in which a scroll view sits. The scroll view contains a content view which gets it size from the container and its width is 3 times the size of the container view, giving a scroll view with 3 pages of content the size of the container view.
Bounce is off, paging is on.
The scrolling doesn't seem "choppy" - I've experienced this with UITableView before and I know what scrolling looks like when the phone is struggling to produce a good frame rate, I don't think its like that.
Its almost like the whole scroll view is stuck in treacle. Or as if someone added some UIDynamics or some kind of spring behaviour to the scroll view at the ends of the scrolling as its about to page its unusually slow, no matter the intensity of 'flick' to scroll.
Ive attached a video to show you what I mean. Ive reproduced this on all devices on the simulator and on the iP6+/iP5s devices.
Video: http://tinypic.com/player.php?v=v5jy4p%3E&s=8#.VJljyr0CkA
Is that scrolling abnormal? What do you think the problem is?
The problem was that I was using a Freeform UIViewController of 1800 x 600 - so I could layout my content in interface builder (3 pages). Reverting back to 600 x 600 restores the normal scrolling. I don't know why this should happen since the whole point of autolayout is to not be affected to these changes in size and my view controller is totally adaptive...but there we are.
This is the approach I'm using: UIScrollView Paging Autolayout & Storyboard - its very useful, but be aware to restore your view controllers to a reasonable size before you compile otherwise you get odd scrolling!
Related
I have a problem with the screen presented modally.
At some point of scroll offset, whenever I change the screen size, the scroll offset flickers with some cells being re-layout, but the delegate is not asked for the new cells at this time.
I hope that the below GIF illustrates it's quite good.
I guess it's due to a change in the collection view height, which Geoff Hackworth showed here.
I'll be glad for any suggestions.
Probably it is worth noticing that I use Compositional Layout and DiffableDataSource.
EDIT:
I've decided to check how the code sample from Implementing Modern Collection Views will work, when the screen will be presented modally. The result is the same.
It seems that this is a bug in UIKit. When the NSCollectionLayoutSize height is estimated, not absolute it forces the layout to calculate the view size, probably based on preferredLayoutAttributesFitting(layoutAttributes:). On change of the view container height, the view is asked to be layout again. At the beginning of the layout loop, UICollectionViewCompositionalLayout returns estimated, not the actual size of the views, which causes reusable views (both supplementary and cells) to jump across the screen. The overall result looks really weird.
Here it is:
I met this weird problem when I had an UIScrollView with pagingEnable = YES and a very large contentSize (let's say over 20000000).
Basically I want to write a PDF viewer just like the iBooks (showing one page in the screen). So the bounds of the UIScrollView is just the size of the screen, but the contentSize will be "the page number of the PDF" * "page width". This worked for small PDF, but with large PDF, the paging function seems broken.
For example, I had a 94MB PDF with over 20000 pages, the width of contentSize will be over 20000000. For the first 3000 pages (approximately), the paging works fine: the scrollview always bounces the page to the center of screen. But after 3000 pages, you will find that the bouncing becomes slow, not that smooth. And start from some page, the bouncing totally broken: the page will not show in the center, but stuck at somewhere else, just like pagingEnable = NO. It doesn't bounce anymore.
At first I thought it was something wrong with my code, but I suprisingly find that the iBooks has the same problem! I can't even trigger the toolbar with a single tap after scrolling the last page. So I'm wondering is this an iOS bug?
More Info: When debugging, I found that after the finger touched up, -scrollViewDidScroll: gets called for many times, which is normal, because the UIScrollView starts bouncing when pagingEnable = YES. But the problem is that the -scrollViewDidEndDecelerating: never gets called. Seems like the bouncing animation is broken at some middle point. Weird.
the PDF is only 94MB
File size does not equal the size in memory. PDFs are compressed, but they have to be uncompressed for display.
What's also important is that you don't need a scroll view that's as wide as the entire book - you only need a scroll view that's three pages wide. This is because a) you're hopefully already recycling your page views, and b) because only one page is visible on the screen at any one time you can move the content around as and when you need to.
Is there any reason you are not using a UIPageViewController, which is designed pretty much for this purpose?
Bottom line: there's no reason for your scroll view to be that wide. It only need to be a few pages wide, and you can move the views around to give the illusion the scroll view is much bigger than it actually is. If you search StackOverflow you'll almost certainly find a number of answers that do basically this.
I've added a UIPageViewController to my app to act as a manual for the app. When the user pops it up it shows one page in portrait and two in landscape with the spine in the middle. Since I have about 100 pages, there is a sibling view UICollectionView page selector view above it to allow jumping to a page quickly. Both the UIPageViewController and the UICollectionView sit on a backing view that contains them both.
The problem I am having with the UIPageViewController is that when the views are first rotated they seem to constrain themselves to the short dimension of the original layout. So, if it first appears in portrait, then when rotating to landscape the width of the two pages is the same as the old portrait width. Likewise, if it first appears landscape with two pages, rotating to portrait has the correct width, but the height is the height of the initial landscape height. This is consistent on any device.
When I create my content views they are all the size I desire, but for some reason they seem to be transformed by some component of UIPageViewController and I'm not grasping why it is only doing one of the two dimensions and why it is always the "short side" that is the problem.
This is one of those kinds of problem that makes me feel a bit nutty, any ideas on how I might debug it if it isn't some trivial misconfiguration?
I finally found it after a long period of debugging. The critical hint was seeing that the spine is set to the correct mid for the width of the view BEFORE the rotation for portrait to landscape. The solution was to reset the frame of the view to the new size given the orientation in willAnimateRotationToInterfaceOrientation.
I calculate the new size before I call an animation block that uses the duration passed into the method, then inside the block I have:
pageViewController.view.frame = newFrame;
When the page is rotated the view holding the content pages is shifted to the correct size and the spine is place correctly and the content fills the given area. I suppose that I ran into the problem because the complexity of the views required me to take over so many defaults, but this one was left hanging.
This question already has answers here:
UICollectionView: paging like Safari tabs or App Store search
(6 answers)
Closed 9 years ago.
I'm trying to implement same feature like mobile Safari has when scrolling among different pages using UICollectionView. One page is in the middle and parts of other are also visible.
I am struggling to achieve such a behaviour using UICollectionView. There is 1 way I found how to put 3 pages at one screen - make pages smaller and set appropriate insets. But as soon as I set pages smaller and I set paging enabled, pages are not scrolled to the centre as they should. I can also leave paging disabled and use this method in subclass of UICollectionViewFlowLayout:
- (CGRect)rectForTargetPageForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
In this method I can set exactly where UICollectionView will stop. However, scrolling experience is not as good as it was as using UIScrollview with paging enabled. When I swiped with bigger velocity, several pages were scrolled and it stopped on proposed page. What I want to achieve is same behaviour as normal scroll view with paging enabled - whatever velocity I use, I will get only 1 page more.
Do anyone have any idea how to solve this using UICollectionView?
So you want to make size of a page smaller than the size scroll view, right? Page size is always the same as the size of scroll view, so you have to make the scroll view smaller.
Then there is another problem. How to receive touches out of the bounds of the scroll view?
Override -[UIView pointInside:withEvent:] of the scroll view to check for larger bounds than they really are. Then the touches should work.
In fact I didn't try this myself, I was doing it by placing supplementary view above with desired bounds and override -[UIView hitTest:withEvent:]. Inside I modified the point and called scroll view hit test. This way the touches were handled by scroll view, but their position was wrong. You may want to try combining these two approaches to get correct position.
I've got a scrollview that allows the user to scroll between different pages and then tap on one to have it expand so that they can read the page in full, a little like how one changes tabs in Safari on the iPhone. Changing the frame size of each sub view is a bit of a pain when rotating as the scroll position is getting lost as the content size of the sub view has to change too. I was wondering if there was a more effective way of
resizing the views for entering 'viewing' mode or rotating the device.
The solution to your first problem is when you want to expand the view, pull it out of the scrollView then add it to self.view.subviews with an appropriate frame, then animate the frame to fill the screen. When done with it do the reverse, shrink it, then when its back to the appropriate size stick it back in the scrollView.
If for some reason this does not work - the scrollview is showing other stuff that gets moved when you remove the view, then instead of just removing your view from it, create a simple UIView of the same size as the view you will expand, and essentially replace the view you pull out with the "placeholder" view.