ビューコントローラからプログラムでどのように線を引きますか?


82

私は持っていUIViewControllerます。プログラムで作成されたビューの1つに線を引くにはどうすればよいですか?


2
いいえ、できません。描画は、コントローラーではなくビューで行う必要があります。デザインを変更する必要があります。
ブライアンチェン

1
@xlcロブの答えが示すように、VCからそれを行うことができます。実際に役立ちたい場合は、ベジェ手法の害点を説明してください。
mkc842 2013年

コードを見ることができますか?私は同意します、それは本当の質問ですが、私(多分私たち)はあなたが話していることを示すコードに最もよく答えます。
bugmagnet 2014年

回答:


186

2つの一般的な手法があります。

  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をプロジェクトの「LinkBinary with Libraries」に手動で追加し、<QuartzCore/QuartzCore.h>ヘッダーを.mファイルにインポートする必要がありましたが、これはもう必要ありません(「EnableModules」と「Link」がある場合)フレームワークを自動的に」ビルド設定をオンにします)。

  2. もう1つのアプローチは、サブクラス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 /ストーリーボードまたはビューの基本クラスとして使用するか、ViewControllerにプログラムでサブビューとして追加させることができます。

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

上記の2つのアプローチの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プログラムで設定するだけです。


@Rob:これは完全に正常に機能します。線の距離ABとABからの角度があることをお聞きしたいのですが、その状況で始点と終点を取得するにはどうすればよいですか?私を助けてください。
マンサン2015年

ビューにuigestureを追加しました。上記のコメントの直線に追加すると、タッチの開始点と移動点が正しく機能します。ただし、開始点自体から横にタッチすると、色@Rob
Kishore Kumar

CAShapeLayerメソッドを使用している場合、あなたは彼らが接続している回線は、滑らか見えるように、丸みを帯びたラインにキャップを設定する(そしておそらくにはなるでしょう)することができますshapeLayer.lineCap = kCALineCapRound;
アルバート・レンショウ

または、接続時にスムーズに見せたい複数の回線がある場合は、/呼び出しUIBezierPathを繰り返した単一の回線を使用することもできます。そして、あなたが好むかどうかを選ぶことができる か、または。addLineToPointaddLine(to:)shapeLayer.lineJoin = kCALineJoinRoundkCALineJoinBevelkCALineJoinMiter
ロブ

コードスニペットをありがとう、それは私をかなりの時間を節約しました。一部のイベントに反応して動的ビューを描画する場合は、描画の開始時に次のようにサブレイヤーをクリーンアップする必要があります。self.layer.sublayers= nil
Vilmir 2018年

15

UIViewを作成し、それをViewControllerのビューのサブビューとして追加します。このサブビューの高さまたは幅を非常に小さく変更して、線のように見せることができます。対角線を描画する必要がある場合は、サブビューの変換プロパティを変更できます。

たとえば、黒い水平線を描画します。これは、ViewControllerの実装内から呼び出されます

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];

セパレータ要素(たとえば、UI要素間の線)の場合、これが最も抵抗の少ないパスであることに同意する傾向があります。CoreAnimationレイヤーをバックアップするためにビットマップにレンダリングするか、カスタムビューに描画ハンドラーを実装するという選択肢は、はるかに複雑です。このおそらくハードウェアも、1行しかない場合は、より高速になります。
マルコ2013年

4
なぜこれがひどい考えであるのかという理由に興味があります。このソリューションが自分のコードで引き起こす可能性のある問題を回避したいと思います。
ジェフエイムズ

@sangonyコードでもこの手法を使用しています。また、なぜこれがひどい考えなのか疑問に思います。説明を手伝ってください。
Joe Huang

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)

8

これが役に立つかもしれないクールなテクニックです: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];

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();

ロブの答えに加えて、簡単に言うと、3番目のアプローチはUIImageView、xibのビューを使用することです。(これは、xcode 5でxibにドラッグしたときのデフォルトのUIImageViewの外観です)

乾杯と+1!


2

実際にはそうすべきではありませんが、何らかの理由でそれが理にかなっている場合は、UIViewのサブクラスを作成できます。DelegateDrawViewたとえば、次のようなメソッドを実装するデリゲートを取ります。

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

次に、メソッドで-[DelegateDrawView drawRect:]デリゲートメソッドを呼び出す必要があります。

しかし、なぜコントローラーにビューコードを配置したいのでしょうか。

UIViewのサブクラスを作成して、その2つのコーナーの間に線を引くことをお勧めします。プロパティを使用して、どちらのコーナーを設定し、ビューコントローラーから目的の場所にビューを配置できます。


1

ビュー内に描画するのは非常に簡単です、@ Mr.ROBは私が最初の方法をとった2つの方法を言いました。

コードをコピーして、必要な場所に貼り付けるだけです。

-(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);
}

指が動く線のように描画されます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.