82

我有一个UIViewController. 如何在其以编程方式创建的视图之一中画一条线?

4

8 回答 8

188

有两种常见的技术。

  1. 使用CAShapeLayer

    • 创建一个UIBezierPath(用任何你想要的替换坐标):

      UIBezierPath *path = [UIBezierPath bezierPath];
      [path moveToPoint:CGPointMake(10.0, 10.0)];
      [path addLineToPoint:CGPointMake(100.0, 100.0)];
      
    • 创建一个CAShapeLayer使用它的UIBezierPath

      CAShapeLayer *shapeLayer = [CAShapeLayer layer];
      shapeLayer.path = [path CGPath];
      shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
      shapeLayer.lineWidth = 3.0;
      shapeLayer.fillColor = [[UIColor clearColor] CGColor];
      
    • 将其添加CAShapeLayer到您的视图层:

      [self.view.layer addSublayer:shapeLayer];
      

    在以前版本的 Xcode 中,您必须手动将QuartzCore.framework 添加到项目的“Link Binary with Libraries”并在 .m 文件中导入<QuartzCore/QuartzCore.h>标头,但这不再需要(如果您有“Enable Modules”和“Link自动框架”构建设置已打开)。

  2. 另一种方法是子类化UIView,然后在方法中使用CoreGraphics调用drawRect

    • 创建一个UIView子类并定义一个drawRect画线的子类。

      你可以用核心图形做到这一点:

      - (void)drawRect:(CGRect)rect {
          CGContextRef context = UIGraphicsGetCurrentContext();
      
          CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
          CGContextSetLineWidth(context, 3.0);
          CGContextMoveToPoint(context, 10.0, 10.0);
          CGContextAddLineToPoint(context, 100.0, 100.0);
          CGContextDrawPath(context, kCGPathStroke);
      }
      

      或使用UIKit

      - (void)drawRect:(CGRect)rect {
          UIBezierPath *path = [UIBezierPath bezierPath];
          [path moveToPoint:CGPointMake(10.0, 10.0)];
          [path addLineToPoint:CGPointMake(100.0, 100.0)];
          path.lineWidth = 3;
          [[UIColor blueColor] setStroke];
          [path stroke];
      }
      
    • 然后你可以使用这个视图类作为你的NIB/故事板或视图的基类,或者你可以让你的视图控制器以编程方式将它添加为子视图:

      PathView *pathView = [[PathView alloc] initWithFrame:self.view.bounds];
      pathView.backgroundColor = [UIColor clearColor];
      
      [self.view addSubview: pathView];
      

上述两种方法的 Swift 版本如下:

  1. CAShapeLayer

    // create path
    
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 10, y: 10))
    path.addLine(to: CGPoint(x: 100, y: 100))
    
    // Create a `CAShapeLayer` that uses that `UIBezierPath`:
    
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.lineWidth = 3
    
    // Add that `CAShapeLayer` to your view's layer:
    
    view.layer.addSublayer(shapeLayer)
    
  2. UIView子类:

    class PathView: UIView {
    
        var path: UIBezierPath?           { didSet { setNeedsDisplay() } }
        var pathColor: UIColor = .blue    { didSet { setNeedsDisplay() } }
    
        override func draw(_ rect: CGRect) {
            // stroke the path
    
            pathColor.setStroke()
            path?.stroke()
        }
    
    }
    

    并将其添加到您的视图层次结构中:

    let pathView = PathView()
    pathView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(pathView)
    
    NSLayoutConstraint.activate([
        pathView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        pathView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        pathView.topAnchor.constraint(equalTo: view.topAnchor),
        pathView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])
    
    pathView.backgroundColor = .clear
    
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 10, y: 10))
    path.addLine(to: CGPoint(x: 100, y: 100))
    path.lineWidth = 3
    
    pathView.path = path
    

    上面,我是以PathView编程方式添加的,但您也可以通过 IB 添加它,只需以path编程方式设置它。

于 2013-05-30T22:19:21.497 回答
16

创建一个 UIView 并将其添加为视图控制器视图的子视图。您可以将此子视图的高度或宽度修改为非常小,使其看起来像一条线。如果需要绘制对角线,可以修改子视图的变换属性。

例如画黑色水平线。这是从您的视图控制器的实现中调用的

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
于 2013-05-30T21:53:08.790 回答
9

这里有一个很酷的技术,你可能会觉得有用:Using blocks for drawing to Avoid subclassing in Objective-C

在您的项目中包含本文的通用视图子类,然后您可以将这种代码放入视图控制器中,以动态创建绘制一条线的视图:

