如何在 swift 中将井字棋盘绘制为 UIView?

how to draw tic tac toe board as UIView in swift?

在我的 UIViewController 中,我有一个 UIView 的子类,我将在其中绘制井字棋盘。不知何故,我使用 UIBezierPath() 绘制的分隔线(“#”形状)没有均匀地划分电路板。垂直分隔线不是 1/3-1/3-1/3,而是更接近 45%-45%-10%,即使打印输出的尺寸有意义。我错过了什么?谢谢

在我的子类中:

import UIKit

@IBDesignable class GameBoardView: UIView {

    override func drawRect(rect: CGRect) {

        // set up gameBoard dimensions everytime drawRect() is called
        setUpGameBoardCells()
        self.frame = CGRectMake(gameBoardPosX, gameBoardPosY, gameBoardLength, gameBoardLength)
        print("gameBoard.frame: x=\(self.frame.origin.x), y=\(self.frame.origin.y), h=\(self.frame.height), w=\(self.frame.width)\n")

        // draw dividers & cells
        var divider = UIBezierPath(rect: CGRect(x: cellWidth, y: 0, width: dividerWidth, height: gameBoardLength))
        divider.lineWidth = 1
        UIColor.orangeColor().setStroke()
        divider.stroke()

        divider = UIBezierPath(rect: CGRect(x: cellWidth * 2 + dividerWidth, y: 0, width: dividerWidth, height: gameBoardLength))
        divider.stroke()
   }
}

这就是我设置尺寸以处理任何尺寸屏幕的方式:

var screenSize = CGRect()
let screenMargin: CGFloat = 20   // to the edge

var gameBoardIsPortrait = Bool()
var gameBoardLength = CGFloat()
var gameBoardPosX = CGFloat()
var gameBoardPosY = CGFloat()

let cellsPerRow: Int = 3
var cellWidth = CGFloat()
let dividerWidthGuide: CGFloat = 0.02   // guideline % of gameBoardLength
var dividerWidth = CGFloat()

let debugPrint = true

func setUpGameBoardCells() {

    screenSize = UIScreen.mainScreen().bounds

    // gameBoard is a square
    gameBoardIsPortrait = (screenSize.height >= screenSize.width ? true : false)
    gameBoardLength = min(screenSize.height, screenSize.width) - screenMargin * 2
    gameBoardPosX = (screenSize.width - gameBoardLength) / 2
    gameBoardPosY = (screenSize.height - gameBoardLength) / 2

    // want cells & dividers on gameBoard to be whole numbers
    dividerWidth = round(gameBoardLength * dividerWidthGuide)
    let cellsTotalWidth: Int = Int(gameBoardLength) - Int(dividerWidth) * (cellsPerRow - 1)
    let dividerWidthFudge: CGFloat = (cellsTotalWidth % cellsPerRow == 1 ? -1 : (cellsTotalWidth % cellsPerRow == 2 ? 1 : 0))
    dividerWidth += dividerWidthFudge
    cellWidth = CGFloat((cellsTotalWidth - Int(dividerWidthFudge) * (cellsPerRow - 1)) / cellsPerRow)

    if debugPrint {
        print("setUpCellDivision()->\nscreen: h=\(screenSize.height), w=\(screenSize.width)")
        print("gameBoardIsPortrait=\(gameBoardIsPortrait), gameBoardLength=\(gameBoardLength), gameBoardPosX=\(gameBoardPosX), gameBoardPosY=\(gameBoardPosY)")
        print("cellWidth=\(cellWidth), dividerWidth=\(dividerWidth)\n")
    }
}

奇怪的是 xcode 看起来是对的:

但在模拟器中它看起来像这样:

看来您的约束设置不正确。尝试重做约束以查看是否可以解决问题。

最简单的方法是在黄色 UIView 上添加 UIView(作为分隔线)并适当地约束它们。你不必写太多 code.I 会建议避免在这种情况下使用代码。

你可以试试这个。通过计算视图的框架来绘制线条。下面会根据frame调整大小

func drawRect(frame frame: CGRect = CGRect(x: 52, y: 30, width: 90, height: 75)) {

    //// Bezier Drawing
    let bezierPath = UIBezierPath()
    UIColor.blackColor().setStroke()
    bezierPath.lineWidth = 1
    bezierPath.stroke()


    //// Rectangle Drawing
    let rectanglePath = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.32778) + 0.5, y: frame.minY + floor(frame.height * 0.06000) + 0.5, width: floor(frame.width * 0.35000) - floor(frame.width * 0.32778), height: floor(frame.height * 0.92667) - floor(frame.height * 0.06000)))
    UIColor.blackColor().setStroke()
    rectanglePath.lineWidth = 1
    rectanglePath.stroke()


    //// Rectangle 3 Drawing
    let rectangle3Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.68333) + 0.5, y: frame.minY + floor(frame.height * 0.06000) + 0.5, width: floor(frame.width * 0.70556) - floor(frame.width * 0.68333), height: floor(frame.height * 0.92667) - floor(frame.height * 0.06000)))
    UIColor.blackColor().setStroke()
    rectangle3Path.lineWidth = 1
    rectangle3Path.stroke()


    //// Rectangle 5 Drawing
    let rectangle5Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.07222) + 0.5, y: frame.minY + floor(frame.height * 0.63333) + 0.5, width: floor(frame.width * 0.92778) - floor(frame.width * 0.07222), height: floor(frame.height * 0.66000) - floor(frame.height * 0.63333)))
    UIColor.blackColor().setStroke()
    rectangle5Path.lineWidth = 1
    rectangle5Path.stroke()


    //// Rectangle 6 Drawing
    let rectangle6Path = UIBezierPath(rect: CGRect(x: frame.minX + floor(frame.width * 0.07222) + 0.5, y: frame.minY + floor(frame.height * 0.31333) + 0.5, width: floor(frame.width * 0.92778) - floor(frame.width * 0.07222), height: floor(frame.height * 0.34000) - floor(frame.height * 0.31333)))
    UIColor.blackColor().setStroke()
    rectangle6Path.lineWidth = 1
    rectangle6Path.stroke()
}

