如何在 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()
}
问题出在 drawRect
中 frame
的设置。如果您为视图定义了任何自动布局约束,这将尤其成为一个问题。
视图的布局和视图的绘制是两个不同的步骤,因此您应该将逻辑分开。
就我个人而言,我会在视图上设置自动布局约束,以确保它是方形的、居中的并且具有正确的间距。那么视图渲染就简化了:
@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)
}
}
产量:
很明显,对你的水平分隔符也重复一遍。
在我的 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()
}
问题出在 drawRect
中 frame
的设置。如果您为视图定义了任何自动布局约束,这将尤其成为一个问题。
视图的布局和视图的绘制是两个不同的步骤,因此您应该将逻辑分开。
就我个人而言,我会在视图上设置自动布局约束,以确保它是方形的、居中的并且具有正确的间距。那么视图渲染就简化了:
@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)
}
}
产量:
很明显,对你的水平分隔符也重复一遍。