I have a UIView subclass that overrides drawRect: to achieve various effects (gradient background, rounded corners with different radii, etc). When I profile the app and enable color blended layers in the simulator/instruments, instances of this class are never green, even if it is just drawing a solid gradient and has the opaque property set to YES. Is there something special you have to do in drawRect: in order for that property to be respected?
May be your should set the "opaque" property to NO , as Apple Doc say :
An opaque view is expected to fill its bounds with entirely opaque content—that is, the content should have an alpha value of 1.0. If the view is opaque and either does not fill its bounds or contains wholly or partially transparent content, the results are unpredictable. You should always set the value of this property to NO if the view is fully or partially transparent.
So in the drawRect method , if you draw some opaque layer , you should make sure that the the view's opaque property's value set to NO.
UIView reference
Related
I'm writing an iPhone app. For most of the scenes on our storyboard the default behaviour when the phone changes from portrait orientation to landscape orientation is fine. I.e. this is the layout change we want:
But for one of the scenes in the storyboard I do not want this layout change. Instead I want this:
I am confused about how to achieve the latter layout change. I can use size classes to ensure that the 100 pixels gap for the toolbar swaps from the bottom (portrait) to the right (landscape), but I cannot work out how to constrain the toolbar correctly, especially because the rotation needs to happen in code, e.g.
switch (UIDevice.currentDevice().orientation) {
case UIDeviceOrientation.LandscapeLeft, UIDeviceOrientation.LandscapeRight:
self.toolbarView.transform = CGAffineTransformMakeRotation(CGFloat(3 * M_PI_2))
// Reposition toolbarView into space to the right of the content's view
break
default:
self.toolbarView.transform = CGAffineTransformIdentity
break
}
What should I do to reposition the toolbar correctly?
Layout constraints constrain the frame of the given view. Let's see what the documentation says about the interplay between the frame and transform properties:
WARNING
If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
...
if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/frame
So you cannot do this via AutoLayout. You have to use center and bounds, and do positioning from code:
-(void)layoutSubviews {
[super layoutSubviews];
self.toolbarView.center = ...
self.toolbarView.bounds = ...
}
I need to make a project where I will draw some graphics on the screen, its about 25 separated bars, I've done it with UIView, but unfortunately not all devices can handle this job, because there is a 25x25 matrix of squares of UIViews, they are updating its color and alpha in 0.04 seconds, and its really takes a lot of memory to draw it like this, can someone please help with a purpose, how can it all be done faster for memory managing, and if its possible to control its components like alpha or background color for an object. Thanks in advance
What I understand is that you use 25 subviews for each bar. You can already optimize that and make each bar a single UIView. You can make a custom subclass of UIView that we will call BarView and override its drawRect method to draw the 25 squares of the bar.
Edit
Assuming you have an array bars that contains 25 bars (of type Bar). Each bar contains an array squares of 25 squares (of type Square).
- (void)drawRect:(CGRect)rect
{
CGContextRef *ctx = UIGraphicsGetCurrentContext();
for (Bar *bar in self.bars) {
for (Square *square in bar.squares) {
CGContextSetFillColorWithColor(ctx, square.color.CGColor);
CGContextFillRect(ctx, square.frame);
}
}
}
Bar and Square do not subclass UIView, they are simple NSObjects.
Finally note that this code is only an example and that there are possibilities to further improve performance.
Go for OpenGL. It has very efficient 2D drawing mechanism as well.
You might want to switch to a Core Animation based drawing approach as proposed in this answer. The idea is to draw as few things as possible using Core Graphics. Instead you create layers for all your independently animating graphical elements and animate layer properties.
To draw bars you could create a layer and set its backgroundColor and bounds/center properties to animate its size and appearance.
How do opaque alpha and the opacity of the background work together for a UIView and what are the differences between them?
UIView http://i.minus.com/jb2IP8TXbYTxKr.png
opaque means don't draw anything underneath, even if you are transparent.
The background color's alpha only affects the background color's transparency, not anything else drawn on the view.
alpha affects everything drawn on the view.
The opaque property can give you a speed increase - if you know that your view will never have transparency you can set this to YES and when iOS renders your view it can make some performance optimisations and render it faster. If this is set to NO iOS will have to blend your view with the view underneath, even if it doesn't happen to contain any transparency.
The alpha will also affect the alpha of the backround color i.e. if the background color is 0.5 transparent and the alpha is also 0.5, this has the effect of making the background view's alpha 0.25 (0.5 * 0.5).
To the very good answer by deanWombourne it's worth to add that, unless you don't draw your own content using the drawRect: method, the opaque property has no effect.
Apple's doc:
You only need to set a value for the opaque property in subclasses of
UIView that draw their own content using the drawRect: method. The
opaque property has no effect in system-provided classes such as
UIButton, UILabel, UITableViewCell, and so on.
If you draw your own content, keep in mind, that opaque is just a hint
This property provides a hint to the drawing system as to how it
should treat the view.
and some more guidelines from the same Apple's doc:
If the view is opaque and either does not fill its bounds or contains
wholly or partially transparent content, the results are
unpredictable. You should always set the value of this property to NO
if the view is fully or partially transparent.
iOS alpha vs opacity vs opaque
[Color Blended Layers]
UIView.alpha is equal to CALayer.opacity - [0.0 - 1.0] - apply alpha to all view(subviews, sublayers). It's like make a single flat bitmap image based on all content and apply alpha. That is why if view contains another subview or sublayer - no Blended Layers and is Off-screen Rendered is applied
UIView.backgroundColor is equal to CALayer.backgroundColor - applies color only on background(not subviews, sublayers)
UIView.opaque is equal to CALayer.opaque - Boolean property which hint's framework about some optimizations. But on practice it is not visible
Experiments
input
alpha
view1.alpha = 0.5
//or
view1.layer.opacity = 0.5
result and Off-screen Rendered
backgroundColor
view1.backgroundColor = .cyan.withAlphaComponent(0.5)
//or
view1.layer.backgroundColor = UIColor.cyan.withAlphaComponent(0.5).cgColor
result and Blended Layers
I have a view that's rendering a PDF into a CATiledLayer. This is working well.
Now I'm attempting to add a drop shadow to the view, so I did the usual:
tiledLayer.masksToBounds = NO;
tiledLayer.shadowOffset = CGSizeMake(5, 5);
tiledLayer.shadowRadius = 5;
tiledLayer.shadowOpacity = 0.5;
tiledLayer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
But what I'm seeing rendered is incorrect. What seems to be happening is that there's a drop shadow drawn for each tile as the tiles are being drawn. Once all the tiles are drawn, the final product looks right and has a shadow in the right place, but the intermediate rendering is distracting.
How can I use a drop shadow with a CATiledLayer?
You should wrap your CATiledLayer in a container layer with those shadow attributes applied to it. Judging by the self.bounds call, you might already be embedding the CATiledLayer in a view’s layer, in which case (unless you need masksToBounds) you can just apply the shadow attributes to that layer directly.
It makes perfect sense that a drop shadow is being drawn for each tile, that is exactly what you told it to do. I assume you have your tiles loading in some kind of parent view that contains them (usually a UIScrollView). You should set your drop shadow on that containing view.
I have a mask (loaded from a 256 grey PNG) that I want to apply to an image that's being used as part of my process for drawing a UITableViewCell's imageView.image property.
When the cell isn't selected/highlighted, I CGImageCreateWithMask with a square of the proper color and the mask, then drawAtPoint: it into the image I'm building. This works fine.
However, when the cell is selected or highlighted, I'd like to instead use the mask to instead punch through my image appropriately. That is, when my mask specifies full opacity, I want the image I'm building to be completely transparent so the tableview's background is drawn through it. Where my mask specifies 0 opacity, I want the alpha channel untouched. I want nothing other than the alpha channel affected.
I guess what I mean is that I want to draw clearColor over a UIImage, with a varying level of opacity according to a mask.
First, what is this called? And second, how do I do it?
I think you have to manipulate the CALayers for that. You can use the mask property of the cell's CALayer : CALayer mask attribute.
That is, something in the way of (if myMask is descendent of UIView) :
myCell.layer.mask = myMask.layer