更新:如果我只将电路板设置为主视图,则不会发生这种情况。为什么会在子视图中发生这种情况?
我有一个视图,你有一个游戏板可以选择字符。为此,我将UIImageView放在游戏板上,并使用辅助函数绘制触摸线。然而,它在绘制线条时起作用,它前面的所有东西都会慢慢消失并向上移动。 它看起来像这样:
这就是绘制函数的样子,并且在移动的触摸中调用它:
//Helper function that draws a line which is used while the user is selecting letters
func drawLine(fromPoint: CGPoint, toPoint: CGPoint){
UIGraphicsBeginImageContext(drawingView.frame.size)
//get a context
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to get image context to draw line")
return
}
self.drawingView.image?.draw(in: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
//set the line
context.move(to: fromPoint)
context.addLine(to: toPoint)
//customize line
context.setLineCap(CGLineCap.round)
context.setLineWidth(4)
context.setStrokeColor(UIColor.blue.cgColor)
context.setBlendMode(CGBlendMode.normal)
//draw the line
context.strokePath()
drawingView.image = UIGraphicsGetImageFromCurrentImageContext()
//close
UIGraphicsEndImageContext()
//print("Drew Line")
}
以下是视图的所有代码:
/**
GameControllerDelegate is used to communicate when the user has chosen a word
*/
protocol GameControllerDelegate: AnyObject {
func wordPicked(letters: [String], moves: [(row: Int, column: Int)])
}
/**
GameViewDelegate is used to let the gameview know a user has picked a word using the board which is a subview
*/
protocol GameViewDelegate: AnyObject {
func wordPickedInBoard(letters: [String], moves: [(row: Int, column: Int)])
}
/**
Game view class holds all the subviews of the Game view as well as provides
getters and setters for each important data
*/
class GameView: UIView , GameViewDelegate{
//the board part
let boardView: BoardView = {
let boardView = BoardView()
boardView.backgroundColor = UIColor.white
boardView.translatesAutoresizingMaskIntoConstraints = true
return boardView
}()
//the score part
let scoreView: ScoreView = {
let scoreView = ScoreView()
scoreView.backgroundColor = UIColor.white
scoreView.translatesAutoresizingMaskIntoConstraints = true
return scoreView
}()
//two other vairables to assist in sizing the subviews
var minusTop: CGFloat = 0
var minusBottom: CGFloat = 0
//the board for the game
var board: [[String]] {
set
{
boardView.boardStrings = newValue
boardView.generateLabels()
setNeedsDisplay()
}
get { return boardView.boardStrings }
}
//the score
var score: Int {
set
{
scoreView.gameScore.text = " Score: " + String(newValue)
}
get
{
let indexStartOfNumber = scoreView.gameScore.text!.index((scoreView.gameScore.text!.startIndex), offsetBy: 9)
let numString = scoreView.gameScore.text?[indexStartOfNumber...]
return Int(String(describing: numString))!
}
}
//delegate for alerting the controller that a word was picked
var delegate: GameControllerDelegate? = nil
init(frame: CGRect, minusTop: CGFloat, minusBottom: CGFloat){
super.init(frame: frame)
boardView.delegate = self
self.minusTop = minusTop
self.minusBottom = minusBottom
addSubview(boardView)
addSubview(scoreView)
}
override init(frame: CGRect){
super.init(frame: frame)
boardView.delegate = self
addSubview(boardView)
addSubview(scoreView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
//manually layout the alarmpreview
override func layoutSubviews() {
var cursor: CGPoint = .zero
let scoreViewHeight = bounds.height/10
let boardHeight = bounds.height - minusTop - minusBottom - scoreViewHeight
cursor.y += minusTop
boardView.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: boardHeight)
cursor.y += boardHeight
scoreView.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: scoreViewHeight)
}
//function to catch when a word is picked in the board
func wordPickedInBoard(letters: [String], moves: [(row: Int, column: Int)]) {
//forward the info via the delegate
delegate?.wordPicked(letters: letters, moves: moves)
}
}
/**
Score view shows the users current score
*/
class ScoreView: UIView {
/*var scoreTitle: UILabel = {
let scoreTitle = UILabel()
scoreTitle.backgroundColor = UIColor.white
scoreTitle.text = "Score: "
return scoreTitle
}()*/
var gameScore: UILabel = {
let gameScore = UILabel()
gameScore.backgroundColor = UIColor.white
gameScore.text = " Score: 0"
return gameScore
}()
//init
override init(frame: CGRect){
super.init(frame: frame)
addSubview(gameScore)
//addSubview(scoreTitle)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
override func layoutSubviews() {
let cursor: CGPoint = .zero
gameScore.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: bounds.height)
}
}
/**
VoardView holds all the cells of the board and communicates when a user draws on it
*/
class BoardView: UIView {
var drawingView: UIImageView = {
let drawingView = UIImageView()
drawingView.backgroundColor = UIColor.white.withAlphaComponent(0.0)
return drawingView
}()
//delegate to communicate with the superview
var delegate: GameViewDelegate? = nil
//variables to aid in tracking the user moves
var lastPoint = CGPoint.zero
var looped = false
var boardStrings:[[String]] = []
var board:[[UILabel]] = Array(repeating: Array(repeating: UILabel(), count: 9), count: 12)
var curMoves: [(row: Int, column: Int)] = []
var highlightedArea: [(row: Int, column: Int)] = []
//centralized colors
let unHighlightedColor = UIColor.lightGray
let highlightedColor = UIColor.yellow
//Initialize this view
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
initBoard()
//self.boardStrings = generateBoard()
//generateLabels(boardStrings: self.boardStrings)
for i in 0...11 {
for j in 0...8 {
addSubview(board[i][j])
}
}
addSubview(drawingView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
//override the draw function, we draw the grid as well as the letters here
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to attain draw context")
return
}
//8 verticle lines
for i in 1 ... 9 {
let fromPoint = CGPoint(x: bounds.width * CGFloat(Double(i) * 1.0/9.0), y: 0)
let toPoint = CGPoint(x: bounds.width * CGFloat(Double(i) * 1.0/9.0), y: bounds.height)
context.move(to: fromPoint)
context.addLine(to: toPoint)
context.strokePath()
}
//draw 11 horizontal lines
for i in 1 ... 12 {
let fromPoint = CGPoint(x: 0, y: bounds.height * CGFloat(Double(i) * 1.0/12.0))
let toPoint = CGPoint(x: bounds.width, y: bounds.height * CGFloat(Double(i) * 1.0/12.0))
context.move(to: fromPoint)
context.addLine(to: toPoint)
context.strokePath()
}
}
//here we manually layout all the subviews that go into the preview
override func layoutSubviews() {
var cursor: CGPoint = .zero
let width = bounds.width/9
let height = bounds.height/12
for i in 0 ... 11 {
for j in 0 ... 8 {
board[i][j].frame = CGRect(x: cursor.x, y: cursor.y, width: width, height: height)
cursor.x += bounds.width * 1.0/9.0
}
cursor.x = 0
cursor.y += bounds.height * 1.0/12.0
}
drawingView.frame = self.bounds
}
//handle the beginning of a user move
override func touchesBegan(_ touches: Set<UITouch>, with: UIEvent?) {
looped = false
if let touch = touches.first as? UITouch {
lastPoint = touch.location(in: self)
//find what row we are in
let buttonHeight = bounds.height/12
let buttonWidth = bounds.width/9
let row: Int = Int(lastPoint.y/buttonHeight)
let column: Int = Int(lastPoint.x/buttonWidth)
curMoves.append((row: row, column: column))
highlightLabel(row: row, column: column)
setNeedsDisplay()
}
}
//handle when the user is moving. Calculate coordintes to drive the move the player is making
override func touchesMoved(_ touches: Set<UITouch>, with: UIEvent?) {
if !looped {
if let touch = touches.first as? UITouch {
let currentPoint = touch.location(in: self)
drawLine(fromPoint: lastPoint, toPoint: currentPoint)
//find what row we are in
let buttonHeight = bounds.height/12
let buttonWidth = bounds.width/9
let row: Int = Int(lastPoint.y/buttonHeight)
let column: Int = Int(lastPoint.x/buttonWidth)
if curMoves[curMoves.count - 1] != (row: row, column: column) {
//if the user is backstepping
if curMoves.count > 1 {
if curMoves[curMoves.count - 2] == (row: row, column: column) {
let pos = curMoves.remove(at: curMoves.count - 1)
unHeighlightLabel(row: pos.row, column: pos.column)
}
//if the user tried to make a loop
else if curMoves.contains(where: {$0 == (row: row, column: column)}){
for pos in curMoves {
unHeighlightLabel(row: pos.row, column: pos.column)
}
print("User tried to make a loop")
looped = true
}
else {
curMoves.append((row: row, column: column))
if board[row][column].backgroundColor != UIColor.green{
highlightLabel(row: row, column: column)
}
}
}
//if the user tried to make a loop
/*else if curMoves.contains(where: {$0 == (row: row, column: column)}){
for pos in curMoves {
unHeighlightLabel(row: pos.row, column: pos.column)
}
print("User tried to make a loop")
looped = true
}*/
else {
curMoves.append((row: row, column: column))
if board[row][column].backgroundColor != UIColor.green{
highlightLabel(row: row, column: column)
}
}
}
lastPoint = currentPoint
}
}
setNeedsDisplay()
}
//handle the end of a player move
override func touchesEnded(_ touches: Set<UITouch>, with: UIEvent?) {
if !looped {
//derive word
var word: [String] = []
for move in curMoves {
//if it contains blank put some garbage in there
if !boardStrings[move.row][move.column].contains("Blank") {
word.append(board[move.row][move.column].text!)
}
else {
word.append("###")
}
}
//let superview know
delegate?.wordPickedInBoard(letters: word, moves: curMoves)
}
//reset
for move in curMoves {
if board[move.row][move.column].backgroundColor != UIColor.green{
unHeighlightLabel(row: move.row, column: move.column)
}
}
curMoves = []
looped = false
drawingView.image = nil
setNeedsDisplay()
}
//Helper functions that changes the background color of the specified label to a centralized color
func highlightLabel(row: Int, column: Int){
board[row][column].backgroundColor = highlightedColor
}
func unHeighlightLabel(row: Int, column: Int) {
board[row][column].backgroundColor = unHighlightedColor
}
//Helper function that draws a line which is used while the user is selecting letters
func drawLine(fromPoint: CGPoint, toPoint: CGPoint){
UIGraphicsBeginImageContext(drawingView.frame.size)
//get a context
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to get image context to draw line")
return
}
self.drawingView.image?.draw(in: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
//set the line
context.move(to: fromPoint)
context.addLine(to: toPoint)
//customize line
context.setLineCap(CGLineCap.round)
context.setLineWidth(4)
context.setStrokeColor(UIColor.blue.cgColor)
context.setBlendMode(CGBlendMode.normal)
//draw the line
context.strokePath()
drawingView.image = UIGraphicsGetImageFromCurrentImageContext()
//close
UIGraphicsEndImageContext()
//print("Drew Line")
}
//helper function that initilizes the board layout
func initBoard() {
for i in 0 ... 11 {
for j in 0 ... 8 {
board[i][j] = UILabel()
board[i][j].text = ""
}
}
}
/**
This function takes the generated board strings and converts them into their proper labels
*/
func generateLabels() {
highlightedArea = []
for i in 0 ... 11 {
for j in 0 ... 8 {
//board[i][j] = UILabel()
board[i][j].textAlignment = .center
board[i][j].layer.borderColor = UIColor.black.cgColor
board[i][j].layer.borderWidth = 1.0;
if boardStrings[i][j].hasSuffix("^") {//.characters.contains("^"){
//highlight the label
board[i][j].backgroundColor = UIColor.green
//set the text
let index = boardStrings[i][j].index(boardStrings[i][j].startIndex, offsetBy: boardStrings[i][j].count - 1)
let range = boardStrings[i][j].startIndex..<index
let letter = String(boardStrings[i][j][range])
board[i][j].backgroundColor = UIColor.green
board[i][j].text = letter
highlightedArea.append((row: i, column: j))
}
else if boardStrings[i][j] != "Blank" {
board[i][j].backgroundColor = unHighlightedColor
board[i][j].text = boardStrings[i][j]
}
else {
//leave it blank
board[i][j].backgroundColor = unHighlightedColor
board[i][j].text = ""
}
}
}
}
}
答案 0 :(得分:0)
最近遇到了同样的问题。可能为时已晚,不能为您提供帮助,但是希望有人有一天会发现这很有用。
在设置图像视图的边界(要绘制到的图像视图)时,使用floor()作为高度和宽度对我来说很有效。这是在目标C中执行的吗...不知道等效的floor()。