2013-02-12 92 views
2

我想绘制一个有四个圆形手柄的矩形。以下是它的样子:带圆形手柄的UIBezierPath矩形

o----o 
| | 
| | 
o----o 

圆形手柄是“热”。换句话说,当用户触摸它时,手柄可以被移动,而其余的点被锚定。我想知道是否有人有编码此功能的方法。我正在寻找UIBezierPath来绘制带圆圈的矩形,但我很难考虑如何让用户只点击圆圈。我认为它可能需要五个不同的UIBezierPath对象,但最终UI将由这些对象的多个组成。

任何建议将不胜感激。谢谢。

+0

'addArcWithCenter:radius:startAngle:endAngle:顺时针:'? 你知道何时停止“直线” ... – Larme 2013-02-12 19:40:26

回答

3

我不会画它与复杂UIBezierPath s的所有单个形状。我会把它想成6个不同的部分。一个容器,一个矩形和4个圆圈。

我会有一个简单的容器UIView有一个矩形视图和四个圆形UIViews在其角落。然后在每个圆上放一个UIPanGestureRecognizer。在手势处理程序中,移动圆的中心,并调整相同数量的基础矩形矩形。这将避免任何复杂的路径或数学,并使它简单地增加和减少矩形本身的数量。

更新:代码!

我创建了一个自包含的UIView子类来处理一切。你可以这样创建一个:

HandlesView *view = [[HandlesView alloc] initWithFrame:self.view.bounds]; 
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth]; 
[view setBackgroundColor:[UIColor redColor]]; 
[self.view addSubview:view]; 

// A custom property that contains the selected area of the rectangle. Its updated while resizing. 
[view setSelectedFrame:CGRectMake(128.0, 128.0, 200.0, 200.0)]; 

视图的框架本身是可拖动的总面积。所选框架是内部可见矩形。

// 
// HandlesView.h 
// handles 
// 
// Created by Ryan Poolos on 2/12/13. 
// Copyright (c) 2013 Ryan Poolos. All rights reserved. 
// 

#import <UIKit/UIKit.h> 
#import <QuartzCore/QuartzCore.h> 

@interface HandlesView : UIView 

@property (nonatomic, readwrite) CGRect selectedFrame; 

@end 

这里是实现。

// 
// HandlesView.m 
// handles 
// 
// Created by Ryan Poolos on 2/12/13. 
// Copyright (c) 2013 Ryan Poolos. All rights reserved. 
// 

#import "HandlesView.h" 

@interface HandlesView() 
{ 
    UIView *rectangle; 

    NSArray *handles; 
    NSMutableArray *touchedHandles; 

    UIView *circleTL; 
    UIView *circleTR; 
    UIView *circleBL; 
    UIView *circleBR; 
} 
@end 

@implementation HandlesView 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     rectangle = [[UIView alloc] initWithFrame:CGRectInset(self.bounds, 22.0, 22.0)]; 
     [self addSubview:rectangle]; 

     // Create the handles and position. 
     circleTL = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 44.0, 44.0)]; 
     [circleTL setCenter:CGPointMake(CGRectGetMinX(rectangle.frame), CGRectGetMinY(rectangle.frame))]; 

     circleTR = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 44.0, 44.0)]; 
     [circleTR setCenter:CGPointMake(CGRectGetMaxX(rectangle.frame), CGRectGetMinY(rectangle.frame))]; 

     circleBL = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 44.0, 44.0)]; 
     [circleBL setCenter:CGPointMake(CGRectGetMinX(rectangle.frame), CGRectGetMaxY(rectangle.frame))]; 

     circleBR = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 44.0, 44.0)]; 
     [circleBR setCenter:CGPointMake(CGRectGetMaxX(rectangle.frame), CGRectGetMaxY(rectangle.frame))]; 

     handles = @[ circleTL, circleTR, circleBL, circleBR ]; 

     for (UIView *handle in handles) { 
      // Round the corners into a circle. 
      [handle.layer setCornerRadius:(handle.frame.size.width/2.0)]; 
      [self setClipsToBounds:YES]; 

      // Add a drag gesture to the handle. 
      [handle addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]]; 

      // Add the handle to the screen. 
      [self addSubview:handle]; 
     } 
    } 
    return self; 
} 

