So I wrote a custom subclass of UIScrollView that basically displays rectangles in a 2-column grid, but while the width of each is fixed to half the width of the iPhone/iPad screen, the height varies, depending on the dimensions of the picture within it. All's well and good now, but I can imagine that after adding lots of these subviews to my UIScrollView subclass, things are going to lag. So I'm trying to implement lazy loading analogous to UITableView's dequeueing reusable cell method.
I've looked at a handful of other questions on SO, but they all involve paging based on full-screen photos, including Apple's WWDDC PhotoScroller example.
Anyone have any insight? Thanks.
You basically want to keep track of the views that are scrolled off screen and reuse them.
You might want to check out ATArrayView. It implements a recycling mechanism like what the UITableView has except with a UIScrollView with an arbitrary number of rows and columns?
I've used it as the basis for my own image scrolling code and is pretty good. It's delegate methods follow the spirit of UITableView data source and delegate protocols.
Good luck
Tim
Related
I am displaying hundreds of thumbnails in my view . I know default way to handle tap on thumbnail is using UICollectionView delegate method "didSelectItemAtIndexPath" but since its many thumbnails i wanted to look into adding gestures to the screen position so when i tap on a particular spot on the screen, it will handle the event accordingly for that particular thumbnail underneath. I would like to know if it is a good/possible approach?
It would be a hell of a lot easier to use a UICollectionView.
If you need a custom layout then you can subclass UICollectionViewLayout and get some really cool dynamic layouts.
You also get the added bonus of dequeued cells meaning that you get better memory management using it.
You may find UIGestureRecognizer useful. A good tutorial to get you started is here.
I am creating an app for practice that is a simple drawing app. The user drags his/her finger along the screen and it colors in a 100px x 100px square.
I currently achieve this by creating a new colored UIView where the user taps, and that is working. But, after a little time coloring in, there is substantial lag, which I believe is down to there being too many UIViews as a subview of the main view.
How can I, and others who similarly create UIViews on dragging a finger reduce the lag to none at all, no matter how many UIViews there are. I also think that perhaps this is an impossible task, so how else can someone like me color a cube of the size stated above in the main view on a finger dragged along the screen?
I know that this may seem like a specific question, but I believe that it could help others understand how to reduce lag if there are a very large amount of UIViews where a less performance reducing option is available.
One approach is to draw each square into an image and display that image, rather than keeping around an UIView for each square.
If your drawing is simple enough, though, you can use OpenGL to do this, which is much faster. You should look at Apple's GL Paint Sample Code which shows how to do this in OpenGL.
If your drawing is too complex for OpenGL, you could create, for example, a CGBitmapContext, and draw each square into that context when the user drags their finger. Whenever you draw a new square into that bitmap, you can turn the bitmap into an image (via CGBitmapConxtextCreateImage) and display that image an a UIImageView.
There are two things that come to my mind:
1- Use Instruments tool to check if you are leaking any memory
2- If you are just coloring the views than instead of creating images for each of them, either set the background color property of UIView or override the drawRect method to do custom drawing
I think what you are looking for is the drawRect: method of UIView. You could create your custom UIView (you propably have that already) and override the drawRect method and do your drawing there! You will have to save your drawings in an array or another container and call the setNeedsDisplay method whenever the array content is changed.
I have a problem. I want for each record in my core data database to draw an UIImage view on screen. But the problem is that I want to make a sort of grid. On the link below you see what I want to achieve.
picture
So my question is, how do I draw an image on screen in code. And place those images in a sort of a grid. using a collection view is no option, because the app should be running on all IOS devices.
While you could implement a custom UIView and implement the drawRect: method and draw UIImages there, I suggest just using multiple UIImageViews as subviews on your "main" view. Your view might be embedded in a UIScrollView, or you could use a UITableView with custom UITableViewCells. Whichever is easier is probably related to how you can interact with the view.
Building that one huge image view is something that I'd definitely try to avoid - it costs many many (probably unnecessary) memory, and it might be slow as well. Definitely not very flexible to handle, and a pain to update dynamically.
A quick cheat for something like this is to use a Table View and then in each cell to place another TableView but rotated at 90 degrees.
You can then use this second TableView to display the pictures etc...
This will give you a table that scrolls up and down and then each cell can scroll left to right.
I'd suggest subclassing UITableViewCell and setting it up as a UITableViewDelegate and UITableViewDatasource.
You will also have to remember to rotate the content of these "sub"tables by 90 degrees also so that they are the right way up.
This sounds like a lot of work but if you push the management of the sub Tables into the cells then it actually becomes quite easy.
I'm trying to add a way for my app to display data in an easily comprehensible form. I tried doing this with graphs, but found it to be a bit awkward, so I'm off to find a better solution.
Here's a problem:
I want to show up to 30 days of data, with user reported events plotted against a timeline.
The events should align vertically, to visually provide a reference of when certain events cluster together.
To solve the problem, I thought of using a UITableView with a background which has a scale, and superimpose upon that background a set of "pins", indicating user events. As the table is scrolled, the events would align one under another, providing a good indication historic event development:
I know that this is possible to be done with a UIScrollView, where I can just position a series of rulers and add events as pins. In order to do this efficiently, I'll have to use Tiling, a technique that I don't have much experience with.
I'm interested in knowing if this is possible with a UITableView, where caching and tiling is already done for me.
I tried adding UIImageViews to a tableViewCell.backgroundview , but this does not produce the desired results. I'd like to be able to dynamically add any number of subviews to the table cell. I can do this by adding a certain pre-determined number of images to an .xib and then trying to reposition them, but this does not seem like an ideal solution.
Is what I'm trying to do possible with UITableView, or should I abandon these efforts and look at UIScrollView with tiling?
Thank you!
yes this should be possible. Add the ruler image to the background of the UITableViewCell.
Then create a subclass of UITableViewCell that takes an array of pins objects that it will place within its view. The pin objects would contain the pin image and a horizontal location on the scale. Then in the tableView dataSource method cellForRowAtIndexPath method you set the tableViewCell's pin array to the correct array (or NSSet) of pins.
To make it even more lightweight, you could draw the pins yourself in the UITableViewCell subclasses drawRect method. Then you could just pass the locations of the pins.
Good luck
I'm currently working on an app which needs to draw s.th. like a network graph. Unfortunately this graph can become very big with thousands of movable objects.
I tried to put a giant UIView inside a UIScrollView but soon noticed this won't work because of memory limitations.
So I tried another approach: currently I have a UIView which has exactly the size of the visible part of the UIScrollView. The scrollview is set to not handle the scrolling (only the pinching). Instead I handle the scrolling in the UIView. Everytime a user scrolls, all graphic objects (those graphic objects are currently just subclasses of NSObject, which contain custom drawing code) are moved, so it seems like the view is scrolling. In the drawRect I only draw the graphics that are currently visible.
Also I constantly add and remove sublayers if they are moved out/in the visible frame
This works very smooth even with thousands of objects.
Unfortunately this approach has some drawbacks:
I can't zoom out to see all the objects in the graph, instead the user can only see a part of it
I don't get the inertial scrolling the UIScrollView offers
Other approaches I tried, like the CATiledLayer, don't work either because all the objects in the graph are draggable by the user and it looks really ugly if I use a CATiledLayer...
Swapping out the UIView with other UIViews while the user scrolls may help with the inertial scrolling, but it makes everything more complicated and zooming out completely still won't work :-(
Do you know of any best practices to draw graphs that can be very big?
//edit: I ended up with a uiscrollview which has a subview which has a cascrolllayer which has many sublayers. While zooming in and out the frame of the uiscrollviews subview is constantly changed to the uiscrollviews bounds by view.frame = scrollview.bounds. While dragging the scrollview the cascrolllayer is always forced to scroll to the current offset of the scrollview.
I needed to subclass the uiscrollview and hack around in order to make the zooming work nicely, but it's working well now. This approach works very well and allows very big graphs with lots of draggable elements.
//edit: see my other answer below, the approach above didn't work out as well as I initially thought, especially the zooming part
CATiledLayer is definitely what you should use here—there’s not really another solution that’ll let you use Quartz/UIKit drawing on a huge zoomable canvas. For anything that needs to be interactive (dragged or animated or whatever), you can disable its display in the main tiled layer and overlay another view or layer on top of it that just contains the object being interacted with.