问题出在 drawRectframe 的设置。如果您为视图定义了任何自动布局约束,这将尤其成为一个问题。

视图的布局和视图的绘制是两个不同的步骤,因此您应该将逻辑分开。

就我个人而言,我会在视图上设置自动布局约束,以确保它是方形的、居中的并且具有正确的间距。那么视图渲染就简化了:

@IBDesignable class GameBoardView: UIView {

    override func drawRect(rect: CGRect) {
        setUpGameBoardCells()

        UIColor.orangeColor().setStroke()

        var divider = UIBezierPath(rect: CGRect(x: cellWidth, y: 0, width: dividerWidth, height: bounds.size.height))
        divider.lineWidth = 1
        divider.stroke()

        divider = UIBezierPath(rect: CGRect(x: cellWidth * 2 + dividerWidth, y: 0, width: dividerWidth, height: bounds.size.height))
        divider.lineWidth = 1
        divider.stroke()
    }

    let cellsPerRow = 3
    let dividerWidthGuide: CGFloat = 0.02   // guideline % of gameBoardLength

    var cellWidth: CGFloat!
    var cellHeight: CGFloat!
    var dividerWidth: CGFloat!

    func setUpGameBoardCells() {
        let gameBoardLength = min(bounds.size.height, bounds.size.width)
        dividerWidth = round(gameBoardLength * dividerWidthGuide)
        let cellsTotalWidth: Int = Int(gameBoardLength) - Int(dividerWidth) * (cellsPerRow - 1)
        let dividerWidthFudge: CGFloat = (cellsTotalWidth % cellsPerRow == 1 ? -1 : (cellsTotalWidth % cellsPerRow == 2 ? 1 : 0))
        dividerWidth! += dividerWidthFudge
        cellWidth = CGFloat((cellsTotalWidth - Int(dividerWidthFudge) * (cellsPerRow - 1)) / cellsPerRow)
    }

}

产量:

很明显,对你的水平分隔符也重复一遍。