Как нарисовать этот значок флажка с помощью UIBezierPath? - PullRequest
0 голосов
/ 26 апреля 2018

Я работаю над созданием некоторых пользовательских кнопок для приложения, есть несколько значков, и я разработал их все в теории, но у меня возникают проблемы с выяснением, как нарисовать этот надоедливый значок "флажок" в iOS 'Язык UIBezierPath.

Как правило, границы значка - 5 x 5, а границы графического объекта, содержащегося внутри значка, - 3 x 3. (Да, я знаю, что флажок выходит за пределы3 x 3 границы).

Здесь есть и значок флажка, и значок «плюс» (Да, я играю с Corel DRAW 12, ну и что ...):

enter image description here

Видите ли, значок «плюс», я не мог сделать никаких проблем, как это:

class BezierPathFactory {


    // "gridSpacing" is expected to be the containing view's width / 5
    static func plus(gridSpacing G: CGFloat) -> UIBezierPath {

        let path = UIBezierPath()

        let startPoint = CGPoint(x:2*G,y:G)

        path.move(to: startPoint)
        path.addLine(to: CGPoint(x:2*G,y:2*G))
        path.addLine(to: CGPoint(x:G,y:2*G))
        path.addLine(to: CGPoint(x:G,y:3*G))
        path.addLine(to: CGPoint(x:2*G,y:3*G))
        path.addLine(to: CGPoint(x:2*G,y:4*G))
        path.addLine(to: CGPoint(x:3*G,y:4*G))
        path.addLine(to: CGPoint(x:3*G,y:3*G))
        path.addLine(to: CGPoint(x:4*G,y:3*G))
        path.addLine(to: CGPoint(x:4*G,y:2*G))
        path.addLine(to: CGPoint(x:3*G,y:2*G))
        path.addLine(to: CGPoint(x:3*G,y:G))
        path.addLine(to: startPoint)

        path.close()

        return path

}

// ...

}

Но, значок флажка заставляет мою голову болеть такплохо.

До сих пор я установил следующее:

  1. Соотношение длины и ширины (повернуто на 45 градусов по часовой стрелке) галочки равно 4: 2

  2. CGPoint в верхнем правом углу флажка идентичен верхнему правому зерну«внутреннее поле (3 x 3)»

  3. Если интервал сетки значка равен 1, то с точки зрения 45 градусов каждый «блок» флажка имеет вид (sqrt (18) / 5) высокий и / или широкий.

Есть ли в доме математики?Где мой дог Александр Сойфер?

Я все еще работаю над этим, но не стесняйтесь попробовать.

Это то, что я имею до сих пор:

static func checkMark(gridSpacing G: CGFloat) -> UIBezierPath {


        let blurp = UIBezierPath()

        let CM_hyp = sqrt((18*G)/5)

        let CM_opp_or_adj = sqrt( ((CM_hyp)*(CM_hyp)) / 2 )

        let startPoint = CGPoint(x: 4*G, y: G)

        blurp.move(to: startPoint)
        blurp.addLine(to: CGPoint(x: (4*G)+CM_opp_or_adj, y: G + CM_opp_or_adj))
        blurp.addLine(to: CGPoint(x: 4*G-(3*CM_opp_or_adj), y: 4*G) )
        blurp.addLine(to: CGPoint( x: G, y:(4*G) - 2*CM_opp_or_adj ))
        blurp.addLine(to: CGPoint( x: G + CM_opp_or_adj, y: (2*G) + CM_opp_or_adj) )
        //6
        blurp.addLine(to: CGPoint( x: 2*G + CM_opp_or_adj, y:      (4*G) - 2*CM_opp_or_adj   )     )
        blurp.addLine(to: startPoint)


        blurp.close()


        return blurp

    }

Но это выглядит глупо.Я сделал что-то не так.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Если кому-то интересно, у меня все получилось ...

Это была в основном куча математических ошибок и Бакарди виноват.

static func checkMark(gridSpacing G: CGFloat) -> UIBezierPath {        

        let blurp = UIBezierPath()

        let CM_hyp = ((sqrt(18))/5) * G

        let CM_opp_or_adj = sqrt( ((CM_hyp)*(CM_hyp)) / 2 )

        let startPoint = CGPoint(x: 4*G, y: G)

        blurp.move(to: startPoint)
        blurp.addLine(to: CGPoint(x: (4*G)+CM_opp_or_adj, y: G + CM_opp_or_adj))
        blurp.addLine(to: CGPoint(x: (4*G)-(3*CM_opp_or_adj), y: 4*G) )
        //3
        blurp.addLine(to: CGPoint( x: G, y:(4*G) - 2*CM_opp_or_adj ))

        blurp.addLine(to: CGPoint( x: G + CM_opp_or_adj, y: (4*G) - 3*CM_opp_or_adj ) )
        blurp.addLine(to: CGPoint( x: (4*G)-(3*CM_opp_or_adj), y: (4*G) - 2*CM_opp_or_adj ) )
        blurp.addLine(to: startPoint)

        blurp.close()
        // !!
        return blurp

    }

static func checkMarkBox(gridSpacing G: CGFloat) -> UIBezierPath {

        let boxPath = UIBezierPath()

        boxPath.move(to: CGPoint(x:G, y: G))
        boxPath.addLine(to: CGPoint(x:4*G, y: G))
        boxPath.addLine(to: CGPoint(x:4*G, y: 4*G))
        boxPath.addLine(to: CGPoint(x:G, y: 4*G))
        boxPath.addLine(to: CGPoint(x:G, y: G))

        boxPath.close()

        return boxPath

    }
0 голосов
/ 26 апреля 2018

