Tôi có một UIViewController
. Làm cách nào để vẽ một đường thẳng trong một trong các chế độ xem được tạo lập trình của nó?
Tôi có một UIViewController
. Làm cách nào để vẽ một đường thẳng trong một trong các chế độ xem được tạo lập trình của nó?
Câu trả lời:
Có hai kỹ thuật phổ biến.
Sử dụng CAShapeLayer
:
Tạo một UIBezierPath
(thay thế tọa độ bằng bất kỳ tọa độ nào bạn muốn):
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
Tạo một CAShapeLayer
sử dụng UIBezierPath
:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
Thêm nó CAShapeLayer
vào lớp trong chế độ xem của bạn:
[self.view.layer addSublayer:shapeLayer];
Trong các phiên bản trước của Xcode, bạn phải thêm QuartzCore.framework theo cách thủ công vào "Liên kết nhị phân với thư viện" của dự án và nhập <QuartzCore/QuartzCore.h>
tiêu đề trong tệp .m của bạn, nhưng điều đó không cần thiết nữa (nếu bạn có "Bật mô-đun" và "Liên kết Frameworks Tự động "bật cài đặt xây dựng).
Cách tiếp cận khác là phân lớp UIView
và sau đó sử dụng lời gọi CoreGraphics trong drawRect
phương thức:
Tạo một UIView
lớp con và xác định một lớp drawRect
vẽ đường của bạn.
Bạn có thể làm điều này với Core Graphics:
- (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);
}
Hoặc sử dụng 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];
}
Sau đó, bạn có thể sử dụng lớp chế độ xem này làm lớp cơ sở cho NIB / bảng phân cảnh hoặc chế độ xem của mình hoặc bạn có thể đặt bộ điều khiển chế độ xem của mình theo cách lập trình thêm nó làm chế độ xem phụ:
PathView *pathView = [[PathView alloc] initWithFrame:self.view.bounds];
pathView.backgroundColor = [UIColor clearColor];
[self.view addSubview: pathView];
Các phiên bản Swift của hai phương pháp trên như sau:
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
lớp con:
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()
}
}
Và thêm nó vào hệ thống phân cấp chế độ xem của bạn:
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
Ở trên, tôi đang thêm theo PathView
chương trình, nhưng bạn cũng có thể thêm nó qua IB và chỉ cần đặt nó theo path
chương trình.
shapeLayer.lineCap = kCALineCapRound;
UIBezierPath
với các cuộc gọi addLineToPoint
/ lặp lại addLine(to:)
. Sau đó, bạn có thể chọn xem bạn thích shapeLayer.lineJoin = kCALineJoinRound
hoặc kCALineJoinBevel
hoặc kCALineJoinMiter
.
Tạo một UIView và thêm nó làm chế độ xem phụ của chế độ xem bộ điều khiển chế độ xem của bạn. Bạn có thể sửa đổi chiều cao hoặc chiều rộng của chế độ xem phụ này thành rất nhỏ để nó trông giống như một đường thẳng. Nếu bạn cần vẽ một đường chéo, bạn có thể sửa đổi thuộc tính chuyển đổi chế độ xem phụ.
ví dụ: vẽ đường ngang màu đen. Điều này được gọi từ bên trong triển khai trình điều khiển chế độ xem của bạn
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
Swift 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)
Đây là một kỹ thuật thú vị mà bạn có thể thấy hữu ích: Sử dụng các khối để vẽ để tránh phân lớp trong Objective-C
Bao gồm lớp con chế độ xem mục đích chung của bài viết trong dự án của bạn, sau đó đây là loại mã bạn có thể đặt trong bộ điều khiển chế độ xem của mình để tạo chế độ xem nhanh chóng vẽ một đường:
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];
Bạn có thể sử dụng UIImageView để vẽ các đường trên.
Tuy nhiên, nó cho phép bỏ qua phân loại phụ. Và vì tôi hơi nghiêng về Đồ họa cốt lõi vẫn có thể sử dụng nó. Bạn chỉ có thể đặt nó vào -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();
Bổ sung cho câu trả lời của Rob, Để có được nhanh chóng, cách tiếp cận thứ ba là sử dụng UIImageView
- che đậy nó - quan điểm của xib. (Đó là giao diện UIImageView mặc định khi được kéo trên xib trong xcode 5)
Chúc mừng và +1!
Bạn thực sự không nên, nhưng nếu vì lý do nào đó nó có ý nghĩa với bạn, bạn có thể tạo một lớp con của UIView, được gọi là DelegateDrawView
ví dụ, lấy một ủy quyền thực hiện một phương thức như
- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect
và sau đó trong các phương thức - [DelegateDrawView drawRect:]
bạn nên gọi phương thức ủy nhiệm của mình.
Nhưng tại sao bạn lại muốn đặt mã chế độ xem trong bộ điều khiển của mình.
Tốt hơn hết bạn nên tạo một lớp con của UIView, lớp này vẽ một đường thẳng giữa hai góc của nó, bạn có thể có một thuộc tính để đặt hai thuộc tính đó và sau đó định vị dạng xem bạn muốn nó từ bộ điều khiển xem.
Để vẽ bên trong khung nhìn của bạn rất đơn giản, @ Mr.ROB cho biết 2 phương pháp tôi đã thực hiện phương pháp đầu tiên.
Chỉ cần sao chép, dán mã vào nơi bạn muốn.
-(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);
}
Nó sẽ vẽ như một đường thẳng, nơi ngón tay di chuyển