带圆形句柄的UIBezierPath矩形

时间:2013-02-12 19:30:02

标签: ios core-graphics uibezierpath

我正在尝试绘制一个有四个圆形手柄的矩形。这就是它的样子:

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

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

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

2 个答案:

答案 0 :(得分:4)

我不会将它绘制为具有复杂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

这只是一个概念证明。有许多缺失的警告,如能够在盒子外面拖动,多点触控并发症,负面大小。所有这些问题都可以用非常不同的方式处理,并且这样做的秘诀就是从一个好主意变成一个漂亮的自定义界面。我会把那部分留给你。 :)

答案 1 :(得分:1)

在实现手势识别器时,您需要在类中存储圆圈贝塞尔路径。

Apple文档描述了如何实现接受带图片和示例代码的触摸事件的UIView或UIControl。

http://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/multitouch_background/multitouch_background.html#//apple_ref/doc/uid/TP40009541-CH5-SW9