在Core Graphics中绘制子弹箭头

时间:2012-04-26 01:23:43

标签: iphone objective-c ios core-graphics

除非绝对必要,否则我不想重新发明轮子,所以我想看看如何使用Core Graphics绘制这样的箭头:

enter image description here

有谁知道如何开始这个? 这是我到目前为止,但它绘制了一个正三角形而不是括号形状:

    CGPoint origin = CGPointMake(100, 20);
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:origin];
    [path addLineToPoint:CGPointMake(origin.x-10, origin.y-20)];
    [path addLineToPoint:CGPointMake(origin.x-10, origin.y+20)];
    [[UIColor redColor] set];
    [path fill];

4 个答案:

答案 0 :(得分:9)

如果您使用@NSGod建议的笔划进行绘制,则需要移动到上部或下部尖端,然后沿箭头线方向移动,然后换行到下部或上部尖端。如果你想要一个45度角,就像你绘制的角度一样,你在坐标上加或减的数量应相等。

您还需要设置路径的线宽。这需要与大小成比例。

CGPoint origin = CGPointMake(100, 20);

UIBezierPath *path = [UIBezierPath bezierPath];
// Upper tip
[path moveToPoint:CGPointMake(origin.x+20, origin.y-20)];
// Arrow head
[path addLineToPoint:CGPointMake(origin.x, origin.y)];
// Lower tip
[path addLineToPoint:CGPointMake(origin.x+20, origin.y+20)];

[[UIColor redColor] set];
// The line thickness needs to be proportional to the distance from the arrow head to the tips.  Making it half seems about right.
[path setLineWidth:10];
[path stroke];

结果是这样的形状。

Arrow drawn by code above

如果你想要填充,而不是中风 - 如果你想勾画你的箭头可能是必要的 - 你需要绘制6个点然后关闭路径。

答案 1 :(得分:3)

问题的一个潜在部分是您使用的是fill而不是stroke

[path fill]更改为[path stroke],您就得到了这个:

CGPoint origin = CGPointMake(100, 20);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:origin];
[path addLineToPoint:CGPointMake(origin.x - 10, origin.y - 20)];
[path addLineToPoint:CGPointMake(origin.x - 10, origin.y + 20)];
[[UIColor redColor] set];
// [path fill];
[path stroke];

enter image description here

这提出了origin点的意图。它实际上会转换为箭头点,而不是传统意义上的原点(将意味着绘制对象的左上角)。

如果您想保留origin的含义,则需要将代码修改为以下内容:

CGPoint origin = CGPointMake(100, 20);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(origin.x - 20, origin.y - 20)];
[path addLineToPoint:origin];
[path addLineToPoint:CGPointMake(origin.x - 20, origin.y + 20)];
path.lineWidth = 4.0;
[[UIColor redColor] set];
[path stroke];

或者,如果您想使用origin的传统含义,您可以使用:

CGPoint origin = CGPointMake(100, 20);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:origin];
[path addLineToPoint:CGPointMake(origin.x + 20, origin.y + 20)];
[path addLineToPoint:CGPointMake(origin.x, origin.y + 20 * 2)];
path.lineWidth = 4.0;
[[UIColor redColor] set];
[path stroke];

这会产生以下结果:

enter image description here

答案 2 :(得分:1)

这是一个 Swift 3.0 兼容类,其中包含来自@ Dondragmer上面答案的原始代码。

您可以更改:

  • lineHeight:CGFloat
  • lineColor:UIColor
  • 方向:Arrow.Direction(带.up,.down,.left,.right的枚举)
class Arrow : UIView {

    enum Direction {
        case up, down, left, right
    }

    var direction : Direction = Direction.right {
        didSet {
            review()
        }
    }

    var lineColor = UIColor.red {
        didSet {
            review()
        }
    }

    var lineWidth : CGFloat = 20 {
        didSet {
            review()
        }
    }

    func review(){
        setNeedsDisplay()
    }


    static func directionToRadians(_ direction: Arrow.Direction) -> CGFloat{
        switch direction {
        case .up:
            return Arrow.degreesToRadians(90)
        case .down:
            return Arrow.degreesToRadians(-90)
        case .left:
            return Arrow.degreesToRadians(0)
        case .right:
            return Arrow.degreesToRadians(180)
        }
    }

    static func degreesToRadians(_ degrees: CGFloat) -> CGFloat {
        return degrees  * CGFloat(M_PI) / 180
    }

    override func draw(_ rect: CGRect) {
        let origin = CGPoint(x: 12, y: self.frame.height / 2)
        let path = UIBezierPath()
        path.lineJoinStyle = CGLineJoin.round
        path.move(to: CGPoint(x: origin.x + self.frame.width * (1/2), y: frame.height - 10))
        path.addLine(to: CGPoint(x: origin.x, y: origin.y))
        path.addLine(to: CGPoint(x: origin.x + self.frame.width * (1/2), y: 10))
        lineColor.set()
        path.lineWidth = lineWidth
        path.stroke()
        self.backgroundColor = UIColor.clear
        self.transform = CGAffineTransform(rotationAngle: Arrow.directionToRadians(self.direction))
    }
}

现在你可以使用

这也是自动布局兼容。

let arrow = Arrow(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
arrow.lineWidth = 20
arrow.lineColor = UIColor.blue
arrow.direction = .up

答案 3 :(得分:0)

我不是在电脑前编写代码,但基本上你创建了一个CGMutablePath,然后添加

CGContextStrokePath(context);

您可以设置所需效果的笔触宽度和线条上限