3

4 つの円形ハンドルを持つ四角形を描画しようとしています。これは次のようになります。

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

円形のハンドルは「ホット」です。つまり、ユーザーがハンドルに触れると、残りのポイントが固定されている間にハンドルを移動できます。誰かがこの機能をコーディングするためのアプローチを持っているかどうか知りたかった. UIBezierPath で四角形を円で描画しようとしているのですが、ユーザーが円だけをタップできるようにする方法を考えるのに苦労しています。5 つの異なる UIBezierPath オブジェクトが必要になるかもしれないと考えていましたが、最終的に UI はこれらのオブジェクトの倍数で構成されます。

どんな提案でも大歓迎です。ありがとう。

4

2 に答える 2

4

UIBezierPath複雑なs を持つ単一の形状としてはまったく描きません。私はそれを6つの異なる部分として考えます。コンテナ、長方形、および 4 つの円。

長方形のビューとその角UIViewに 4 つの円形がある単純なコンテナーがあります。UIViews次に、UIPanGestureRecognizer各円に a を付けます。ジェスチャ ハンドラーで、円の中心を移動し、下にある四角形を同じ量だけ調整します。これにより、複雑なパスや計算を回避し、長方形自体の量を簡単に加算および減算できます。

更新: コード!

すべてを処理する自己完結型の 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

これは概念実証にすぎません。ボックスの外にドラッグできること、マルチタッチの複雑さ、負のサイズなど、見逃されている警告がたくさんあります。これらの問題はすべて非常に異なる方法で処理することができ、このようなものを素晴らしいアイデアから美しいカスタム インターフェイスに変える秘密のソースです。その部分はお任せします。:)

于 2013-02-12T19:40:41.033 に答える
1

ジェスチャ レコグナイザーを実装するときのために、サークル ベジエ パスをクラスに保存する必要があります。

タッチ イベントを受け入れる UIView または UIControl を画像とサンプル コードで実装する方法を説明している Apple ドキュメントがあります。

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

于 2013-02-12T19:38:37.273 に答える