How to add shadows to the shapes in iOS 8 Swift? - ios

I am learning swift language.
I am working on shapes. Can we add shadows to the shape?
I am creating rectangle using CGPathAndRect. How to add shadow to this?
Code to create rectangle:
func drawRectOnScreen(){
let currentContext = UIGraphicsGetCurrentContext()
let secondPath = CGPathCreateMutable()
let secondRect = CGRect(x: 150, y: 250, width: 100, height: 100)
CGPathAddRect(secondPath, nil, secondRect)
CGContextAddPath(currentContext, secondPath)
UIColor.purpleColor().setFill()
CGContextDrawPath(currentContext, kCGPathFill)
}

Use Following Code :
CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5)
after
UIColor.purpleColor().setFill()

Found an answer from iOS 8 Swift Programming Cookbook
func drawRectAtTopOfScreen(){
let currentContext = UIGraphicsGetCurrentContext()
CGContextSaveGState(currentContext)
let offset = CGSizeMake(10, 10)
CGContextSetShadowWithColor(currentContext, offset, 20, UIColor.grayColor().CGColor)
let path = CGPathCreateMutable()
let firstRect = CGRect(x: 55, y: 60, width: 150, height: 150)
CGPathAddRect(path, nil, firstRect)
CGContextAddPath(currentContext, path)
UIColor(red: 0.20, green: 0.60, blue: 0.80, alpha: 1.0).setFill()
CGContextDrawPath(currentContext, kCGPathFill)
CGContextRestoreGState(currentContext)
}

Related

UIButton shadow and lighting effect (Swift 4)

I'd like to add a lighting effect like these two buttons, a shadow on the bottom but also a lighted edge on top as if there were a light above it.
I've been experimenting with :
button.layer.shadowColor = UIColor.black.cgColor
button.layer.shadowColor.layer.shadowOffset = CGSize(width: 2, height: 2)
button.layer.shadowColor.layer.shadowRadius = 2
button.layer.shadowColor.layer.shadowOpacity = 8
button.layer.shadowColor.layer.masksToBounds = false
and get a nice shadow on the bottom, but how would I light up the top edge?
I was able to get a button pretty similar to your first drawing, just as an experiment:
The button background is constructed entirely using elementary drawing commands involving UIBezierPath and CGContext in a UIGraphicsImageRenderer. So if that's an acceptable sort of approach, you could just do a tweak on the sort of thing I'm doing.
let r = UIGraphicsImageRenderer(size: CGSize(width:100, height:100))
let im = r.image {
ctx in let con = ctx.cgContext
do {
let p = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 0, width: 100, height: 50), cornerRadius: 10)
UIColor(white: 0.9, alpha: 1.0).setFill()
p.fill()
}
do {
let p = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 50, width: 100, height: 50), cornerRadius: 10)
UIColor(white: 0.1, alpha: 1.0).setFill()
p.fill()
}
do {
let p = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 2, width: 100, height: 95), cornerRadius: 10)
p.addClip()
}
let locs : [CGFloat] = [ 0.0, 0.2, 0.8, 1.0 ]
let colors : [CGFloat] = [
0.54, 0.54, 0.54, 1.0,
0.5, 0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 1.0,
0.44, 0.44, 0.44, 1.0,
]
let sp = CGColorSpaceCreateDeviceRGB()
let grad = CGGradient(
colorSpace:sp, colorComponents: colors, locations: locs, count: 4)!
con.drawLinearGradient(grad,
start: CGPoint(x:0,y:0), end: CGPoint(x:0,y:100), options:[])
}
let b = UIButton(type: .custom)
b.setTitle("9", for: .normal)
b.setBackgroundImage(im, for: .normal)
b.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
b.titleLabel?.font = UIFont.systemFont(ofSize: 40, weight: .bold)
self.view.addSubview(b)
b.layer.borderWidth = 1
b.layer.borderColor = UIColor.black.cgColor
b.layer.cornerRadius = 10

How to erase the thin side line right bottom?

I want compound view's shape from Oval shape subtract Rect shape,
so first I create a mask image:
let paths = CGMutablePath()
//Oval shape path at left
let leftPath = CGPath(ellipseIn: CGRect(x: 0, y: 0, width: 200, height: 150), transform: nil)
//Rect shape path at right
let rightPath = CGPath(roundedRect: CGRect(x: 100, y: 100, width: 120, height: 100), cornerWidth: 8, cornerHeight: 8, transform: nil)
paths.addPath(leftPath)
paths.addPath(rightPath)
UIGraphicsBeginImageContext(CGSize(width: 220, height: 200))
let ctx = UIGraphicsGetCurrentContext()
ctx?.addPath(paths)
ctx?.clip(using: .evenOdd)
ctx?.addPath(leftPath.cgPath)
ctx?.clip(using: .evenOdd)
ctx?.setFillColor(UIColor.red.cgColor)
ctx?.fill(CGRect(x: 0, y: 0, width: 220, height: 200))
//the mask image
let maskImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
next I use this image for mask:
let maskView = UIImageView(image: maskImage)
maskView.contentMode = .center
imageView.mask = maskView
run App, I get this:
looks good?not really...
if you look carefully,you will notice a thin line at view right bottom
It's not OK for me!
How do I erase the sideline??? Thanks :)
Draw the ellipse, then clear the rounded rect.
import UIKit
let ellipse = CGPath(ellipseIn: CGRect(x: 0, y: 0, width: 200, height: 150), transform: nil)
let roundedRect = CGPath(roundedRect: CGRect(x: 100, y: 100, width: 120, height: 100), cornerWidth: 8, cornerHeight: 8, transform: nil)
let maskImage = UIGraphicsImageRenderer(size: CGSize(width: 220, height: 200)).image { rendererContext in
let ctx = rendererContext.cgContext
ctx.setFillColor(UIColor.red.cgColor)
ctx.addPath(ellipse)
ctx.fillPath()
ctx.setBlendMode(.clear)
ctx.addPath(roundedRect)
ctx.fillPath()
}
Result:

