Ios - Is there a way to draw a line in UIViewController without using code - ios

I want to draw a line in UIViewController without using code, so like the constraints for the lines can be given in storyboard itself. if there is a way to do it, please tell me. Now i have drawn a line by placing an UIView in storyboard and used the following code to draw line on it. Is this the best way ?. Or do i have any better way ?. Thanks in advance.
class line: UIView {
override func draw(_ rect: CGRect) {
let aPath = UIBezierPath()
aPath.move(to: CGPoint(x:0, y:1))
aPath.addLine(to: CGPoint(x:500, y:1))
//Keep using the method addLineToPoint until you get to the one where about to close the path
aPath.close()
//If you want to stroke it with a red color
UIColor.blue.set()
aPath.stroke()
//If you want to fill it as well
aPath.fill()
}
}
Using Swift 3.0 and Xcode 8.2

Use #IBDesignable as follows. Make your view with height of one as suggested and the #IBDesignable will show your line in your storyboard.:
import UIKit
#IBDesignable class line: UIView {
override func draw(_ rect: CGRect) {
let aPath = UIBezierPath()
aPath.move(to: CGPoint(x: 0, y: 1))
aPath.addLine(to: CGPoint(x: 250, y: 1))
aPath.close()
UIColor.blue.set()
aPath.stroke()
}
}

Add a UIView with a height of 1 point.
Add constraints for it.

Related

Why does CGContext not work in UITableViewCell on iOS 14?

Drawing lines doesn't work on iOS 14.
I create a subclass of UITableViewCell.
I want to draw two lines in the custom cell.
The code is below.
override func draw(_ rect: CGRect) {
super.draw(rect);
guard let context = UIGraphicsGetCurrentContext() else { return }
context.saveGState() // Save state. This includes transformations and clips
context.setLineWidth(8.0)
let lineColor = UIColor.red
let bgColor = UIColor.lightGray
context.setStrokeColor(bgColor.cgColor)
context.move(to: CGPoint(x: 86.0, y: 42))
context.addLine(to: CGPoint(x: (86.0 + 120.0), y: 42))
context.setLineCap(.round)
context.strokePath()
context.setLineWidth(8.0)
context.setStrokeColor(lineColor.cgColor)
context.move(to: CGPoint(x: 86.0, y: 42))
context.addLine(to: CGPoint(x: (86.0 + 120.0 * self.lineScale ), y: 42))
context.setLineCap(.round)
context.strokePath()
context.restoreGState() // Put back state. This includes transformations and clips
}
It works well on iOS 12. It doesn't work on iOS 14. (I don't know whether it works on iOS 13).
I don't know what I can do to solve this issue.
Do you know the reason? Can you fix it?
You should not be trying to override draw(_ rect: CGRect) for a table view cell to begin with. Cells have subviews, which have subviews, and the cell itself does a lot more than just "be there."
If you use Debug View Hierarchy you will see what's going wrong, and it will reinforce why that's a bad idea.
With iOS 14 the cell structure changed and you should only be manipulating the cell's .contentView -- not the cell itself.
Much better to make that a custom view which is added to the content view.
You shouldn't override the draw(_ rect: CGRect) of a table cell. Instead, create a new custom view and add it to the cell's contentView, and draw in there.
You should instead create your UIView and add it as a subview of the contentView property. There are many questions/answers on here and across the web about drawRect: and UITableViewCell, most of them suggest that you do not do it.

iOS Swift draw to screen

I am new to iOS development and need help from someone a bit more experienced than me. I searched the internet and couldn't find any working solution.
I need to draw to the screen like canvas in Android. Currently I have a CADisplayLink to call a function every frame. And that's working well. The problem is: How do I actually draw anything, like a rectangle, a circle or a line to the screen every frame?
This is what I have (I linked this class to the view in the storyboard):
class Canvas: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineWidth(2.0)
context?.setStrokeColor(UIColor.green.cgColor)
context?.move(to: CGPoint(x: 30, y: 30))
context?.addLine(to: CGPoint(x: Double(xBall), y: Double(yBall)))
context?.strokePath()
}
}
With the following code I can actually draw a line to the screen:
let canvas = Canvas()
canvas.draw(CGRect())
The problem is, that this works exactly ONE time. When I have canvas.draw(CGRect()) in my loop which repeats every frame, it works for the first frame (the initial values of xBall and yBall) and never again. When I print the values in the draw method, it gets called every frame and the variables have the correct values. But it does not draw it to the screen. I tried adding the line setNeedsDisplay() in the draw method, with similar results.
Any help will be appreciated! Thanks!
If you refer to the draw(_:) documentation, it says:
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay() or setNeedsDisplay(_:) method instead.
The common approach would be to have your view controller viewDidLoad method add Canvas view:
override func viewDidLoad() {
super.viewDidLoad()
let canvas = Canvas()
canvas.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(canvas)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
You don’t call draw(_:) yourself, but rather the OS will do so automatically. All you need to do is add it to your view hierarchy with addSubview(_:). And you can then just have your CADisplayLink update the properties and call setNeedsDisplay (or, better, add didSet observers to those properties that calls setNeedsDisplay for you).
By the way, if you don’t want to add this programmatically, like shown above, you can add Canvas right in Interface Builder. Just drag a UIView onto your storyboard scene, add all of the appropriate constraints, go to the “identity” inspector, and set the base class name to be Canvas:
And if you mark your class as #IBDesignable, you can actually see your path rendered right in Interface Builder, like shown above.
A number of refinements:
If you are going to implement draw(_:) yourself, instead of getting a graphics context with UIGraphicsGetCurrentContext, you might just stroke a UIBezierPath:
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 30, y: 30))
path.addLine(to: CGPoint(x: xBall, y: yBall))
path.lineWidth = 2
UIColor.green.setStroke()
path.stroke()
}
Like your solution, this requires that after you update xBall and yBall, if you call setNeedsDisplay to have the view re-rendered with the updated path.
Sometimes we wouldn’t even implement draw(_:). We would just add a CAShapeLayer as a sublayer:
#IBDesignable
class Canvas: UIView {
var xBall = ...
var yBall = ...
let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 2
return shapeLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
func configure() {
layer.addSublayer(shapeLayer)
updatePath()
}
func updatePath() {
let path = UIBezierPath()
path.move(to: CGPoint(x: 30, y: 30))
path.addLine(to: CGPoint(x: xBall, y: yBall))
shapeLayer.path = path.cgPath
}
}
In this sort of approach, you just update the path of the shapeLayer and the OS will render your shape layer (and its path) for you.

