I'm trying to add some shadows to one of my views and what I would like to achieve is drawing shadows only on one side and let them have sharp edges. No I've tried quite a few methods without any luck (using the shadow related properties of the view's CALayer + UIBezierPaths). However, iOS is always rendering a shadow with soft edges like this:
But what I really want to acchieve is something like this (without round corners and sharp edges on the sides except one):
Is there any elegant way to do this or will I have to draw the shadow myself using CoreGraphics?
PS: I forgot to mention, my view should actually be a custom UIButton, so overriding drawRect: would be a pain here
I've experienced a mask removing the shadow from view...so maybe you can try that.
CALayer *mask = [[[CALayer alloc] init] autorelease];
mask.backgroundColor = [UIColor blackColor].CGColor;
mask.frame = CGRectMake(0.0, 0.0, yellowView.bounds.size.width + shadowWidth, yellowView.bounds.size.height);
yellowView.layer.mask = mask;
I think what you want to be changing is the shadowRadius value - set that to zero and you should get the sharp edge you're looking for:
myView.layer.shadowRadius = 0;
Related
I'm using AVFoundation framework to scan a barcode, but that may be unrelevant for my problem.
What I want:
I would like that the square bordered in green be transparent (not with the darkened black).
Here is what I have done:
I have 2 views: backgroundView( which occupies the whole screen) and highlightView which is the square bordered with green, on top of backgroundView (I have used a XIB for dimensions and positions) :
self.highlightView.layer.borderColor = [UIColor greenColor].CGColor;
self.highlightView.layer.borderWidth = 3;
// this following line does not allow the square to be transparent
self.highlightView.layer.opacity = 0;
// relative to AVFoundation
_previewLayer.frame = _backgroundView.bounds;
[_backgroundView.layer addSublayer:_previewLayer];
_previewLayer.backgroundColor = [UIColor blackColor].CGColor;
_previewLayer.opacity = 0.3;
UPDATE : xib (here representing the square with a clear color background), the backgroundView has the property black color background).
As I mentioned, you were looking in the wrong direction. There are multiple posts with a problem similar to yours, which have pretty decent answers. (You will have to study and understand to make the most of them):
Cut Out Shape with Animation
Simply mask a UIView with a rectangle
To sum it up, you need to apply the semi-transparent color to the layer of backgroundView and then play around with the layer's mask property to get the work done.
You can find many tutorials to learn using the layer and mask together.
Hope this helps.
I'm trying to see if there's a way to create a UIView with a shadow behavior compliant with material design. My understanding is that the shadow gets more intense as the object is further removed from the background surface.
I can manually add a shadow like this, however this shadow does not calculate how intense the shadow should be (based on Z order).
button.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:button.layer.bounds cornerRadius:11].CGPath;
button.layer.shadowOpacity = 1.0;
button.layer.shadowOffset = CGSizeMake(1,1);
button.layer.shadowColor = [UIColor blackColor].CGColor;
How do I create a UIView which will behave like Google's material design? I found this example, called Material Kit, however it simply hides shadow on touch
One way in which Google does this is by emphasizing the use of a
‘z-axis’ to create a sense of depth in which elements can occupy
different levels. In order to show that an element is occupying a
higher level on the z-axis, shadows are used around its border, being
cast on to the level below. What this creates is the illusion of an
interactive layer/element that exists above a different, lower
interactive layer/element.
You could subclass UIButton, and first set the shadow properties to your liking:
button.layer.shadowOffset = CGSizeMake(0, 1);
button.layer.shadowRadius = 5;
button.layer.shadowOpacity = 0;
Then change the shadowOpacity property when the highlighted state changes:
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
self.layer.shadowOpacity = (highlighted ? 0.85 : 0);
}
In order to apply both a shadow and a rounded corner, you need to use 2 nested views. This is because the two effects require competing masksToBounds properties.
Nest 2 UIViews. Apply the shadow to the outer view, setting masksToBounds = false. Then apply the rounded corner to the inner view, which requires masksToBounds = true.
Note that, according to Apple docs, masksToBounds is equivalent to clipsToBounds.
I did a bit of research, and I see, there is no easy way to
make only top right and top left corners of the UIView round, right?
ps. This code makes all 4 corners round which is smth. I don't want.
#import <QuartzCore/QuartzCore.h>
self.layer.cornerRadius = 5;
self.layer.masksToBounds = YES;
You can do it with this snippet:
// Set top right & left corners
[self setMaskTo:yourView byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight];
EDIT
Sorry, I forgot this
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(8.0, 8.0)];
CAShapeLayer *shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
PS: as I said in the comment, if you use things like this when displaying UITableViewCell cells, I've found that it's always a better choice to use background images because this kind of drawing stuff always affects performance.
I tried extensions for the UIView once and it did not work for me because it have caused problems when drawing a cell
I got a better and easier solution now in 2 steps that worked perfectly good :)
1) One line of code (Swift 2.0) - it wounds all 4 corners of a view:
YourView.layer.cornerRadius = 10
2) and one addition in storyboard you add 1 view with regular corners where you need no round corners and adjust constraints as you need :
note that small regular corner View should be behind the main view. This is how it looks in storyboard
Here you can see constraints needed for the small view
I have a UIView that programmatically draws a "sunburst" pattern using UIBezierPath. Now I would like to extend this by masking the edges with a gradient -- effectively making each "burst" fade from opaque to transparent. I'm think this could be done with a CAGradientLayer mask but I'm not sure how to make it circular.
This is what I'm trying -- it masks the view but the gradient is linear:
CAGradientLayer *l = [CAGradientLayer layer];
l.frame = CGRectMake(0.0f, 0.0f, rect.size.width, rect.size.height);
l.cornerRadius = rect.size.width/2.0f;
l.masksToBounds = YES;
l.colors = [NSArray arrayWithObjects:(id)[UIColor blackColor].CGColor, (id)[UIColor clearColor].CGColor, nil];
self.layer.mask = l;
I'm open to not using CAGradientLayer if anyone knows any other ways to mask a view with a circle with blurred edges.
SOLUTION
Thanks to matt's insight, I ended up drawing a mask view using CGContextDrawRadialGradient, rendering that as a UIImage, and using that as a mask layer. If anyone is interested in this process, it is being used in this test project.
An obvious approach is to draw this effect manually. Start very small and draw the sunburst larger and larger and (at the same time) less and less opaque.
On the other hand, it might be sufficient to make a radial gradient and use it as a mask (vignette effect). Core Graphics will draw the radial gradient for you:
https://developer.apple.com/library/ios/#documentation/graphicsimaging/reference/CGContext/Reference/reference.html#//apple_ref/c/func/CGContextDrawRadialGradient
I'm also very fond of CIFilters for adding touches like this: you should look through the catalogue and see what strikes your fancy:
https://developer.apple.com/library/ios/#documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html
CIFilter actually gives you a sunburst transition that might suit your purposes, especially if combined with masking and compositing; here's a discussion of the sunburst (used in an animation), from my book:
http://www.apeth.com/iOSBook/ch17.html#_cifilter_transitions
CAGradientLayer draws linear gradients.
You could try to set a shadow and see if that suits your needs:
l.shadowColor = [UIColor blackColor];
l.shadowRadius = rect.size.width / 2;
You can do this by creating a CALayer instance and give it a delegate that implements drawLayer:inContext: and draws a radial gradient in the implementation of that method. Then use that CALayer as your mask.
I know there have been many questions on this before however none seem to work in my scenario. Pretty much I am trying to make the top maybe 10 points below the top of the frame of my tableview somewhat darker so have a nicer effect than just the cells scrolling off the frame.
Pretty much I need to accomplish an effect where the alpha starts at 0 and ends at 1 of a gray color which is 10 points high. This way there is some sort of subtle area before the top of the frame so that it doesn't look like the cells are just moving out of the frame.
Is this possible?
Thanks!
You can set a shadow to the navigationBar layer, assuming you are using one.
self.navigationController.navigationBar.layer.shadowColor = [[UIColor blackColor] CGColor];
self.navigationController.navigationBar.layer.shadowOffset = CGSizeMake(0.0f,0.0f);
self.navigationController.navigationBar.layer.shadowOpacity = 1.0f;
self.navigationController.navigationBar.layer.shadowRadius = 4.0f;
If you are not using a navigation controller, then you can apply this same type of shadow to a UIView's layer.