0

I'm about ready to begin to create a Gantt chart like control in iOS for my app. I need to show a timeline of events. Basically a bunch of rectangles, some lines/arcs for some decoration, possibly a touch point or two to edit attributes. It will basically be a "full screen" control on my phone.

I see two basic paths to implement this custom UIView subclass:

  1. Simply implement drawRect: and go to town using CoreGraphics calls. Most likely split over a bunch of private methods that do all the drawing work. Possibly cache some information as needed, to help with any sub region hit detection.

  2. Rather than "draw" the graphics, add a bunch of UIViews as children using addSubview: and manipulating their layer properties to get them to show the different graphic pieces, and bounds\frame to get them positioned appropriately. And then just let "drawing" take care of itself.

Is one path better than the other? I may end up trying both in the long run just to see, but I figured I'd seek the wisdom of those who've gone before first.

My guess is that the quicker solution would be to go the drawRect: route, and the subview approach would require more code, but maybe be more robust (easier hit detection, animation support, automatic clipping management, etc). I do want to be able to implement pinch to zoom and the like, long term.

UPDATE

I went with the UICollectionView approach. Which got me selection and scrolling for free (after some surprises). I've been pretty pleased with the results so far.

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
  • It's been 3 years since you worked on this Gantt Chart component. Any lessons learned you can share with me? I'm in need of a very robust Gantt Chart component with lots of customizations. I'm trying to find out what the best approach is in iOS. I figure at this point I'm going to have to build it myself, kind of like you did back then. Any wisdom? Thanks! – Fernando May 26 '17 at 16:20
  • @Fernando first I did the UICollectionView approach. But as the view progressed, I had so many different "specializations" and UI interaction ideas, that it didn't seem to scale. I've used UICollectionView elsewhere since then... and maybe it would work better now. I also had some interesting scrolling needs. So I ended up with a custom View that manipulated custom row View objects (plus a couple of other full view background views) ( (all using drawRect:). That's worked for a while so far. – Travis Griggs May 26 '17 at 16:52
  • Thank you! Much appreciated. – Fernando May 27 '17 at 23:26

3 Answers3

1

When it comes to performance, a well written drawRect: is preferred, especially when you would potentially have to render many many rects. With views, an entire layout system goes to work, much worse if you have autolayout, where an entire layout system goes to town and kills your performance. I recently upgraded our calendar views from view-based to CG-based for performance reasons.

In all other aspects, working with views is much preferred, of course. Interface Builder, easy gesture recognizer setup, OO, etc. You could still create logical classes for each element and have it draw itself in the current context (best to pass a context reference and draw on that), but still not as straight forward.

On newer devices, view drawing performance is quite high actually. But if you want these iPhone 4 and 4S devices, if you want these iPad 3 devices, which lack quite a lot in GPU performance, I would say, depending on your graphs potential sizes, you might have to go the CG way.

Now, you mention pinch to zoom. This is a bitch no matter what. If you write your drawRect: well, you could eventually work your way to tiling and work with that.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
1

If you plan on letting the user move parts of the chart around I would definitely suggest going with the views.

FYI, you will be able to handle pinch to zoom with drawRect just fine.

What would push me to using UIView's in this case would be to support dragging parts of the chart, animating transitions in the chart, and tapping on elements in the chart (though that wouldn't be too hard with drawRect:). Also, if you have elements in your chart that will need heavy CPU usage to render you will get better performance if you need to redraw sub portions of your chart with UIView's since the rendering of the elements is cached to a layer and you will only need to redraw the pieces you care about and not the entire chart.

If you chart will be VERY big AND you want to use drawRect: you will probably want to look at using CATileLayer for you backing so that you don't have the entire layer in memory. This can add added challenges if you only want to render the requested tiles and not the entire area.

Stephen Johnson
  • 5,293
  • 1
  • 23
  • 37
  • If `drawRect:` is optimized correctly to only draw the specified rect, dragging around and redrawing the affected portions of the canvas is not very difficult. – Léo Natan Feb 25 '14 at 00:49
1

Going with CoreGraphics is going force you to write many more lines of code than building with UIViews, although it is more performant and better on memory. However, you're likely going to need a more robust solution for managing all of that content. A UICollectionView seems like an appropriate solution for mapping your data on to a view with a custom UICollectionViewCell subclass. This is going to be much quicker to develop than rolling your own, and comes with great flexibility through UICollectionViewLayout subclasses. Pinch to zoom isn't supported out of the box, but there are ways to do it. This is also better for memory than using a bunch of UIViews because of cell reuse, but reloading can become slow with a few hundred items that all have different sizes to be calculated.

Community
  • 1
  • 1
Patrick Goley
  • 5,397
  • 22
  • 42