How To Draw the Oval Shape Layer to the UITextField - ios

I need to draw the Oval shape to my textfield , I don't know how to draw using layer, if anyone help me for this design shadow,

Here's the Objective-C translation of Anton's answer since question is tagged for Objective-C and not Swift:
CAShapeLayer *shadowLayer = [[CAShapeLayer alloc] init];
shadowLayer.fillColor = [UIColor lightGrayColor].CGColor;
shadowLayer.lineWidth = 0.0f;
CGSize shadowSize = CGSizeMake(textField.bounds.size.width + 40, 40);
CGRect shawdowBounds = CGRectMake(0, 0, shadowSize.width, shadowSize.height);
shadowLayer.path = [UIBezierPath bezierPathWithOvalInRect:shawdowBounds].CGPath;
shadowLayer.bounds = shawdowBounds;
shadowLayer.position = CGPointMake(CGRectGetMidX(textField.bounds), CGRectGetMaxY(textField.bounds));
[containerView.layer insertSublayer:shadowLayer atIndex0];

You can use this code as an example:
let shadowLayer = CAShapeLayer()
// set your shadow color here
shadowLayer.fillColor = UIColor.lightGray.cgColor
shadowLayer.lineWidth = 0
// calc size of your shadow according to your design
let shadowSize = CGSize(width: textField.bounds.width + 40, height: 20)
let shadowBounds = CGRect(origin: .zero, size: shadowSize)
shadowLayer.path = UIBezierPath(ovalIn: shadowBounds).cgPath
shadowLayer.bounds = shadowBounds
shadowLayer.position = CGPoint(x: textField.bounds.midX, y: textField.bounds.maxY)
containerView.layer.insertSublayer(shadowLayer, at: 0)
Here I assume that you have some containerView, containing your text field as a subview and keep reference to the text field in variable called textField.

Related

CAShapeLayer cutout in UIView

My goal is to create a pretty opaque background with a clear rounded rect inset
let shape = CGRect(x: 0, y: 0, width: 200, height: 200)
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: shape, cornerRadius: 16).cgPath
maskLayer.fillColor = UIColor.clear.cgColor
maskLayer.fillRule = kCAFillRuleEvenOdd
let background = UIView()
background.backgroundColor = UIColor.black.withAlphaComponent(0.8)
view.addSubview(background)
constrain(background) {
$0.edges == $0.superview!.edges
}
background.layer.addSublayer(maskLayer)
// background.layer.mask = maskLayer
When I uncomment background.layer.mask = maskLayer, the view is totally clear. When I have it commented out, I see the semi-opaque background color but no mask cutout
Any idea what I'm doing wrong here? Thanks!
Here is a playground that I think implements your intended effect (minus .edges and constrain - that appear to be your own extensions).
a) used a red background instead of black with alpha (just to make the effect stand out)
b) set maskLayer.backgroundColor instead of maskLayer.fillColor
Adding the maskLayer as another layer to uiview is superfluous (as indicated by #Ken) but seems to do no harm.
import UIKit
import PlaygroundSupport
let bounds = CGRect(x: 0, y: 0, width: 400, height: 200)
let uiview = UIView(frame: bounds)
uiview.backgroundColor = UIColor.red.withAlphaComponent(0.8)
PlaygroundPage.current.liveView = uiview
let shape = CGRect(x: 100, y: 50, width: 200, height: 100)
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: shape, cornerRadius: 16).cgPath
maskLayer.backgroundColor = UIColor.clear.cgColor
maskLayer.fillRule = kCAFillRuleEvenOdd
uiview.layer.mask = maskLayer
image of clear inset
On the other hand, if you intended a picture frame / colored-envelope-with-transparent-window effect like below, then see gist
image of picture frame
Your mask Layer has no size.
Add this line maskLayer.frame = shape
and you don't need background.layer.addSublayer(maskLayer)

Shadow on UIView layer

I've make a path in order to mask my view:
let path = // create magic path (uiview bounds + 2 arcs)
let mask = CAShapeLayer()
mask.path = path.cgPath
view.layer.masksToBounds = false
view.layer.mask = mask
Up to here all ok.
Now I would like to add a shadow that follows path, is it possibile?
I try in several way, the last one is:
mask.shadowPath = path.cgPath
mask.shadowColor = UIColor.red.cgColor
mask.shadowOffset = CGSize(width: 10, height: 2.0)
mask.shadowOpacity = 0.5
But this produce a partial shadow and with color of the original view..
With debug view hierarchy:
Any advice?
Final result should be similar to this, but with shadow that "follows" arcs on path.
When you add a mask to a layer, it clips anything outside that mask - including the shadow. To achieve this you'll need to add a "shadow" view below your masked view, that has the same path as the mask.
Or add a shadow layer to the masked view's superview.
let view = UIView(frame: CGRect(x: 50, y: 70, width: 100, height: 60))
view.backgroundColor = .cyan
let mask = CAShapeLayer()
mask.path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 10).cgPath
view.layer.mask = mask
let shadowLayer = CAShapeLayer()
shadowLayer.frame = view.frame
shadowLayer.path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 10).cgPath
shadowLayer.shadowOpacity = 0.5
shadowLayer.shadowRadius = 5
shadowLayer.masksToBounds = false
shadowLayer.shadowOffset = .zero
let container = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
container.backgroundColor = .white
container.layer.addSublayer(shadowLayer)
container.addSubview(view)
If you're going to be using this elsewhere, you could create a ShadowMaskedView that contains the shadow layer, and the masked view - maybe with a path property.
You can try this extension:
extension UIView {
func dropShadow() {
self.layer.masksToBounds = false
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOpacity = 0.5
self.layer.shadowOffset = CGSize(width: -1, height: 1)
self.layer.shadowRadius = 1
self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
self.layer.shouldRasterize = true
}
}

