简体   繁体   中英

How to draw a line in the simplest way in swift

I am fairly new to swift and Xcode and I am trying to make a tic tac toe game. I have everything figured out except how to draw a line through the three x's or o's. I have no idea on how to draw lines. I have looked on the web for the answer and can't figure it out.

Try looking into UIBezierPath, it will help you a lot for drawing lines. Here is documentation . Here is an example:

override func drawRect(rect: CGRect) {
    let aPath = UIBezierPath()

    aPath.move(to: CGPoint(x:<#start x#>, y:<#start y#>))
    aPath.addLine(to: CGPoint(x: <#end x#>, y: <#end y#>))

    // Keep using the method addLine 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.red.set()
    aPath.lineWidth = <#line width#>
    aPath.stroke()
}

Make sure you put this code in the drawRect , like in the example above.

If you need to update the drawing just call setNeedsDisplay() to update.

Update for Swift 3.x using Epic Defeater's example

override func draw(_ rect: CGRect) {
        let aPath = UIBezierPath()

        aPath.move(to: CGPoint(x:20, y:50))

        aPath.addLine(to: CGPoint(x:300, y:50))

        //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.red.set()
        aPath.stroke()
        //If you want to fill it as well
        aPath.fill()
    }

The questioner isn't really asking what code to use, he is asking where to put the code. It's actually a good question because if you put any of the graphics code in the 'wrong' place, nothing at all will be drawn. The 'wrong' place to put the code is in a class that is not a subclass of UIView . If you try doing that, the code will compile but when it runs, the call to get the graphics context will fail and the calls to the following graphics functions, such as context?.move() , will not run because the context is nil .

As an example, let's create a storyboard with a View, a Button and a Label by dragging the respective objects from the Object Library onto the storyboard. My example looks like this, where the white square is the View (actually a sub-view because the main screen is also a view):

在此处输入图像描述

It's possible to draw graphics on Button and Label controls (and the other types of UI controls) because UIButton and UILabel are subclasses of UIView .

I also created a new file in the project, of type Swift, and called it ExampleDraw.swift and put the following code in it. The code contains three classes to write graphics on the view, button and label. Each class overrides the draw() function in the base UIView class:

import UIKit

class DrawOnView: UIView {
    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setLineWidth(2.0)
        context?.setStrokeColor(UIColor.blue.cgColor)
        context?.move(to: CGPoint(x:0, y: 0))
        context?.addLine(to: CGPoint(x: 20, y: 30))
        context?.strokePath()

        print("in DrawOnView")
    }
}

class DrawOnButton: UIButton {
    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setLineWidth(4.0)
        context?.setStrokeColor(UIColor.green.cgColor)
        context?.move (to: CGPoint(x: 0, y: 0))
        context?.addLine (to: CGPoint(x: 40, y: 45))
        context?.strokePath()

        print("in DrawOnButton")
    }
}

class DrawOnLabel: UILabel {
    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setLineWidth(1.0)
        context?.setStrokeColor(UIColor.red.cgColor)
        context?.move (to: CGPoint(x: 0, y: 0))
        context?.addLine (to: CGPoint(x: 35, y: 45))
        context?.strokePath()

        print("in DrawOnLabel")
    }
}

Then in the main storyboard, select the view, like this:

在此处输入图像描述

Then open the Identity Inspector and associate this view with the custom class (ie the first class in E xampleDraw.swift ) called DrawOnView() like this:

在此处输入图像描述

Do the same for the Button and the Label, like this:

在此处输入图像描述

在此处输入图像描述

Then run the project in the simulator and hopefully the graphics will write on the view, button and label like this:

在此处输入图像描述

Swift 3.1 , inside a UIView:

public override func draw(_ rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()
    context!.setLineWidth(2.0)
    context!.setStrokeColor(UIColor.red.cgColor)
    context?.move(to: CGPoint(x: 0, y: self.frame.size.height))
    context?.addLine(to: CGPoint(x: self.frame.size.width, y: 0))
    context!.strokePath()
}

If you want to add a line to a UIViewController, just add a UIView with this function as a subview to the UIViewController, ei:

let line = LineView(CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
self.view.addSubview(line)

I've been struggling on this topic too. In XCode 7.3.1, with Swift version 2.2, the simplest way to draw a line is to create a playground and insert this code in it. Hope this helps other people with this simple task in mind.

import UIKit
import XCPlayground

public class SimpleLine: UIView  {

    public init() {
        super.init(frame: CGRect(x: 0, y: 0, width: 480, height: 320))
        backgroundColor = UIColor.whiteColor()
    }

    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public override func drawRect(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        CGContextSetLineWidth(context, 4.0)
        CGContextSetStrokeColorWithColor(context, UIColor.darkGrayColor().CGColor)
        CGContextMoveToPoint(context, 100, 100)
        CGContextAddLineToPoint(context, 300, 300)
        CGContextStrokePath(context)
    }

}

let firstLine = SimpleLine()

XCPlaygroundPage.currentPage.liveView = firstLine

Edit: Update for Xcode 10.1 with Swift version 4.2.1

import UIKit
import PlaygroundSupport

public class SimpleLine: UIView  {

    public init() {
        super.init(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
        backgroundColor = .white
    }

    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else { return }
        context.setLineWidth(4.0)
        context.setStrokeColor(UIColor.darkGray.cgColor)
        context.move(to: CGPoint(x: 40, y: 40))
        context.addLine(to: CGPoint(x: 280, y: 300))
        context.strokePath()
    }
}

PlaygroundPage.current.liveView = SimpleLine()

Simple SWIFT 4.1 Implementation:

public override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }
    let lineWidth: CGFloat = 1.0
    context.setLineWidth(lineWidth)
    context.setStrokeColor(UIColor(style: .tertiaryBackground).cgColor)
    let startingPoint = CGPoint(x: 0, y: rect.size.height - lineWidth)
    let endingPoint = CGPoint(x: rect.size.width, y: rect.size.height - lineWidth)
    context.move(to: startingPoint )
    context.addLine(to: endingPoint )
    context.strokePath()
}

