Partially fill a CAShapeLayer() with a colour - ios

I am working with swift on xcode 9.2 to create bounding boxes on iOS 11. What I have here is a bounding box that can either be completely clear (so that the object being bounded can be seen) or completely filled with color (green here, so that the object the box bounds is completely covered in green). What I would like to do, is go partway with the color fill so that the bounding box is translucent. For instance, a bounding box with a green tint where the object being bounded is still visible. Any help on how to accomplish this will be very helpful
class BoundingBox {
let shapeLayer: CAShapeLayer
let textLayer: CATextLayer
init() {
shapeLayer = CAShapeLayer()
//shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.fillColor = UIColor.green.cgColor
shapeLayer.lineWidth = 4
shapeLayer.isHidden = true
textLayer = CATextLayer()
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.isHidden = true
textLayer.contentsScale = UIScreen.main.scale
textLayer.fontSize = 14
textLayer.font = UIFont(name: "Avenir", size: textLayer.fontSize)
textLayer.alignmentMode = kCAAlignmentCenter
}
The .fillColor property on line 6 and 7 is what I am currently manipulating to change the bounding box properties

Related

How to make a CAGradientLayer follow a CGPath

Given a CAShapeLayer defining a path as in the picture below, I want to add a CAGradientLayer that follows the path of the shape layer.
For example, given a gradient from black->red:
the top right rounded piece would be black,
and if the slider was at 100, the top left would be red,
and if the slider was at 50, then half the slider would be black (as below), and the visible gradient would go from black (top right) to a redish-black at the bottom
Every previous post I've found does not actually answer this question.
For example, because I can only add axial CAGradientLayers, I can kind-of do this (pic below), but you can see it's not correct (the top left ends up becoming black again). How do I make the gradient actually follow the path/mask
For the simple circular shape path, the new conic gradient is great. I was able to get this immediately (this is a conic gradient layer masked by a circle shape layer):
I used red and green so as to show the gradient clearly. This doesn't seem to be identically what you're after, but I can't believe it will be very difficult to achieve your goals now that .conic exists.
class MyGradientView : UIView {
override class var layerClass : AnyClass { return CAGradientLayer.self }
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
let lay = self.layer as! CAGradientLayer
lay.type = .conic
lay.startPoint = CGPoint(x:0.5,y:0.5)
lay.endPoint = CGPoint(x:0.5,y:0)
lay.colors = [UIColor.green.cgColor, UIColor.red.cgColor]
}
override func layoutSubviews() {
super.layoutSubviews()
let shape = CAShapeLayer()
shape.frame = self.bounds
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
let b = UIBezierPath(ovalIn: shape.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)))
shape.path = b.cgPath
shape.lineWidth = 10
shape.lineCap = .round
shape.strokeStart = 0.1
shape.strokeEnd = 0.9
shape.anchorPoint = CGPoint(x: 0.5, y: 0.5)
shape.transform = CATransform3DMakeRotation(-.pi/2, 0, 0, 1)
self.layer.mask = shape
}
}
Anybody on iOS 12 should go with Matt's suggestion or maybe use SFProgressCircle as DonMag suggested.
My solution:
I personally ended up adding two CAShapeLayers, each with a corresponding CAGradientLayer.
By programmatically splitting the slider in half as in the pic below, I was able to apply a top-to-bottom gradient on each side, which gives the effect I'm looking for. It's invisible to the user.

Aligning CAShapeLayer center of my UIView

I've been trying to solve this for days, and none of the suggestions solved my problem. I have a UIView inside a UITableView. I've been trying to draw my CAShapeLayer inside my UIView, but I just can't get it right.
I need my yellow CAShapeLayer to be exactly center within the gray UIView.
func DrawActivityRect(cell: CalorieDashboardTVCell){
let rectangle = UIBezierPath(rect: cell.calorieBurnUIView.bounds)
let trackLayer = CAShapeLayer()
trackLayer.frame = cell.calorieBurnUIView.bounds
trackLayer.path = rectangle.cgPath
trackLayer.position = cell.calorieBurnUIView.center
trackLayer.strokeColor = UIColor.yellow.cgColor
trackLayer.lineWidth = 10
trackLayer.fillColor = UIColor.clear.cgColor
trackLayer.lineCap = kCALineCapRound
cell.calorieBurnUIView.layer.addSublayer(trackLayer)
}
Result:
I suspect the cell size change after you have set the layer. The easiest place to fix this is in the cell's layoutSubviews(). Since your path is using absolute coordinates you need to update both the layer frame and the path.
override func layoutSubviews() {
super.layoutSubviews()
// You need to keep trackLayer around after you created it
let rectangle = UIBezierPath(rect: cell.calorieBurnUIView.bounds)
self.trackLayer.frame = cell.calorieBurnUIView.bounds
self.trackLayer.path = rectangle.cgPath
self.trackLayer.position = cell.calorieBurnUIView.center
}