Drop shadow in ios

How to drop an object shadow in iOS?
My object is UIImageView and i want to drop an elliptical shadow.Please refer image for reference.
Better you use another image for showing shadow. Use blur image or change alpha of the imageview.
Or if you want to do it programmatically, try it:
Obj c:
//create elliptical shadow for image through UIBezierPath
CGRect ovalRect = CGRectMake(0.0f, _imageView.frame.size.height + 10, _imageView.frame.size.width, 15);
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:ovalRect];
//applying shadow to path
_imageView.layer.shadowColor = kShadowColor.CGColor;
_imageView.layer.shadowOffset = CGSizeMake(0.0, 0.0);
_imageView.layer.shadowOpacity = 1.0;
_imageView.layer.shadowRadius = 3.0;
_imageView.layer.shadowPath = path.CGPath;
Swift :
//create elliptical shdow forimage through UIBezierPath
var ovalRect = CGRectMake(0.0, imageView.frame.size.height + 10, imageView.frame.size.width, 15)
var path = UIBezierPath(ovalInRect: ovalRect)
//applying shadow to path
imageView.layer.shadowColor = UIColor(white: 0.0, alpha: 0.5).CGColor
imageView.layer.shadowOffset = CGSizeMake(0.0, 0.0)
imageView.layer.shadowOpacity = 1.0
imageView.layer.shadowRadius = 3.0
imageView.layer.shadowPath = path.CGPath
Output:
Taken from http://www.innofied.com/implementing-shadow-ios/ and also have a look to know more: UIView with rounded corners and drop shadow?
You can use CAShapeLayer like this:
Objective-C:
// init CAShapeLayer
CAShapeLayer *shadowLayer = [CAShapeLayer layer];
shadowLayer.frame = CGRectMake(CGRectGetMinX(_imageView.frame), CGRectGetMaxY(_imageView.frame), _imageView.frame.size.width, _imageView.frame.size.height);
shadowLayer.path = [UIBezierPath bezierPathWithOvalInRect:shadowLayer.bounds].CGPath;
shadowLayer.fillColor = [UIColor colorWithWhite:0 alpha:0.02].CGColor;
shadowLayer.lineWidth = 0;
[self.view.layer addSublayer: shadowLayer];
Swift 3
let shadowLayer = CAShapeLayer()
shadowLayer.frame = CGRect(x: imageView.frame.minX, y: imageView.frame.maxY, width: imageView.frame.width, height: imageView.frame.height * 0.25)
shadowLayer.path = UIBezierPath(ovalIn: shadowLayer.bounds).cgPath
shadowLayer.fillColor = UIColor(white: 0, alpha: 0.02).cgColor
shadowLayer.lineWidth = 0
view.layer.addSublayer(shadowLayer)
Output:

Corner radius for a button to align with a view below