BlurView below a button with fading edges

I created a button on top of my mapView.
In order to make that Button more visible I added a blur view below that button.
I don't like the sharp edges of my blur view.
How do I make the blur fade out slowly transitioning into the mapView?
EDIT: To be more specific. I mean a fading blurred gradient with round corners.
I think this can help you, first you need subclass your button and add this code in drawRect and replace UIColor.blueColor().CGColor by yourColor.CGColor
class UICustomBackgroundButton: UIButton {
override func draw(_ rect: CGRect) {
// Drawing code
super.draw(rect)
let ctx = UIGraphicsGetCurrentContext();
let path = CGPath(roundedRect: rect.insetBy(dx: self.frame.size.height/4, dy: self.frame.size.height/4) , cornerWidth: self.frame.size.height/8, cornerHeight: self.frame.size.height/8, transform: nil)
ctx?.setShadow(offset: CGSize.zero, blur: self.frame.size.height/4, color: UIColor.blue.cgColor);
ctx?.setFillColor(UIColor.blue.cgColor);
//if number of cicles is our glow is darker
for _ in 0..<6
{
ctx?.addPath(path);
ctx?.fillPath();
}
}
}
I Hope this helps you.
and this is how it look
Have you tried the cornerRadius property? That should remove the sharp edges

Filing UIBezierPath in Swift

How can I color the inside of the UIBezier path? I am making a simple triangle and want to color inside of the triangle with red color.
class GraphView : UIView {
override func drawRect(rect: CGRect) {
UIColor.redColor().setFill()
UIColor.greenColor().setStroke()
let path = UIBezierPath(rect: rect)
path.moveToPoint(CGPointMake(100,620))
path.addLineToPoint(CGPointMake(300,100))
path.addLineToPoint(CGPointMake(500,620))
path.addLineToPoint(CGPointMake(100,620))
path.closePath()
path.fill()
path.stroke()
}
}
let graphView = GraphView(frame: CGRectMake(0,0,960,640))
XCPlaygroundPage.currentPage.liveView = graphView
The above code is written in the playground: Here is the result:
The problem is with how you're creating your UIBezierPath. You're creating it with a rectangle of the view's bounds, and then adding a triangle inside that rectangle. Therefore they're both getting filled – resulting in the entire view being red.
If you set usesEvenOddFillRule to true, you'll better see the result of the unwanted rectangle in your path:
If you just want to fill a triangle then replace this line:
let path = UIBezierPath(rect: rect)
with this:
let path = UIBezierPath()
This will create a new empty UIBezierPath that you can add your triangle to.

How to set border edges in HorizontalBarChartView

I need help creating this style BarChart, only the rounded end edges.
Here is an example:
I'm using the library "ios-charts" but it does not have this feature. Please let me know how to do this - rounded end edges and horizontal bar chart with negative values.
It's not that that hard to draw bars that like that yourself. Perhaps fork that library and improve it and make a push request. Here's some simple code that draws a red bar pointing to the right.
import UIKit
#IBDesignable
class RoundedBarView: UIView {
override func drawRect(rect: CGRect) {
let color = UIColor.redColor()
let barRect = CGRectMake(0.0,0.0,self.bounds.width, self.bounds.height)
var rectanglePath = UIBezierPath(roundedRect: barRect, byRoundingCorners: UIRectCorner.TopRight | UIRectCorner.BottomRight, cornerRadii: CGSizeMake(barRect.height/2.0, barRect.height/2.0))
rectanglePath.closePath()
color.setFill()
rectanglePath.fill()
}
}

Resources