drop shadow around border of UITextView to give it 3d effect in iOS/swift

Is there a way to drop a shadow around the border of a UITextView to give it a 3D effect? The textView has rounded corners.
I don't want to drop a shadow for the content of the textView (i.e. text). Just around the textView border only.
I need to clipToBounds on the textView for the rounded corners.
So far this is what I have tried:
let shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: textView.bounds, cornerRadius: 15).cgPath
shadowLayer.fillColor = UIColor.clear.cgColor
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 2, height: 2)
shadowLayer.shadowOpacity = 1
shadowLayer.shadowRadius = 2
textView.layer.addSublayer(shadowLayer)
This results in:
Reason : Clips to bounds = true and shadow on the same view doest not work simultaneous. So to sort out this you have to do follow.
Add your TextView in a UIView (says viewTextBG).
TextView Constraints : top bottom, leading, trailing = 0 wrt. viewTextBG.
Give corner radius to textview and viewTextBG
textview.cornerRadius = 10
viewTextBG.cornerRadius = 10
Give clipsToBounds to textview and viewTextBG
textview.clipsToBounds = True
viewTextBG.clipsToBounds = false
Now give shadow to viewTextBG.
Now everything works, thats all.

How to remove CALayer mask margin? + how to position UILabel properly?

I am trying to create the effect of the text color inversing while being intercepted by the background layer.
As you can see in the screenshot below, i have a blue CAShapeLayer moving from left to right and a mask layer directly attached to it, moving accordingly. Strangely there is a gap between the two layers.
My Code for the layers:
//Add Shape Layer
let path = UIBezierPath(rect: self.contentView.frame)
initPostion = -contentView.frame.size.width+initialVisibility
colorStripeLayer.path = path.CGPath
colorStripeLayer.fillColor = UIColor(red:0.71, green:0.86, blue:0.84, alpha:1.0).CGColor
colorStripeLayer.frame = self.contentView.frame
colorStripeLayer.transform = CATransform3DMakeTranslation(initPostion, 0, 0)
self.contentView.layer.insertSublayer(colorStripeLayer, atIndex: 0)
//white UILabel Masking
maskLayer.path = path.CGPath
maskLayer.fillColor = UIColor.lightGrayColor().CGColor
maskLayer.frame = self.contentView.bounds
Additionaly I wanted to place the white text exactly underneath the black one, but even after setting all the attributes, it still positions quite randomly.
Code for the labels:
textLabel?.layer.mask = maskLayer
textLabel?.backgroundColor = UIColor.clearColor()
textLabel?.textColor = UIColor.blackColor()
let whiteLabel = UILabel(frame: textLabel!.frame)
whiteLabel.text = textLabel!.text
whiteLabel.font = textLabel!.font
whiteLabel.textAlignment = textLabel!.textAlignment
whiteLabel.textColor = UIColor.whiteColor()
contentView.insertSubview(whiteLabel, belowSubview: textLabel!)
Animation is just a simple x-axis translation, done in pop.
Can anyone help here?
2 Problems here

How to draw horizontal bar graphs without showing axises

I need to implement a horizontal bar graph similar to the one shown below. Here I don't need to show axises along with the graph, still I need to imagine there is one:
How can I achieve this?
You can easily do this by using
UIBezierPath with CAShapeLayer
You can use the following function to draw an horizontal bar
func drawLine(startpoint start:CGPoint, endpint end:CGPoint, linecolor color: CGColor , linewidth widthline:CGFloat){
var path = UIBezierPath()
path.moveToPoint(start)
path.addLineToPoint(end)
var shapeLayer = CAShapeLayer()
shapeLayer.path = path.CGPath
shapeLayer.strokeColor = color
shapeLayer.lineWidth = widthline
view.layer.addSublayer(shapeLayer)
}
How to call this function in swift is
let start = CGPoint(x:20,y:100)
let end = CGPoint(x:200,y:100)
//red part of line
drawLine(startpoint: start, endpint: end,linecolor: UIColor.redColor().CGColor,linewidth:11.0)
You can find out complete code in here
http://bestarticlesall.blogspot.com/2014/12/draw-horizontal-bar-chart-using-swift.html

Resources