Mam UIViewController
. Jak narysować linię w jednym z jej widoków utworzonych programowo?
Mam UIViewController
. Jak narysować linię w jednym z jej widoków utworzonych programowo?
Odpowiedzi:
Istnieją dwie powszechne techniki.
Używając CAShapeLayer
:
Utwórz UIBezierPath
(zamień współrzędne na dowolne):
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
Utwórz, CAShapeLayer
który używa tego UIBezierPath
:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
Dodaj to CAShapeLayer
do warstwy widoku:
[self.view.layer addSublayer:shapeLayer];
W poprzednich wersjach Xcode trzeba było ręcznie dodać QuartzCore.framework do elementu „Połącz<QuartzCore/QuartzCore.h>
plik binarny z bibliotekami” projektu i zaimportować nagłówek do pliku .m, ale nie jest to już konieczne (jeśli masz opcje „Włącz moduły” i „Połącz Struktury automatycznie „włączone ustawienia kompilacji).
Drugim podejściem jest podklasa, UIView
a następnie użycie wywołań CoreGraphics w drawRect
metodzie:
Utwórz UIView
podklasę i zdefiniuj, drawRect
która rysuje twoją linię.
Możesz to zrobić z 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);
}
Lub za pomocą 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];
}
Następnie możesz użyć tej klasy widoku jako klasy bazowej dla swojego NIB / serii ujęć lub widoku, albo możesz programowo dodać ją jako widok podrzędny do kontrolera widoku:
PathView *pathView = [[PathView alloc] initWithFrame:self.view.bounds];
pathView.backgroundColor = [UIColor clearColor];
[self.view addSubview: pathView];
Szybkie wersje dwóch powyższych podejść są następujące:
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
podklasa:
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()
}
}
I dodaj go do swojej hierarchii widoków:
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
Powyżej PathView
dodaję programowo, ale możesz też dodać go przez IB i po prostu ustawić path
programowo.
shapeLayer.lineCap = kCALineCapRound;
UIBezierPath
, z powtórzonymi addLineToPoint
/ addLine(to:)
wywołania. Następnie możesz wybrać, czy wolisz, shapeLayer.lineJoin = kCALineJoinRound
czy kCALineJoinBevel
lub kCALineJoinMiter
.
Utwórz widok UIView i dodaj go jako widok podrzędny widoku kontrolera widoku. Możesz zmodyfikować wysokość lub szerokość tego widoku podrzędnego, aby był bardzo mały, aby wyglądał jak linia. Jeśli chcesz narysować linię ukośną, możesz zmodyfikować właściwość transformacji widoków podrzędnych.
np. narysuj czarną poziomą linię. Jest to wywoływane z implementacji kontrolera widoku
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)
Oto fajna technika, która może Ci się przydać: Używanie bloków do rysowania, aby uniknąć tworzenia podklas w Objective-C
Uwzględnij podklasę widoku ogólnego przeznaczenia w swoim projekcie, a następnie w kontrolerze widoku możesz umieścić taki kod, aby w locie utworzyć widok rysujący linię:
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];
Możesz użyć UIImageView do rysowania linii.
Pozwala jednak na pominięcie podklas. A ponieważ jestem mało skłonny do Core Graphics, nadal mogę go używać. Możesz to po prostu włożyć -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();
Dodatek do odpowiedzi Roba, Trzecim podejściem jest użycie UIImageView
- zakryj to - widoku xib. (To jest domyślny wygląd UIImageView po przeciągnięciu na xib w xcode 5)
Pozdrawiam i +1!
Nie powinieneś, ale jeśli z jakiegoś powodu ma to dla ciebie sens, możesz utworzyć podklasę UIView, nazywaną DelegateDrawView
na przykład, która przyjmuje delegata, który implementuje metodę taką jak
- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect
a następnie w metodach - [DelegateDrawView drawRect:]
należy wywołać metodę delegata.
Ale dlaczego miałbyś chcieć umieścić kod widoku w kontrolerze.
Lepiej jest utworzyć podklasę UIView, która rysuje linię między dwoma jej rogami, możesz ustawić właściwość, aby ustawić które z nich, a następnie ustawić widok tam, gdzie chcesz, od kontrolera widoku.
Aby narysować wnętrze twojego widoku jest bardzo proste, @ Mr.ROB powiedział 2 metodę, którą wybrałem pierwszą metodę.
Po prostu skopiuj, wklej kod tam, gdzie chcesz.
-(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);
}
Będzie rysować jak linia, po której porusza się palec