我正在为应用程序创建一些自定义按钮,有几个图标,我在理论上设计了它们,但我无法弄清楚如何在iOS中绘制这个讨厌的“复选框”图标UIBezierPath语言。
作为一般规则,图标的边界为5 x 5,图标内包含的图形边界为3 x 3.(是的,我知道复选框突出于3 x 3边界之外)。
这里有一个复选框图标和一个“加号”图标(是的,我带着Corel DRAW 12,所以......):
你看,“加号”图标,我没有这样的问题:
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
}
// ...
}
但是,复选框图标让我头疼得厉害。
到目前为止,我已经确定了以下事项:
复选标记的长度:宽度比(顺时针旋转45度)为4:2
复选标记右上角的CGPoint与“内部(3 x 3)框”的右上角相同
如果图标的网格间距为1,则从45度角度看,复选标记的每个“块”为(sqrt(18)/ 5)高和/或宽。
< / LI> 醇>房子里有数学家吗?亚历山大·索弗在哪里?
我还在努力,但可以随意尝试。
这就是我到目前为止:
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
}
但它看起来很傻。我做错了什么。
答案 0 :(得分:1)
我制作了一个自定义复选框作为按钮
@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
}
}
}
它有各种属性,你可以通过创建这个类的实例来调整它
答案 1 :(得分:0)
如果有人有兴趣,我就让它工作......
这基本上是一堆数学错误和百加得的责任。
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
}