There are tons of answers on SO for rounding a particular corner. The issue I'm running into is I'm trying to align a button corner to a rounded corner of the view below. Please see the image. The yellow view is rounded in 4 corners. I'm trying to get the close button to round off at top right to align with the yellow view's round corner. I've used the Swift 3 code below, but the button stays square. Can anyone please point out what is missing?
viewRaised is the yellow view.
Many thanks!
let path = UIBezierPath(roundedRect: btnCancel.layer.bounds, byRoundingCorners:[.topRight, .bottomLeft], cornerRadii: CGSize(width: 10, height: 10))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
btnCancel.layer.mask = maskLayer
btnCancel.layer.masksToBounds = true
self.viewRaised.layer.cornerRadius = 10
self.viewRaised.layer.masksToBounds = false
self.viewRaised.layer.shadowOffset = CGSize(width: 5, height: 10);
self.viewRaised.layer.shadowRadius = 10;
self.viewRaised.layer.shadowOpacity = 0.5;
UPDATE:
Interesting thing is that the same code seems to be working but only for top left. See the second image.
self.viewRaised.layer.cornerRadius = 10
self.viewRaised.layer.masksToBounds = false
self.viewRaised.layer.shadowOffset = CGSize(width: 5, height: 10);
self.viewRaised.layer.shadowRadius = 10;
self.viewRaised.layer.shadowOpacity = 0.5;
let path = UIBezierPath(roundedRect: btnCancel.layer.bounds, byRoundingCorners:[.allCorners], cornerRadii: CGSize(width: 10, height: 10))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
btnCancel.layer.mask = maskLayer
This is quite perplexing. I'm using XCode Version 8.0 beta 6 (8S201h)
Your btnCancel.layer.mask should be set to the yellow view.
You need to add btnCancel as a sublayer of of yellow view's parent.
Example (Swift 3.x) :
let yellowView = UIView(frame: CGRectMake(20.0, 20.0, 200.0, 200.0))
yellowView.backgroundColor = UIColor.yellowColor()
yellowView.layer.borderColor = UIColor.clearColor().CGColor
yellowView.layer.borderWidth = 1.0
yellowView.layer.cornerRadius = 10.0
self.view.addSubview(yellowView) // Add yellowView to self's main view
let btnCancel = UIView(frame: CGRectMake(20.0, 20.0, 45.0, 45.0))
btnCancel.backgroundColor = UIColor.redColor()
btnCancel.layer.mask = yellowView.layer // Set btnCancel.layer.mask to yellowView.layer
self.view.addSubview(btnCancel) // Add btnCancel to self's main view, NOT yellowView
NOTE:
You don't need to enable clipsToBounds because you're setting a mask layer.
You Also don't need to create a new CAShapeLayer for the mask. Use yellowView's layer as the mask.
Swift 4.x :
let yellowView = UIView(frame: CGRect(x: 20.0, y: 20.0, width: 200.0, height: 200.0))
yellowView.backgroundColor = .yellow
yellowView.layer.borderColor = UIColor.clear.cgColor
yellowView.layer.borderWidth = 1.0
yellowView.layer.cornerRadius = 10.0
self.view.addSubview(yellowView) // Add yellowView to self's main view
let btnCancel = UIView(frame: CGRect(x: 20.0, y: 20.0, width: 45.0, height: 45.0))
btnCancel.backgroundColor = .red
btnCancel.layer.mask = yellowView.layer // Set btnCancel.layer.mask to yellowView.layer
self.view.addSubview(btnCancel) // Add btnCancel to self's main view, NOT yellowView
All I needed to do was remove the whole of this. But it worked if I remove the bolded line only. But the rest of the lines were not needed once since Cancel Button was the subview of the yellow view.
let path = UIBezierPath(roundedRect: btnCancel.layer.bounds, byRoundingCorners:[.topRight, .bottomLeft], cornerRadii: CGSize(width: 10, height: 10))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
btnCancel.layer.mask = maskLayer
btnCancel.layer.masksToBounds = true

iOS Clean corners for rounded profile image

So I followed an AppCoda tutorial on rounding the corners of a profile image, and it worked fine, except for one thing. Wherever the image was rounded, there is a bit of bleed-through from the image (especially if a white border is used).
self.imageview.image = image
self.imageview.layer.cornerRadius = 10.0
self.imageview.layer.borderWidth = 3.0
self.imageview.layer.borderColor = UIColor.whiteColor().CGColor
self.imageview.clipsToBounds = true
You can also add a mask which is inset a little, if you want:
let path = UIBezierPath(roundedRect: CGRectInset(imageView.bounds, 0.5, 0.5), cornerRadius: 10.0)
let mask = CAShapeLayer()
mask.path = path.CGPath
imageview.layer.mask = mask
You could create a mask over the rectangle. This seems to give clean edges, at least in Playground. Here is the code, but you will need to modify it a bit to get rounded inner rect.
// simple red rect
var view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = UIColor.redColor()
view.layer.borderColor = UIColor.whiteColor().CGColor
view.layer.borderWidth = 6.0
// path for the mask
let rectanglePath = UIBezierPath(roundedRect:view.bounds, cornerRadius: 20)
// applying the mask over the view
let maskLayer = CAShapeLayer()
maskLayer.frame = view.bounds
maskLayer.path = rectanglePath.CGPath
view.layer.mask = maskLayer
A simple solution is that you can enlarge layer's bounds a little bit to cover the edge of view's image:
CGFloat offset = 1.f; // .5f is also good enough
self.imageview.image = image;
self.imageview.layer.cornerRadius = 10.0;
self.imageview.layer.borderWidth = 3.0 + offset;
self.imageview.layer.borderColor = UIColor.whiteColor().CGColor;
self.imageview.layer.masksToBounds = YES;
[self.imageview.layer setBounds:CGRectMake(-offset,
-offset,
CGRectGetWidth(self.imageview.frame) + offset * 2.f,
CGRectGetHeight(self.imageview.frame) + offset * 2.f)];

Resources