I have a paging scrollview much like Apple's Page Control example project which I have adapted into a horizontal picker. I would really like the ability to scroll through many pages per flick gesture instead of one-at-a-time, much like how UIPickerViews work. Looking for some guidance on how to approach this. Thanks!
First here best Source Code
It could be that whatever is setting those numbers in there, is not greatly impressed by you setting the contentOffset under its hands. So it just goes on setting what it thinks should be the contentOffset for the next instant - without verifying if the contentOffset has changed in the meantime.
I would subclass UIScrollView and put the magic in the setContentOffset method. In my experience all content-offset changing passes through that method, even the content-offset changing induced by the internal scrolling. Just do [super setContentOffset:..] at some point to pass the message on to the real UIScrollView.
Maybe if you put your shifting action in there it will work better. You could at least detect the 3000-off setting of contentOffset, and fix it before passing the message on. If you would also override the contentOffset method, you could try and see if you can make a virtual infinite content size, and reduce that to real proportions "under the hood".
This is also helpful for you..!!!
Related
Can I know in advance where the Scrollview will stop before scrolling stop? I have consulted relevant online materials, but it seems that there is no relevant topic. I am making a magic app to know where it will scroll before Scrollview stops, so that I can modify the value there in advance
My attempt: mark when it starts to slow down and stop, but the sliding distance between them is uncertain, so I haven't finished my idea yet
There is a scroll view delegate method.
https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619385-scrollviewwillenddragging
This will tell you the intended target offset when the deceleration finishes.
It is intended to be used to change the target offset. For instance if you want to make sure it aligns with the content you have tween it finishes.
But you don’t have to change it. You can just return the target offset but use that to change the content like you mentioned.
I've implemented the SWTableViewCell code in order to allow side swipes to reveal more UI, such as buttons.
Which is working fine, except that the UIScrollview it subclasses is really just too touchy, flicking back and forth like a manic game of ping pong.
I went to make changes to the class, but realised UIScrollView didn't seem to give me the ability to say change the way the scrolling animations work in the way I wanted.
Leaving me thinking that I either need to create my own version of the a Swipe cell, with a pan gesture and a overlay view, instead of a scrollview or find someone who has already solved this problem.
Please check it out sample: https://github.com/runmad/RMSwipeTableViewCell
May be it will helpful to you, Sir
:)
Not sure if this will give you the effect you desire, but you can make it less "jumpy" by altering the decelerationRate. Try:
someScrollView.decelerationRate = UIScrollViewDecelerationRateFast;
If that's the right idea, you can jump-to-definition in Xcode, and checkout the float value, then try your own.
I'm using CPPickerView in my app to accomplish a horizontal UIPickerView, and it works great, but with large data sources (dozens of items) it scrolls very slowly which makes navigation before (especially considering a normal UIPickerView can go very fast through them).
I don't mean performance-wise, by the way, I mean the view decelerates very quickly, making traversal difficult.
It's just a subclass of UIScrollView with pagingEnabled set to YES. What can I do?
I looked in the source, and it seems CPPickerView is using a scroll view. Scroll views have a decelerationRate property. Play with that and see which value makes for the best result.
Don't fill CPPickerView with all data.
For example fill with first 20 items and if it reaches to the end add another 20.
Creator of CPPickerView here - I've recently updated CPPickerView to add an allowSlowDeceleration property, which should do what you're looking for. Check out the latest code on Github, or Cocoapods version 1.2.0.
For the purposes of documentation, here's how the solution works. Like you mentioned CPPickerView just a scrollview with pagingEnabled set to YES, so the solution I found was to disable paging when the user scrolls with enough velocity.
UIScrollViewDelegate has an optional method scrollViewWillEndDragging:withVelocity:targetContentOffset:, which is called when the user's finger is lifted after swiping/scrolling on the scrollview, and it's still called even when paging is enabled. Based on that value you can tell if the user was trying to scroll quickly through items, or just move one or two items.
I played around with the CPPickerViews in the Demo project, and found that a velocity of about 2.9f seems to be about the normal "fast swipe" threshold. So if the velocity is greater than this threshold (which I defined as kCPPickerDecelerationThreshold in CPPickerView.m) and allowSlowDeceleration is set to YES, CPPickerView now sets pagingEnabled to NO before the deceleration starts. This allows the picker to "coast" and decelerate like a normal scrollview.
It then catches the end of the deceleration, OR the user touching to stop the scroll, by the call to the scrollViewDidEndDecelerating: delegate method. The current item is determined (based on the offset of the scrollview), and then if the scrollview's pagingEnabled property is set to NO a call to the private method scrollToIndex:animated: is made with animation set to YES. This scrolls the CPPickerView to the current item, which necessary as it's unlikely the coasting scroll ended right on a page boundary.
Finally, when the animated scroll completes, the scrollViewDidEndScrollingAnimation: delegate method is called, at which point pagingEnabled is set back to YES.
If you find that you're having trouble getting it to recognize a "fast" swipe, try playing with the kCPPickerDecelerationThreshold value. In hindsight that maybe should be a customizable property, so perhaps I'll roll that into the next update.
As mentioned above you can use the decelerationRate property, setting it to UIScrollViewDecelerationRateNormal might help.
scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
If that still doesn't solve your problem you could also buffer your inputs into the scroll. See this:
Advanced scrollview techniques
OK so in my game I need the users to scroll between items, just like you scroll a web page in Safari. Is there any way to do that? If not, maybe scrolling them to the side, like you do in the spriboard? Thanks.
I am not really sure I have understood what you would like to do, but there is a cocos2d extension that seems appropriate to it: CCScrollLayer.
CCLayer subclass that lets you pass-in an array of layers and it will then create a smooth scroller. Complete with the “snapping” effect.
If you are looking for a generic scrolling within your view, I suggest this tutorial or this topic rom cocos2d list.
EDIT:
I have never done it, but I think it should be possible to scale the CCScrollLayer to the size you need.
Otherwise, you might change the contentSize of the layer, or even put the CCScrollLayer into a clipping node.
Anyway, I think that it is much easier to start from this and find a way to adapt it to your specific requirements than start from scratch.
OK, I think it's time to make an official place on the internet for this problem: How to make a UIScrollView photoviewer with paging and zooming. Welcome my fellow UIScrollView hackers.
I have a UIScrollView with paging enabled, and I'm displaying UIImageViews like the built-in photos app. (Does this sound familiar yet?)
I found the following project on github:
https://github.com/andreyvit/ScrollingMadness/wiki
Which shows how to implement zooming in a scroll view while paging is enabled. If anyone else tries this out, I actually had to remove the UIScrollView subclass and use the native class otherwise it doesn't work. I think it's because of changes in the 3.0 SDK relating to how the scroll view intercepts touch events.
So the the idea is to remove all the other views when you start zooming, and move the current view to (0, 0) in the scrollview, updating the contentsize etc. Then when you zoom back to 1.0f it adds the other views back and puts things all back in order.
Anyway, that project works perfectly in the simulator, but on the device there is some nasty movement of the view you are resizing, which looks like it's caused by the fact we are changing the contentsize/offset etc. for the view being resized. You have to do this view moving otherwise you can pan left through the whitespace left by the other views.
I found one interesting note in the "Known Issues" of the 3.0 SDK release notes:
UIScrollView: After zooming, content inset is ignored and content is left in the wrong position.
This kind of sounds like what is happening here. After zooming in, the view will shift offscreen because you have changed the offset etc.
I've spent hours on this already and I'm slowing coming to the sad realization that this just isn't going to work.
Three20's photo viewer is out of the question: it's too heavy weight and there is too much unnecessary UI and other behaviour.
The built in Photo app seems to do some magic. If you zoom in on an image and pan to the far edges, the current photo moves independently of the photo next to it which isn't what you get when trying this with a standard UIScrollView.
I've seen discussion about nesting the UIScrollView's but I really don't want to go there.
Has anybody managed this with the standard UIScrollView (and works in the 2.2 and 3.0 SDK)? I don't fancy rolling my own zoom + bounce + pan + paging code.
UPDATE
I deleted my previous answer because of the news below...
Big news for those who haven't heard. Apple has released the 2010 WWDC session videos to all members of the iphone developer program. One of the topics discussed is how they created the photos app!!! They build a very similar app step by step and have made all the code available for free.
It does not use private api either. Here is a link to the sample code download. You will probably need to login to gain access.
Check This
And, here is a link to the iTunes WWDC page:
Check This
I've written a simple and easy to use photo browser called MWPhotoBrowser. I decided to create it as Three20 was too heavy/bloated as all I needed was a photo viewer.
MWPhotoBrowser can display one or more images by providing either UIImage objects, or URLs to files, web images or library assets. The photo browser handles the downloading and caching of photos from the web seamlessly. Photos can be zoomed and panned, and optional (customisable) captions can be displayed. The browser can also be used to allow the user to select one or more photos using either the grid or main image view.
You say you've seen discussions of nesting UIScrollViews but don't want to go there - but that is the way to go! It works easily and well.
It's essentially what Apple does in its PhotoScroller example (and the 2010 WWDC talk linked to in Jonah's answer). Only in those examples, they've added a whole bunch of complex tiling and other memory management. If you don't need the tiling etc. and if you dont want to wade through those examples and try and remove the bits related to it, the underlying principle of nesting UIScrollViews is actually quite simple:
Create an outer UIScrollView and set its pagingEnabled = true. Add it to your main view and set its width and height to your main view's width and height.
Create as many inner UIScrollViews as you want images. Set their width and height to your main view's width and height. Add them as subviews to your outer UIScrollView, each one next to the other, left to right.
Set the content size of the outer UIScrollView to the total of the widths of all the inner UIScrollViews side by side (which is equal to [your main view's width]*[number of images]).
Add your images' UIImageViews to the inner UIScrollViews, one UIImageView to each inner UIScrollView. Set each UIScrollView's content size to each UIImageView's size.
Set min and max zoom scales for each inner UIScrollView and set each of the inner UIScrollView's delegate to your View Controller. In the delegate's viewForZoomingInScrollView, return the appropriate UIImageView for the UIScrollView that is passed. (To do this, just keep each of the UIImageViews in an NSArray and set the corresponding UIScrollView's tag property to the index of the appropriate UIImageView. You can then read the tag in the UIScrollView passed to viewForZoomingInScrollView and return the appropriate UIImageView from the NSArray).
That's it. Works just like the photo app.
If you have a lot of photos, to save memory you can just have two inner UIScrollViews and two UIImagesViews. You then dynamically flip between them, moving their position within the outer UIScrollView and changing their images as the user scrolls the outer UIScrollView. It's a bit more complex but the same principle.
I did some playing around with the native Photos app, and I think I can say with confidence they are using a single UIScrollView. The giveaway is this: zoom in on an image, and pull to the left or right. You will see the next or previous photo. If you tug hard enough, it will even page to the next photo at 1.0f zoom. Flip back and the previously zoomed photo will be back to 1.0f zoom as well.
Obivously I didn't write Photos.app, but I'll take a wild guess at how they did it:
A single UIScrollView and a single UIScrollViewDelegate
Populate the UIScrollView with UIImageView children
Listen for scrollViewDidScroll:
Do some math and figure out what page you are currently on
Listen for viewForZoomingInScrollView:
Return a different view depending on the page index
Listen for scrollViewDidEndZooming:withView:atScale: and optionally do some anti-aliasing, etc based on the content
If you decide to try that out, let me know how it works out for you. I'd love to know how you finally end up getting this to work. Even better, post it to github.
I did some playing around with the
native Photos app, and I think I can
say with confidence they are using a
single UIScrollView. The giveaway is
this: zoom in on an image, and pull to
the left or right. You will see the
next or previous photo. If you tug
hard enough, it will even page to the
next photo at 1.0f zoom. Flip back and
the previously zoomed photo will be
back to 1.0f zoom as well.
This is wrong. I'm using nested scrollviews, and getting exactly the same effect. If you're using some memory management scheme (which I had to start using... my page number is fairly high ('bout 50 each in 2 scrollViews)), then you can use a mechanism similar to whatever you have triggering your page loads / unloads to trigger a zoom reset for the pages -1 and +1 from the current page.
I suspect that apple sets this off as soon as the previous pic has disappeared.
What I don't understand is how to achieve smooth scrolling between pages - there's always a very short hang at the moment of transition. Do not get it. I've gotten pretty deep into fixing it - NSInvocationOperations were my first stop, then I made a reusable views queue for the page views (which retain their image views)... still this durned hang.
I only have one NSOperationQueue running, and I've tried fiddling with the max number of concurrent operations. My thought was that the main thread was getting clogged by competing Queues, or maybe even one queue trying to do to much... still, the hang.
I even tried creating super low-qual versions of my media, in case that was the problem. With each image weighing in at around 10k (these are jpegs, mind you)... you guessed it. The hang's still there.
I'm pretty much resolved to do what I've done before and use TTPhotoViewController from Three20. I've spent some hours swimming through that code, and it's always a great education. At this point, though, I would really like to know where the heck this hang comes from, if only so I can spend my can't-sleep hours wondering about something less brain boiling.
sure would be nice if apple built an image viewer like the photos app into the SDK for us to use. I'm currently using three20 and it works great. But it is a lot of extra stuff to carry around when all you really want is the photo viewer.
i write a code for that , and can be as reference
load current view scrollview and imageview ..
and for the screen next to the current view , only imageview
remove all view when current page load to save memory , so good for many photo project
use tag to differentiate different scrollview
_xxxxxxx
the download link click here
Take a look at https://github.com/facebook/three20/blob/master/src/Three20UI/Headers/TTPhotoViewController.h Not sure if that's what you are looking for