Obviously, you need to adjust the starting and ending point.

Are you using SpriteKit? If not, you really should do for any kind of iOS games as it makes manipulating and adding sprites (images) and other game-style objects very easy.

Although not at all the best way in terms of coding best-practices, a very simple way to accomplish this would be to create a new view when someone wins, check which direction (out of the possible 8) the row is and then set the image of this view accordingly. The images would be semi-transparent (eg PNGs) squares each containing a different possible line.

If you want to do it the proper way research how to draw paths in SpriteKit between coordinates.

Hope this is of some help! Steve

In general, you have to draw a path in Core Graphics. You can follow this example:

let context = UIGraphicsGetCurrentContext()
CGContextSetLineWidth(context, 2.0)
CGContextSetStrokeColorWithColor(context, color)
CGContextMoveToPoint(context, startPoint)
CGContextAddLineToPoint(context, endPoint)
CGContextStrokePath(context)

Drawing in Swift 4.1

override func viewDidLoad() {
    super.viewDidLoad()
     self.lastPoint = CGPoint.zero
     self.red = 0.0
     self.green = 0.0
     self.blue = 0.0

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


//MARK: Touch events
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    isSwiping    = false
    if let touch = touches.first{
        lastPoint = touch.location(in: mainImageView)
    }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    isSwiping = true;
    if let touch = touches.first{
        let currentPoint = touch.location(in: mainImageView)
        UIGraphicsBeginImageContext(self.tempImageView.frame.size)
        self.tempImageView.image?.draw(in: CGRect(x:0, y:0,width:self.tempImageView.frame.size.width, height:self.tempImageView.frame.size.height))

        UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
        UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: currentPoint.x, y: currentPoint.y))

        UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round)
        UIGraphicsGetCurrentContext()?.setLineWidth(9.0)
        UIGraphicsGetCurrentContext()?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
        UIGraphicsGetCurrentContext()?.strokePath()


        self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        lastPoint = currentPoint
    }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if(!isSwiping) {
        // This is a single touch, draw a point
        UIGraphicsBeginImageContext(self.tempImageView.frame.size)
        self.tempImageView.image?.draw(in: CGRect(x:0, y:0,width:self.tempImageView.frame.size.width, height:self.tempImageView.frame.size.height))
        UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round)
        UIGraphicsGetCurrentContext()?.setLineWidth(9.0)

        UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
        UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
        UIGraphicsGetCurrentContext()?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
        UIGraphicsGetCurrentContext()?.strokePath()
        self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
}

Quick and dirty fix in Storyboard:

在此处输入图像描述

  1. Create a UIView
  2. Set the background color to the color you want
  3. Set height constraint to the line width you want
import UIKit

@IBDesignable class DrawView: UIView {

    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setLineWidth(2.0)
        context?.setStrokeColor(UIColor.red.cgColor)
        context?.move(to: CGPoint(x: 210, y: 30))
        context?.addLine(to: CGPoint(x: 300, y: 200))
        context?.addLine(to: CGPoint(x: 100, y: 200))
        context?.addLine(to: CGPoint(x: 210, y: 30))
        context?.strokePath()
    } 

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM