2016-07-14 37 views
1

In meiner UIViewController habe ich eine einzelne Unterklasse von UIView, in der ich ein Tic Tac Toe Board zeichnen werde. Irgendwie teilen die Teiler (die "#" Form), die ich mit UIBezierPath() zeichne, die Tafel nicht gleichmäßig. Anstelle von 1/3-1/3-1/3 liegen die vertikalen Teiler näher bei 45% -45% -10%, obwohl die Ausdrucke der Abmessungen sinnvoll sind. Was vermisse ich? DankWie zeichnet man Tic Tac Toe Board als UIView in swift?

In meiner Unterklasse:

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() 
    } 
} 

Und das ist, wie ich die Dimensionen eingerichtet jeder Größe Bildschirme zu handhaben:

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") 
    } 
} 

Was seltsam ist, dass in Xcode es sieht recht:

enter image description here

Aber im Simulator sieht es aus dies wie:

enter image description here

Antwort

1

Das Problem ist die Einstellung des frame aus drawRect. Dies ist insbesondere dann ein Problem, wenn Sie für die Ansicht definierte automatische Layouteinschränkungen definiert haben.

Das Layout einer Ansicht und die Zeichnung dieser Ansicht sind zwei verschiedene Schritte, und Sie sollten diese Logik daher trennen.

Persönlich würde ich automatische Layout-Einschränkungen für die Ansicht einrichten, um sicherzustellen, dass es quadratisch, zentriert und mit dem richtigen Abstand ist. Dann wird die Ansicht Rendering vereinfacht:

@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) 
    } 

} 

Das ergibt:

enter image description here

ist klar, nur für Ihre horizontale Trennlinien wiederholen, auch.

+0

Hallo Rob, vielen Dank für Ihre Antwort. Ich bestätige, indem ich CGRectMake() aus drawRect() heraushole, die Teiler nun an den richtigen Stellen erscheinen. Wenn ich immer noch die Größe des Boards programmgesteuert ändern und an einen bestimmten Ort verschieben möchte, wo sollte ich den Aufruf von CGRectMake() einfügen? Ich habe versucht, es in ViewWillAppear() in meinem ViewController zu setzen, aber das scheint nicht zu funktionieren. Danke – rockhammer

+1

Sie konfigurieren das 'frame' wie Sie jede andere Ansicht.Wenn Sie das automatische Layout verwenden und es in einem Storyboard hinzugefügt haben, fügen Sie einfach Outlets für die Constraints hinzu, und Sie können dann die Eigenschaft "constant" der Constraints entsprechend anpassen. Der Schlüssel ist, dass wenn Sie das automatische Layout verwenden, der 'Rahmen' nicht direkt angepasst wird. Passen Sie die Einschränkungen an. – Rob

+0

Einschränkungen! Na sicher. Danke, Rob, ich habe es gerade zur Arbeit gebracht. – rockhammer

0

Es scheint, als ob Ihre Zwänge sind nicht richtig eingerichtet. Versuchen Sie, die Einschränkungen zu wiederholen, um zu sehen, ob das Dinge behebt.

+0

Ich habe absichtlich keine Einschränkungen hinzugefügt, da ich die Größe der Karte programmgesteuert ändere und neu positioniere. – rockhammer

+0

oh richtig! Mein Entschuldigung, in diesem Fall versuchen Sie selbst vor der Bildschirmgröße – Konsy

1

Der einfachste Weg wäre, UIViews (als Trennlinien) in die gelbe UIView einzufügen und sie richtig zu beschränken. Sie müssen nicht zu viel Code schreiben. Ich würde vorschlagen, den Code in solchen Fällen zu vermeiden.

Sie können dies versuchen. Zeichnen Sie die Linien, indem Sie den Rahmen der Ansicht berechnen. Die folgende Größe wird entsprechend dem Rahmen angepasst.

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() 
} 

enter image description here