快速绘制时线条褪色

时间:2018-03-17 04:02:06

标签: swift4

更新:如果我只将电路板设置为主视图,则不会发生这种情况。为什么会在子视图中发生这种情况?

我有一个视图,你有一个游戏板可以选择字符。为此,我将UIImageView放在游戏板上,并使用辅助函数绘制触摸线。然而,它在绘制线条时起作用,它前面的所有东西都会慢慢消失并向上移动。 它看起来像这样: enter image description here

这就是绘制函数的样子,并且在移动的触摸中调用它:

//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 = ""
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

最近遇到了同样的问题。可能为时已晚,不能为您提供帮助,但是希望有人有一天会发现这很有用。

在设置图像视图的边界(要绘制到的图像视图)时,使用floor()作为高度和宽度对我来说很有效。这是在目标C中执行的吗...不知道等效的floor()。