render two UILabels in CGContext without overlapping

Hello i try to render two labels in one CGContext to get an UIImage - one above the other. However the code is ignoring the origins of the CGRects. Can anyone point me in the right direction?
// frames with positions and bounds
let frame = CGRect(x: 0, y: 0, width: 64, height: 64)
let upperFrame = CGRect(x: 0, y: 0, width: 64, height: 40)
let lowerFrame = CGRect(x: 0, y: 40, width: 64, height: 24)
// settings of lower label
let lowerLabel = UILabel(frame: lowerFrame)
lowerLabel.textAlignment = .center
lowerLabel.backgroundColor = UIColor.init(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.0)
lowerLabel.textColor = .black
lowerLabel.font = nameLabel.font.withSize(15.0)
lowerLabel.adjustsFontSizeToFitWidth = true
lowerLabel.minimumScaleFactor = 1.0/nameLabel.font.pointSize
lowerLabel.text = "Monatsende"
// settings of upper label
let upperLabel = UILabel(frame: upperFrame)
upperLabel.textAlignment = .center
upperLabel.backgroundColor = UIColor.init(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.0)
upperLabel.textColor = .black
upperLabel.font = upperLabel.font.withSize(15.0)
upperLabel.adjustsFontSizeToFitWidth = true
upperLabel.minimumScaleFactor = 1.0/upperLabel.font.pointSize
upperLabel.text = "2500 €"
// draw alltogether
UIGraphicsBeginImageContext(frame.size)
if let currentContext = UIGraphicsGetCurrentContext() {
lowerlabel.layer.render(in: currentContext)
upperLabel.layer.render(in: currentContext)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
the result is, that both labels are overlapping each other:
as i understand it the two labels should be clearly distinguishable from one another.

How to draw lines using UIView?

I can draw lines using CGContext. How to draw lines with the same coordinates using UIView? I want to move lines in the future, so that I need to use UIView.
func DrawLine()
{
UIGraphicsBeginImageContext(self.view.frame.size)
imageView.image?.draw(in: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
let context = UIGraphicsGetCurrentContext()
let lineWidth : CGFloat = 5
context?.move(to: CGPoint(x: 100, y: 100))
context?.addLine(to: CGPoint(x: self.view.frame.width - 100, y: 100))
context?.setBlendMode(CGBlendMode.normal)
context?.setLineCap(CGLineCap.round)
context?.setLineWidth(lineWidth)
context?.setStrokeColor(UIColor(red: 0, green: 0, blue: 0, alpha: 1.0).cgColor)
context?.strokePath()
context?.move(to: CGPoint(x: self.view.frame.width/2, y: 100))
context?.addLine(to: CGPoint(x: self.view.frame.width/2, y: 700))
context?.strokePath()
imageView.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
override func viewDidLoad()
{
super.viewDidLoad()
DrawLine()
}
Add a CAShapeLayer to a UIView
let shapeLayer = CAShapeLayer()
view.layer.addSublayer(shapeLayer)
set the shapelayer path to the lines
shapeLayer.path = // some CGPath you create
See: https://stackoverflow.com/a/40556796/3937 for how to make a CGPath with lines.

How to put a black color with opacity on an image in Swift 3

I'd like to know how can I put a black rectangle with opacity on the top of an image in Swift 3. For example:
you can create a UIView that is black with an opacity and make it the same size of your UIImageView and add it as subview. Try something like:
let tintView = UIView()
tintView.backgroundColor = UIColor(white: 0, alpha: 0.5) //change to your liking
tintView.frame = CGRect(x: 0, y: 0, width: imageView.frame.width, height: imageView.frame.height)
imageView.addSubview(tintView)
imageView = Your UIImageView
func drawRectOn(image: UIImage) -> UIImage {
UIGraphicsBeginImageContext(image.size)
image.draw(at: CGPoint.zero)
let context = UIGraphicsGetCurrentContext()
// set fill gray and alpha
context!.setFillColor(gray: 0, alpha: 0.5)
context!.move(to: CGPoint(x: 0, y: 0))
context!.fill(CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
context!.strokePath()
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
// end the graphics context
UIGraphicsEndImageContext()
return resultImage!
}

Resources