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.
Related
I am new in swift and I am trying to add shadow to UIView.
My code is like this
ViewPay.layer.masksToBounds = false
ViewPay.layer.shadowRadius = 2
ViewPay.layer.shadowOpacity = 1
ViewPay.layer.shadowColor = UIColor.red.cgColor
ViewPay.layer.shadowOffset = CGSize(width: 0 , height:2)
but it is adding shadow to all side
How can I add shadow like this
One solution is, put your ViewPay inside a container UIView.
Set your ViewPay to leading and trailing edges of container view, and for top and bottom add some padding to show shadow.
Also set container view clipsToBounds equals to true.
I hope to help with the solution of your question. In case you wanted something simple to understand, and also following the tips. You create a large container and add the required views. A vertical view of the purple color, another horizontal that would be gray color and in the middle put an image, as I did in the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Big container
let container = UIView(frame: CGRect(x: self.view.bounds.width * 0.25, y: self.view.bounds.height * 0.5, width: 250, height: 290))
container.backgroundColor = .clear
self.view.addSubview(container)
//Purple view
let viewContainer = UIView(frame: CGRect(x: container.bounds.midX , y: 0, width: container.bounds.width * 0.89, height: container.bounds.height))
viewContainer.layer.anchorPoint.x = 1.0
viewContainer.backgroundColor = UIColor(displayP3Red: 158/255, green: 131/255, blue: 178/255, alpha: 1.0)
viewContainer.layer.cornerRadius = 8
viewContainer.clipsToBounds = true
container.addSubview(viewContainer)
//Gray view
let viewContainer2 = UIView(frame: CGRect(x: container.bounds.midX , y: container.bounds.midY, width: container.bounds.width * 0.93, height: container.bounds.height * 0.86))
viewContainer2.layer.anchorPoint.y = 1.0
viewContainer2.layer.anchorPoint.x = 1.0
viewContainer2.backgroundColor = UIColor(white: 0.5, alpha: 0.3)
viewContainer2.layer.cornerRadius = 5
viewContainer2.clipsToBounds = true
container.addSubview(viewContainer2)
//image
let imageView = UIImageView(frame: CGRect(x: container.bounds.midX, y: container.bounds.midY, width: container.bounds.width * 0.90, height: container.bounds.height * 0.90))
imageView.contentMode = .scaleToFill
imageView.layer.anchorPoint = CGPoint(x: 1.0, y: 1.0)
imageView.layer.cornerRadius = 10
imageView.clipsToBounds = true
imageView.image = UIImage(named: "image name")
container.addSubview(imageView)
}
}
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
I set "borderwidth = 3" to the view. After I scaling, the border either became thicker or thinner.
before scaling (yellow border on the left photo)
after scaling( yellow border on the right photo)
enter image description here
How can I keep the width of the border fixed after I scale it?
I user this source on the GitHub
https://github.com/yokurin/DragRotateScaleView
And just add v.layer.borderWidth = 5
lazy var rect1: DragRotateScaleView = {
let v = DragRotateScaleView(frame: CGRect(x: 20, y: 100, width: 200, height: 200))
v.delegate = self
v.backgroundColor = UIColor.cyan
v.layer.borderColor = UIColor(red: 22/255, green: 22/255, blue: 22/255, alpha: 1).cgColor
v.layer.borderWidth = 5
return v
}()
Thank You!!
Just divide the border width by the scale and set that value to the borderWidth again.
Try this in a playground:
import UIKit
import PlaygroundSupport
// Save this values, you will use them.
let border: CGFloat = 3
let scale: CGFloat = 5
// Example views.
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .red
let secondView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
secondView.layer.borderColor = UIColor.yellow.cgColor
secondView.layer.borderWidth = border
view.addSubview(secondView)
// View scale transformation.
secondView.transform = CGAffineTransform(scaleX: scale, y: scale)
// IMPORTANT: Change the width of the border after the transformation.
secondView.layer.borderWidth = border / scale
// This is only for the playground.
PlaygroundPage.current.liveView = view
I am trying to achieve something as this:
However I am getting this:
Code I am using:
let border = CALayer()
border.backgroundColor = UIColor.viewShadowGray().cgColor
border.frame = CGRect(x: 0, y: 0, width: bottomView.frame.size.width, height: 2)
bottomView.layer.addSublayer(border)
class func viewShadowGray() -> UIColor
{
return UIColor(red: 177.0/255.0, green: 177.0/255.0, blue: 179.0/255.0, alpha: 0.7)
}
Create a shadow with UIBezierPath something like as below.
You may need to vary opacity (layer?.shadowOpacity = 0.80) and shadow radius (layer?.shadowRadius = 3.0) to match your requirement .
func addShadow(to view: UIView?) {
//Adds a shadow to view
let layer: CALayer? = view?.layer
layer?.shadowOffset = CGSize(width: 0, height: 3)
layer?.shadowColor = UIColor.black.cgColor
layer?.shadowRadius = 3.0
layer?.shadowOpacity = 0.80
layer?.shadowPath = (UIBezierPath(rect: CGRect(x: layer?.bounds.origin.x ?? 0.0, y: layer?.bounds.origin.y ?? 0.0, width: layer?.bounds.size.width ?? 0.0, height: (layer?.bounds.size.height ?? 0.0) + 1))).cgPath
}
I'm able to add a custom status bar (with gradient) to the UIView like this:
override func viewDidLoad() {
super.viewDidLoad()
var statusBar : UIView = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 20))
let statusBarGradient : CAGradientLayer = CAGradientLayer()
statusBarGradient.frame = statusBar.bounds
let cor1 = UIColor(red: 0.416, green: 0.604, blue: 0.796, alpha: 1.0)
let cor2 = UIColor.whiteColor()
let arrayColors = [cor1.CGColor, cor2.CGColor]
statusBarGradient.colors = arrayColors
view.layer.insertSublayer(statusBarGradient, atIndex:0)
}
I would also like to add the same gradient to the footer but I'm not having much luck.
Your code works if you add the statusBar as a subview of the view, but I would make it dynamically size the width to fit the width of the superview, so just do the same thing for the footer, but dynamically set the height to be whatever the height of your view is minus the desired height of your footer bar.
let statusBar = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 20))
let footer = UIView(frame: CGRect(x: 0, y: view.frame.height - 20.0, width: view.frame.width, height: 20))
let statusBarGradient = CAGradientLayer()
let footerGradient = CAGradientLayer()
statusBarGradient.frame = statusBar.bounds
let cor1 = UIColor(red: 0.416, green: 0.604, blue: 0.796, alpha: 1.0)
let cor2 = UIColor.blackColor()
let arrayColors = [cor1.CGColor, cor2.CGColor]
footerGradient.frame = footer.bounds
let arrayColorsFooter = [cor2.CGColor, cor1.CGColor]
statusBarGradient.colors = arrayColors
footerGradient.colors = arrayColorsFooter
statusBar.layer.insertSublayer(statusBarGradient, atIndex:0)
footer.layer.insertSublayer(footerGradient, atIndex:0)
view.addSubview(statusBar)
view.addSubview(footer)