- (void)setSelectedFrame:(CGRect)selectedFrame 
{ 
    [rectangle setFrame:selectedFrame]; 

    [circleTL setCenter:CGPointMake(CGRectGetMinX(rectangle.frame), CGRectGetMinY(rectangle.frame))]; 
    [circleTR setCenter:CGPointMake(CGRectGetMaxX(rectangle.frame), CGRectGetMinY(rectangle.frame))]; 
    [circleBL setCenter:CGPointMake(CGRectGetMinX(rectangle.frame), CGRectGetMaxY(rectangle.frame))]; 
    [circleBR setCenter:CGPointMake(CGRectGetMaxX(rectangle.frame), CGRectGetMaxY(rectangle.frame))]; 
} 

- (CGRect)selectedFrame 
{ 
    return rectangle.frame; 
} 

// Forward the background color. 
- (void)setBackgroundColor:(UIColor *)backgroundColor 
{ 
    // Set the container to clear. 
    [super setBackgroundColor:[UIColor clearColor]]; 

    // Set our rectangle's color. 
    [rectangle setBackgroundColor:[backgroundColor colorWithAlphaComponent:0.5]]; 

    for (UIView *handle in handles) { 
     [handle setBackgroundColor:backgroundColor]; 
    } 
} 

- (void)handlePan:(UIPanGestureRecognizer *)gesture 
{ 
    // The handle we're moving. 
    UIView *touchedHandle = gesture.view; 

    // Keep track of touched Handles. 
    if (!touchedHandles) { 
     touchedHandles = [NSMutableArray array]; 
    } 

    switch (gesture.state) { 
     case UIGestureRecognizerStateBegan: 
      [touchedHandles addObject:touchedHandle]; 
      break; 

     case UIGestureRecognizerStateChanged: 
     { 
      CGPoint tranlation = [gesture translationInView:self]; 

      // Calculate this handle's new center 
      CGPoint newCenter = CGPointMake(touchedHandle.center.x + tranlation.x, touchedHandle.center.y + tranlation.y); 

      // Move corresponding circles 
      for (UIView *handle in handles) { 
       if (handle != touchedHandle && ![touchedHandles containsObject:handle]) { 
        // Match the handles horizontal movement 
        if (handle.center.x == touchedHandle.center.x) { 
         handle.center = CGPointMake(newCenter.x, handle.center.y); 
        } 

        // Match the handles vertical movement 
        if (handle.center.y == touchedHandle.center.y) { 
         handle.center = CGPointMake(handle.center.x, newCenter.y); 
        } 
       } 
      } 

      // Move this circle 
      [touchedHandle setCenter:newCenter]; 

      // Adjust the Rectangle 
      // The origin and just be based on the Top Left handle. 
      float x = circleTL.center.x; 
      float y = circleTL.center.y; 

      // Get the width and height based on the difference between handles. 
      float width = abs(circleTR.center.x - circleTL.center.x); 
      float height = abs(circleBL.center.y - circleTL.center.y); 

      [rectangle setFrame:CGRectMake(x, y, width, height)]; 

      [gesture setTranslation:CGPointZero inView:self]; 
     } 
      break; 

     case UIGestureRecognizerStateEnded: 
      [touchedHandles removeObject:touchedHandle]; 
      break; 

     default: 
      break; 
    } 
} 

@end 

这只是一个概念证明。有很多缺失的警告,如能够拖出盒子,多点触摸并发症,负面尺寸。所有这些问题都可以用不同的方式处理,并且是使这样的事情从一个不错的想法变成一个美丽的自定义界面的秘诀。我会把这部分留给你。 :)

+0

我真的很喜欢这种方法有很多。看起来非常简单。当屏幕上同时存在多个这些对象时,您是否看到使用此方法的任何性能问题? – Clay 2013-02-12 19:51:12

+0

我不指望。我决定向其中投入一些代码。所以给我5分钟,我会有一个小例子,你可以尝试。 – 2013-02-12 19:52:14

+0

添加了一些代码:)希望它可以帮助你开始。试图留下一些有用的评论,但如果你有更多的问题不要犹豫。 – 2013-02-12 20:29:48