我有一个UIViewController
. 如何在其以编程方式创建的视图之一中画一条线?
8 回答
有两种常见的技术。
使用
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自动框架”构建设置已打开)。另一种方法是子类化
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 版本如下:
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)
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
编程方式设置它。
创建一个 UIView 并将其添加为视图控制器视图的子视图。您可以将此子视图的高度或宽度修改为非常小,使其看起来像一条线。如果需要绘制对角线,可以修改子视图的变换属性。
例如画黑色水平线。这是从您的视图控制器的实现中调用的
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
这里有一个很酷的技术,你可能会觉得有用: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];
斯威夫特 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)
你可以使用 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!
你不应该真的,但如果出于某种原因它对你有意义,你可以创建一个 UIView 的子类,DelegateDrawView
例如,它需要一个实现类似方法的委托
- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect
然后在方法中 -[DelegateDrawView drawRect:]
你应该调用你的委托方法。
但是为什么要将视图代码放在控制器中。
你最好创建一个 UIView 的子类,在它的两个角之间画一条线,你可以有一个属性来设置哪两个,然后将视图从视图控制器定位到你想要的位置。
在您的视图中绘制非常简单,@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);
}
它会像一条线一样绘制,手指移动的地方
斯威夫特 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)
])