Я сделал пользовательский флажок в качестве кнопки

@IBDesignable class SquareCheckBox: UIButton {
//MARK: - Properties
@IBInspectable var isOn:Bool = false{
    didSet{
        self.setNeedsDisplay()
    }
}
//gives the actual functionality of the button


@IBInspectable var tickWidth: CGFloat = 2.0
//decides the width of the tick
/*
 THIS VALUE CANNOT EXCEED THE HALF OF THE BUTTON'S HEIGHT OR GO BELOW ZERO. IT WILL RESET TO 3.0 IN ANY SUCH CASE.
 */


@IBInspectable var borderWidth: CGFloat = 3.0
//decides the width of the border of the button
/*
 THIS VALUE WILL BE RESET TO 3.0 IF THE DEVELOPER EXCEEDS THE 1/4TH OF THE BUTTON'S HEIGHT OR BELOW ZERO.
 */


@IBInspectable var borderRadius: CGFloat = 3.0
//decides the corner radius of the button
/*
 THIS VALUE CANNOT EXCEED THE HALF OF THE BUTTON'S HEIGHT OR GO BELOW ZERO. IT WILL RESET TO 3.0 IN ANY SUCH CASE.
 */


@IBInspectable public var borderColor: UIColor = UIColor(red: 255/255, green: 0, blue: 0, alpha: 1)
//decides the color of the border of the button


@IBInspectable public var BGColorOn: UIColor = UIColor(red: 255/255, green: 0, blue: 0, alpha: 1)
//decides the color of button's background when it is checked


@IBInspectable public var BGColorOff: UIColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
//decides the color of button's background when it is checked


@IBInspectable public var tickColor: UIColor = UIColor.white
//decides the color of the tick

//MARK: - Overriden Functions
override init(frame: CGRect) {
    super.init(frame: frame)

    self.setTitle(nil, for: .normal)
    //removing any title as it doesn't allow the layers in button to form and crashes the App
}
// Xcode uses this to render the button in the storyboard.


required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
// The storyboard loader uses this at runtime.


override func draw(_ rect: CGRect) {
    let boxDim = min(bounds.height, bounds.width)
    self.clipsToBounds = true
    self.layer.borderColor = self.borderColor.cgColor


    //NOTE: we cannot set the value for the radius more than half of the width if the width is smaller than height OR we cannot set the value for the radius more than half of the width if the height is smaller than the width
    if borderRadius < 0 || borderRadius > boxDim/2 {
        self.layer.cornerRadius = 3.0
    } else {
        self.layer.cornerRadius = self.borderRadius
    }

    //creating box
    let path = UIBezierPath(roundedRect: rect, cornerRadius: self.borderRadius)
    //creating tick
    let tickPath = UIBezierPath()

    tickPath.lineWidth = 2.0

    //tick's path
    if bounds.width > bounds.height{
        //when width is greater than height
        tickPath.move(to: CGPoint(x: bounds.width/2 - boxDim/3, y: boxDim/2))
        tickPath.addLine(to: CGPoint(x: bounds.width/2 - boxDim/6, y: ((boxDim)*3)/4))
        tickPath.addLine(to: CGPoint(x: bounds.width/2 + boxDim/3, y: boxDim/4))
    } else if bounds.width < bounds.height{
        //when height is greater than width
        tickPath.move(to: CGPoint(x: boxDim/6, y: bounds.height/2))
        tickPath.addLine(to: CGPoint(x: ((boxDim)*2)/6, y: (((boxDim)*3)/4) - boxDim/2 + bounds.height/2))
        tickPath.addLine(to: CGPoint(x: ((boxDim)*5)/6, y: bounds.height/2 - (boxDim/4)))
    } else {
        //when it's a square
        tickPath.move(to: CGPoint(x: boxDim/6, y: boxDim/2))
        tickPath.addLine(to: CGPoint(x: ((boxDim)*2)/6, y: ((boxDim)*3)/4))
        tickPath.addLine(to: CGPoint(x: ((boxDim)*5)/6, y: boxDim/4))
    }



    if isOn{
        self.layer.borderWidth = 0.0
        BGColorOn.setFill()//setting background color for when box is on
        path.fill()

        //creating sublayer
        let pathLayer = CAShapeLayer()
        pathLayer.frame = self.bounds
        pathLayer.path = tickPath.cgPath
        pathLayer.strokeColor = tickColor.cgColor//setting tick color
        pathLayer.fillColor = nil
        //NOTE: we cannot set the value for the width of tick more than one-fourth of width if width is smaller than height OR we cannot set the value for the width of tick more than one-fourth of width if height is smaller than width
        //we cannot set the value for the width of tick less than one
        if tickWidth < 1 || tickWidth > boxDim/4 {
            pathLayer.lineWidth = 2
        }else {
            pathLayer.lineWidth = tickWidth
        }

        pathLayer.lineJoin = kCALineJoinBevel

        //adding sublayer
        self.layer.addSublayer(pathLayer)

        //animating
        let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
        pathAnimation.duration = 0.5
        pathAnimation.fromValue = 0.0
        pathAnimation.toValue = 1.0
        pathLayer.add(pathAnimation, forKey: "strokeEnd")
    } else {
        if borderWidth < 0 || borderWidth > boxDim/4 {
            self.layer.borderWidth = 3.0
        } else {
            self.layer.borderWidth = self.borderWidth
        }
        BGColorOff.setFill()
        path.fill()
        self.layer.sublayers?.removeAll()
        //removing all sublayers
    }
}
}

, у него есть различные свойства, которые вы можете настроить, создав экземпляр этого класса

...