DrawView* drawableView = [[[DrawView alloc] initWithFrame:CGRectMake(0,0,320,50)] autorelease];
drawableView.drawBlock = ^(UIView* v,CGContextRef context)
{
  CGPoint startPoint = CGPointMake(0,v.bounds.size.height-1);
  CGPoint endPoint = CGPointMake(v.bounds.size.width,v.bounds.size.height-1);

  CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
  CGContextSetLineWidth(context, 1);
  CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
  CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
  CGContextStrokePath(context);
};
[self.view addSubview:drawableView];
于 2013-05-31T05:12:36.657 回答
9

斯威夫特 3:

let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 10))
path.addLine(to: CGPoint(x: 100, y: 100))

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 3.0

view.layer.addSublayer(shapeLayer)
于 2017-01-28T22:37:15.800 回答
6

你可以使用 UIImageView 在上面画线。

但是,它允许跳过子分类。而且由于我不太倾向于 Core Graphics 仍然可以使用它。你可以把它放进去——ViewDidLoad

  UIGraphicsBeginImageContext(self.view.frame.size);
  [self.myImageView.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
  CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
  CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);

  CGContextMoveToPoint(UIGraphicsGetCurrentContext(), 50, 50);
  CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), 200, 200);
  CGContextStrokePath(UIGraphicsGetCurrentContext());
  CGContextFlush(UIGraphicsGetCurrentContext());
  self.myImageView.image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

除了 Rob 的回答,第三种方法是使用UIImageView- 掩盖它 - xib 的视图。(这是在 xcode 5 中的 xib 上拖动时的默认 UIImageView 外观)

干杯和+1!

于 2014-08-22T06:43:05.900 回答
2

你不应该真的,但如果出于某种原因它对你有意义,你可以创建一个 UIView 的子类,DelegateDrawView例如,它需要一个实现类似方法的委托

- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect

然后在方法中 -[DelegateDrawView drawRect:]你应该调用你的委托方法。

但是为什么要将视图代码放在控制器中。

你最好创建一个 UIView 的子类,在它的两个角之间画一条线,你可以有一个属性来设置哪两个,然后将视图从视图控制器定位到你想要的位置。

于 2013-05-30T23:41:29.887 回答
2

在您的视图中绘制非常简单,@Mr.ROB 说两种方法我采用了第一种方法。

只需将代码复制粘贴到你们想要的地方。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
     startingPoint = [touch locationInView:self.view];

    NSLog(@"Touch starting point = x : %f Touch Starting Point = y : %f", touchPoint.x, touchPoint.y);
}
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{

}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
     touchPoint = [touch locationInView:self.view];

    NSLog(@"Touch end point =x : %f Touch end point =y : %f", touchPoint.x, touchPoint.y);
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{

    UITouch *touch = [[event allTouches] anyObject];
    touchPoint = [touch locationInView:self.view];
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
    [path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
    startingPoint=touchPoint;
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = [path CGPath];
    shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
    shapeLayer.lineWidth = 3.0;
    shapeLayer.fillColor = [[UIColor redColor] CGColor];
    [self.view.layer addSublayer:shapeLayer];

    NSLog(@"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
    [self.view setNeedsDisplay];


}
- (void)tapGestureRecognizer:(UIGestureRecognizer *)recognizer {
    CGPoint tappedPoint = [recognizer locationInView:self.view];
    CGFloat xCoordinate = tappedPoint.x;
    CGFloat yCoordinate = tappedPoint.y;

    NSLog(@"Touch Using UITapGestureRecognizer x : %f y : %f", xCoordinate, yCoordinate);
}

它会像一条线一样绘制,手指移动的地方

于 2016-01-09T05:40:57.057 回答
0

斯威夫特 5.4

使用高度为 1 或 2 点的 UIView 并将其添加为视图控制器视图的子视图。

class Separator: UIView {

    let line = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }


    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func configure() {
        backgroundColor = .red

        addSubview(line)
        line.translatesAutoresizingMaskIntoConstraints = false
        line.backgroundColor = .secondaryLabelColor

        NSLayoutConstraint.activate([
            line.centerYAnchor.constraint(equalTo: self.centerYAnchor),
            line.centerXAnchor.constraint(equalTo: self.centerXAnchor),
            line.heightAnchor.constraint(equalToConstant: Pad.separatorHeight),
            line.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.8 )
        ])
    }
}

然后将其添加到您的视图控制器中:


let separator = Separator()
view.addSubview(separator)
separator.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
    separator.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    separator.topAnchor.constraint(equalTo: view.bottomAnchor),
    separator.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    separator.heightAnchor.constraint(equalToConstant: 72.0)
    ])
于 2021-02-25T11:53:02.457 回答