iOS Brownbag: Views vs. Layers
Join the DZone community and get the full member experience.
Join For Free
for many ios developers,
layers
are a lower-level, complex
version of the uiview. in reality, it’s the uiview which is a thin
layer on top of calayer. unfortuntely, 95% of the ios books and
documentation out there talk almost exclusively about the uikit and so
it’s no surprise we get that impression.
in this blog, i’m going to explain the difference between uiview and
calayer, tell you when you should be using either, and demonstrate the
power of layers by creating a working clock.
uiview vs. calayer
despite what many developers think, it’s the calayer that’s the
fundamental drawing unit in ios. the reason why we perceive uiview as
such is because it’s a thin layer on top of calayer and for most ui
challenges using some form of uiview works just fine. you can create
custom views, draw into them, handle user interactions, and even animate
them without ever having to touch calayer.
every uiview comes packaged with a calayer knows as the “backing
layer” or “underlying layer.” many of the methods you call on uiview
simply delegate to the layer. when you change a view’s frame, it’s
simply changing the layer’s frame. if you change the alpha, it changes
the layer’s alpha…and so on with background colors, transformations and
more. and while you can maintain a hierarchy of uiviews each
representing parents and children of one another, you can do the same
with calayer.
now, let’s say you wanted to write a bar chart component. you’d
subclass uiview (or better yet, uicontrol) and write the logic for
displaying the colored bars you need to represent your data. if you’re
comfortable with the uikit, you might find it an easy choice to use
subviews to represent each bar. you can use a plain uiview, slap a
background color on it, size it…and repeat a dozen times depending on
how much data you’re representing. but, you’d be wrong. you shouldn’t
be using subviews, you should be using sublayers.
should i use subviews or sublayers?
this isn’t a simple question, but there’s one rule of thumb that make
deciding a lot easier. the main different between a view and a layer
is that views can accept user input while a layer cannot. a layer is
simply a graphical representation. views can handle user taps, drags,
pinches, etc. to me, this is all you need to know.
so, when making your bar chart, you should be using sublayers for the
bars. why? because they don’t need user input and since they’re
lighter weight than views, they’re the right choice. so what do you
gain by using layers? well, aside from performance, you also gain
implicit animation and better control of the visual representation. you
see, every property you change on a layer is automatically animated.
you can disable them if you need to, but they come in handy. also, you
can apply shadow effects, corner radiuses, 3d transforms and more on
layers. you can apply many of these on views, too, but they’re simply
delegating to their “underlying layer” and in many cases stealing event
notifications you’d rather they not from your view.
demo: let’s build a working clock!
to demonstrate how we use layers, i’m going to build a working clock. the architecture will be as follows:
- clockview will extend uicontrol so that we can use it with interface builder and, potentially in the future, handle user events.
- all the parts of the clock will be layers.
- since all of the parts are layers, we won’t be implementing drawrect.
- a timer, that we can start and stop, will handle updating the clock by adjusting the three hands.
here’s what our clock looks like:
every piece of it is rendered in layers: the face, numbers, ticks,
all three hands, and the centerpoint. i used a mix of techniques to
render it. shadow effects give the hands depth, rounded line miters
give the hands softness, and combining anchoring with transforms gives
the hands a more natural clock look by having them rotate around the
centerpoint. no pngs were used and no primitives were drawn.
here’s the
source code
.
you can take this code and drop it right into your own project. simply
call clockview#startupdates to get things going! also, note that i only
implement initwithcoder, so if you want to add it to your ui
programmatically, override initwithframe as well. you’ll also need to
link in the quartzcore framework — anything that uses ca* will need it.
(note: it’s not a memory leak, it’s arc! also, i recommend using constants instead of raw time constants. why not try
iboost
?)
on line #41, i use a cashapelayer. these things are awesome! by
providing a path, you can make a layer of any shape. you can specify
stroke and fill colors, change line attributes, and so on. the clock
would be way more complex without these bad boys.
on line #45, i use the position property to place the face layer.
layers are positioned differently than views. while you might use
frame, bounds, or center to position a view…you use bounds, position,
and anchorpoint to position a layer. while bounds works as expected,
position and anchorpoint are different. the anchorpoint is a cgpoint
where the x and y normally range between 0 and 1. the 0 represents the
top or left of the image, and 1 is the bottom or right of the image.
the default is 0.5, 0.5 which is the center of the image. that means
that whatever you set the position property to, that’s where the center
of the layer will be. you can change the anchorpoint to position things
differently. if you set it to 0, 0, position will be where the top
left of the image is. get it? additionally, you can make an anchor
0.5, 10 which will position the layer 10x the height of the layer above
the position. magic.
on line #59, i use a catextlayer which lets you specify text easily as a layer.
on line #67, i use 3d transforms to position the numbers. by making
the bounds of the number higher than expected, a simple rotational
transform positions the numbers where i want. (if you wanted the numbers
all “face up”, you’d have to position these using trigonometry instead,
but this is a layer demo!) note that the last 3 params of this method
specify which axes to rotate around. i specify the last one, which is
the z-axis, which is by far the most common.
summary
layers are the powerful core of the cocoa touch framework. even if
you’ve never used a layer directly, you’re probably familiar with many
concepts because uiviews are simply thin layers on top of them. want to
give your view a rounded rectangle appearance? simply set
myview.layer.cornerradius to 5.0! want dynamic drop shadows to make
image sizing easier? set myview.layer.shadowopacity greater than 0.0.
done! remember, uiviews are designed to handle user input, and layers
are the graphical workhorse. use them!
source:
http://raptureinvenice.com/ios-brownbag-view-vs-layers-including-clock-demo/
Opinions expressed by DZone contributors are their own.
Comments