I want to create a scroll view with a massive contentSize that will display content inside it. The content will be mostly text (a few small images will be drawn for content-boundaries).
So, think like a tiled map application, but tiling labels instead of tiled images.
Performance is critical in this application, so I think I should avoid using UILabels or any UIViews at all inside the scroll view.
How can I draw these labels as the user scrolls around? Some options I've considered:
override drawRect: in the scroll view and draw everything within the window - this seems like it would be really slow. Sometimes drawRect is called with only a 1 pixel difference.
Same, but keep track of which ones I've already drawn
Draw them from the "outside" somehow, like from the scroll view delegate - I can't figure out how to use [#"mystring" drawInRect:] outside of drawRect: (context problems)
Is there something I haven't thought of? I know the scroll views were designed to be able to handle this kind of problem, but I'm not sure what the designed way is. Thanks!
The standard way to achieve this in an iPhone application is to create a normal UIScrollView that is the size you want it to be, and to populate it either directly with a CATiledLayer if you're feeling brave or with a custom UIView subclass that uses a CATiledLayer and implements - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context.
CATiledLayer provides the same experience as Safari — it's good for views that are much larger than the screen and which are expensive to render, but which you don't want to ruin the fluidity of the user experience. It'll request tiles as and when it needs them on a background thread, then fade them in (according to a fade of any length, so you can cause them to appear instantly if you desire) when they're ready. If your program really can always keep up with the scrolling and you've requested an instant appearance then there'll be no evidence that there's an asynchronous step involved.
An example people tend to point to is this one, but if you're new to implementing your own UIView subclasses then it might be worth seeing e.g. this tutorial. Then look into the + layerClass property on UIView and the various properties of CATiledLayer (which I think you'll also possibly need to subclass since + fadeDuration is a class method).
Related
I want to implement a grid view like the one in Pinterest
I thought about implementing as 3 table views. But I was not able to scroll them together well. When I implemented the scrollViewDidScroll and set the contentOffset for the table views other the scrollView , the scrolling became slow and unusable.
Another implementation I did was of was having a set of images to load and calling the viewDraw function in scrollViewDidScroll. The ViewDraw function just draws the necessary images and removes the rest of the images from the memory which were already drawn but wont be visible .
this too makes the ScrollView scrolling slow. And another issue with it is that there are white(background color) patches before the images are drawn.
What should be the best way to implement this grid view ?
Solution 1 (i don't know if this works and I don't like it very much)
How about having 3 vertical table views side by side, but forward any touch events from any tableview to the other ones. I understand that you had performance problems when trying to sync the tableviews, but maybe working on an event level things would work better. Maybe.
Solution 2
Use a UIScrollView (for the scrolling purposes of course). For performance and memory reasons you also need to implement a load-on-demand mechanism so that you don't load all your images at once.
To do this I would create a class, CustomImageStrip that handles a vertical image list. This class works together with the scrollview and uses contentOffset to decide when it is time to load/unload a image from the strip.
By having 3 independent image strip classes, the images can be of any size and don't need to be aligned. But, since they all belong to the same UIScrollView the scrolling will be done simultaneously.
I've understood that I need to subclass a UIView t be able to draw inside it.
The thing I don't understand yet, is the philosophy of the way i must be done...
Let's say I have a view controller, and depending on context, I may want to draw a line into one of the subviews it manages, or a circle, or a rect, or a processed graphic. Or lets say two points that are moving inside a view into a defined rect and that display a bigger point when they are close.
How may I subclass and define the subview to make it able to do this only into its drawRect method ?
How does the controller, that manages more than this simple UIView (let's imagine you have a view controller that manages a view inside which there are many other view, and you want to make some drawings in two of them), and that knows what is needed to be drawn into the correct view (it's a controller, isn't it ?), may interact with the views ? And when the drawing is done, how may the views interact with the controller ?
I've read many doc about drawings (apple, web, forums, tutorials, ...), but I still can't touch the philosophy of the way this must be done.
it's very simple. Make a new class, OliverView, which is a UIView. (ie, it is a subclass of UIView.) In that view, make it draw stuff in a fancy way, inside drawRect.
Now make a UIViewController, called OliverVC. In storyboard put an OliverView inside OliverVC. (beginner explanation of how to do that).
In the OliverView, have properties "hours", "minutes", "seconds".
Now, in OliverView - in the drawRect - have a fancy way to display those values. (Pie chart, glowing letters, animation - whatever you want.)
Now, up in OliverVC, do some calculations to determine the time in Zimbabwe, for example.
Once you want a time displayed, simply set those properties in OliverView - - and you are done.
Your colleague could be programming the OliverView. You need know nothing about how she is going to display the time. Conversely, your colleague need know nothing about your calculations in OliverVC..
So, it's simpleL One part has the job of displaying the data. One part has the job of coming up with the data (doing whatever sort of calculation is relevant in the app).
It's the only architecture possible in a "real time" screen device where the views can and do change at any time.
In answer to your question below: you've forgotten that quite simply, if you have a button that would be a whole separate element. (Perhaps sitting "on top of" the OliverView.) So, it's easy!
The -drawRect method in your UIView subclass defines the onscreen appearance of the view. All drawing is done in -drawRect. Your UIViewController calls methods on its UIView to tell it to draw something differently or to perform some other action.
The UIViewController manages everything to do with the view that is not inherently associated with the drawing of the content. Data associated with the view is often stored in the controller.
I am new to iPhone development. I am parsing a xml and display the title, date, contents and image in the cell. Now the scrolling is not smooth, it is stuck.
How can I increase it? I have already applied lazy loading in another view, I am not able to apply in the new view. So how can I increase the scrolling performance? Can I check for any condition that if image is already loaded in the image view, so I can stop once again the loading of image view?
What I do to guarantee fast scrolling in a table is to subclass my own UITableViewCell where I implement all properties that I need.
Whenever that tablecell is initialized I draw the properties of the cell on the cell itself. So when you need an image on there, dont use an UIImageView, but just draw the image on the cell. Also all the text I need I just draw on there.
After a long stuggle finding out how to do all this, I also found a nice blog post about this.
http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/
First of all, check if you're not resizing the images - that takes a lot of computing power, and will slow down the table for sure.
Second of all, check for view hierarchy - complicated view hierarchy means bad performance. Rembemer to use as much opaque views as possible, and when you're using non-opaque views don't make the cells too complex(by complex Apple means three or more custom views). If the views are too complex - use drawRect method for custom drawing of the content.
There's a great example on how to achieve this provided by Apple called AdvancedTableViewCell (here's a link), and there's a great tutorial by Apple about table view cells (another link).
I have a problem, I can't solve properly.
In short: I want to create a single view (say: UIImageView) out of multiple subviews - i.e. it consists out of multiple ImageViews and TextViews. The thing is, I want to sort of 'render' them to be a single View.
Say, I take an image, add some description below, add a title above, and maybe another little image at the bottom. I want this whole thing to be a single UIImage to make it sort of 'listen' to one (e.g.) swiping gesture, which I cant tell to bring the new image to display.
Does anyone know the best way to achieve this? So far my results were fairly poor.
Any hints are welcome!
This is definitely possible. You seem to know about views and subviews, but should also read up on the "UIResponder" class and the "responder chain". The master view that you want to contain them all won't be a UIImageView, though, because that exists to just show an image. You can make all the ones you talk about subviews (addSubview: or in Interface Builder) of a plain UIView that you subclass yourself (say, MyContainerView), which then itself handles the gestures. If you want to take advantage of free scrolling on swipe, you could instead put your container view into a UIScrollView, which has its own set of semantics that you can leverage. For this latter, you should check out Apple's sample code for scroll views (don't have a link handy but should be easy to find) which embeds multiple image views in a scroll view.
I imagine this is pretty dead-simple, but somehow I haven’t been able to get it to work:
I need to display a View containing a group of controls (roughly 800px tall) -- which can be scrolled vertically by the user, as that view is too big to fit on the screen all at once.
That’s it.
I’d think that this might mean something like this:
UIView [normal size] > UIScrollView >
UIView [the oversized one]
... and then enabling vertical scrolling, etc.
But somehow I'm missing something, as the best I've gotten is the first screenful to appear on-screen, without the ability to scroll down.
~~~
[Note: I know that this might often be done using a Table view, and vertical scrolling then happens for ‘free’. But this is a series of special-purpose controls (an odd assortment of various UISliders, UISwitches, UILabels, UIButtons, etc.) that wouldn’t readily fit into a standard table view without a bunch of customizing anyway. They’re also static as well (i.e., don’t need to be changed programatically) -- hence they can be completely built in IB, and that’s how I’d much prefer to do it for this situation anyway. I just need to allow the whole lot to be accessible via scrolling.
I also know that they could be split up into multiple screens, and I'll do this if absolutely necessary; but they're a unified logical group, and so that's not the optimal choice in this instance.]
Any suggestions? That (and/or a code fragment) would be VERY much appreciated.
Many thanks in advance!
My initial thought is... have you tried:
[scrollView setContentSize:CGSizeMake( scrollWidth, scrollHeight)];
My secondary thought is the UIScrollView may not be receiving the scroll commands as you are really scrolling on a UIView, and not the UIScrollView directly... You might need to do some subClassing to get this operational, but I'm afraid that's a bit beyond me as I am still a beginner. :)
My tertiary thought is - why are you adding a UIView to the UIScrollView rather than adding the controls directly to the UIScrollView?