0

イメージビューで動的な長方形を作成しようとしています。これは、長方形がタッチで始まり、ユーザーがタッチを動かしている限り、その方向に大きくなる必要があることを意味します。友人が私に提案してください。

4

3 に答える 3

0

画像のサイズを変更する機能だけでなく、UIImage の上に選択用の四角形が必要なようです。

その場合は、次の構造をお勧めします。

  1. UIImage を UIImageView にロードし、それを画面に配置します。
  2. UIImageView の兄弟である UIView を作成します
  3. #2 の UIView の -drawRect: メソッドをオーバーライドして、単純に縁取りされたアウトラインを描画します。
  4. -touchesBegan:/-touchesMoved:/-touchesEnded: などを使用して、ユーザーのタッチを検出します。
  5. #4 のロジックと数学に基づいて、アニメーション ブロックで UIView のフレームを調整します。

私の経験では、この性質のアニメーションは、Autolayout や UIGestureRecognizers ではなく YMMV とは対照的に、shock や struts、-touchesBegan などを使用すると簡単に機能させることができます。

もちろん、次のような質問への回答方法によっては、高度な計算が必要になる場合があります。

  1. ユーザーは選択長方形を移動できますか?
  2. ユーザーが「エッジ」をつかんでサイズを変更できるようにする必要がありますか?
  3. エッジを「つかむ」には、ユーザーはどれくらい近づく必要がありますか?
  4. そうでない場合、指の位置に関係なく、ユーザーは四角形を大きくする方向に「押す」だけですか?

次のコードは、次のことを行います。

  1. 画像を UIImageView にロードします
  2. ユーザーが 100x100 の選択長方形を配置できるようにします (最初)。
  3. ユーザーが長方形の内部でタッチ/ドラッグして選択長方形を移動できるようにします
  4. ユーザーが 8 つのエッジ領域の 1 つをつかんで、選択した四角形のサイズを変更できるようにします
  5. 「非アクティブ」モードから「アクティブ」モードを示すように、選択長方形の描画を更新します

コードによる仮定:

  1. ユーザーは 1 本の指で画面を操作します
  2. UIImageView はビュー全体を占有します

このコードに必要な可能性のある更新:

  1. ユーザーは選択長方形を部分的に画面外に移動できます
  2. このコードは、選択長方形で何も行いません(選択長方形の内容のスナップショット/画像を取得するなど)。
#define GRAB_DISTANCE                       10
#define VIEW_PLACEMENT_ANIMATION_DURATION   0.1
#define VIEW_SIZING_ANIMATION_DURATION      0.1
typedef enum {
    kMSSLineTypeDashed,
    kMSSLineTypeSolid
} MSSLineType;
typedef enum {
    kMSSRectangleGrabZoneBottom,
    kMSSRectangleGrabZoneBottomLeft,
    kMSSRectangleGrabZoneBottomRight,
    kMSSRectangleGrabZoneLeft,
    kMSSRectangleGrabZoneNone,
    kMSSRectangleGrabZoneRight,
    kMSSRectangleGrabZoneTop,
    kMSSRectangleGrabZoneTopLeft,
    kMSSRectangleGrabZoneTopRight
} MSSRectangleGrabZone;
typedef enum {
    kMSSRectangleStatusNone,
    kMSSRectangleStatusPlacement,
    kMSSRectangleStatusResizing
} MSSRectangleStatus;
@interface MSSSelectionView : UIView
@property (assign, nonatomic)   MSSLineType  currentLineType;
@property (strong, nonatomic)   UIColor     *borderColor;
@end
@implementation MSSSelectionView
- (void)awakeFromNib {
    [super awakeFromNib];
    self.currentLineType = kMSSLineTypeSolid;
}
- (void)drawRect:(CGRect)rect {
    // Just make a border, 2 points wide, 1 point inset (so it is all contained by the view)
    CGContextRef context    = UIGraphicsGetCurrentContext();
    CGRect borderRect       = CGRectInset(rect, 1, 1);
    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, 2.0f);
    switch (self.currentLineType) {
        case kMSSLineTypeDashed:
        {
            CGFloat lengths[2] = {3, 4};
            CGContextSetLineDash(context, 0.0f, lengths, 2);
        }
            break;

        case kMSSLineTypeSolid:
        {
            CGContextSetLineDash(context, 0.0f, NULL, 0);
        }
            break;

        default:
            break;
    }
    [self.borderColor setStroke];
    CGContextStrokeRect(context, borderRect);
}
@end
#import "MSSViewController.h"
@interface MSSViewController ()
@property (assign, nonatomic)           BOOL                     selectionIsVisible;
@property (assign, nonatomic)           MSSRectangleGrabZone     currentGrabZone;
@property (assign, nonatomic)           MSSRectangleStatus       currentStatus;
@property (strong, nonatomic) IBOutlet  MSSSelectionView        *selectionView;
@property (strong, nonatomic) IBOutlet  UIImageView             *imageView;
@end
@implementation MSSViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.imageView.image    = [UIImage imageNamed:@"image.jpg"];
    self.currentGrabZone    = kMSSRectangleGrabZoneNone;
    self.currentStatus      = kMSSRectangleStatusNone;
}
#pragma mark - Touch Handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // Get a touch object (assuming just a 1-finger touch here)
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self.view];

    if (self.selectionIsVisible == NO) {
        // Showing the selection view for the first time

        // Update instance property
        self.selectionIsVisible = YES;

        // Place the rectangle (centered around touch)
        self.selectionView.center = location;

        // Unhide the rectangle
        self.selectionView.hidden = NO;

        // Set the status flag to placement
        self.currentStatus = kMSSRectangleStatusPlacement;

        // Change the border color to indicate that it's active
        self.selectionView.borderColor      = [UIColor lightGrayColor];
        self.selectionView.currentLineType  = kMSSLineTypeDashed;
        [self.selectionView setNeedsDisplay];

    } else {
        // Selection view already visible, so first make sure the touch was inside the selection view
        if (CGRectContainsPoint(self.selectionView.frame, location)) {
            // The touch was inside the selection view, so update the selection view's line drawing properties
            self.selectionView.borderColor      = [UIColor lightGrayColor];
            self.selectionView.currentLineType  = kMSSLineTypeDashed;
            [self.selectionView setNeedsDisplay];

            // Set status flag based on proximity to edge
            BOOL edgeGrabbed = [self location:location inGrabZoneForRect:self.selectionView.frame];
            if (edgeGrabbed == YES) {
                // The user has grabbed the edge, so allow selection view resizing
                self.currentStatus      = kMSSRectangleStatusResizing;
                self.currentGrabZone    = [self zoneGrabbedForPoint:location inRect:self.selectionView.frame];

            } else {
                // The user has touched the interior, so allow selection view movement/placement
                self.currentStatus      = kMSSRectangleStatusPlacement;
                self.currentGrabZone    = kMSSRectangleGrabZoneNone;
            }

        }

    }

}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    // Get a touch object (assuming just a 1-finger touch here)
    UITouch *touch              = [touches anyObject];
    CGPoint currentLocation     = [touch locationInView:self.view];
    CGPoint previousLocation    = [touch previousLocationInView:self.view];
    CGFloat xDelta              = currentLocation.x - previousLocation.x;
    CGFloat yDelta              = currentLocation.y - previousLocation.y;
    CGRect frame                = self.selectionView.frame;


    switch (self.currentStatus) {
        case kMSSRectangleStatusNone:
            // Do nothing
            break;

        case kMSSRectangleStatusPlacement:
        {
            // The entire selection view should be moved under the user's finger
            frame.origin.x      = frame.origin.x + xDelta;
            frame.origin.y      = frame.origin.y + yDelta;
        }
            break;

        case kMSSRectangleStatusResizing:
        {
            switch (self.currentGrabZone) {
                case kMSSRectangleGrabZoneBottom:
                {
                    // Make the view's frame taller or shorter based on yDelta
                    frame.size.height   = frame.size.height + yDelta;

                }
                    break;

                case kMSSRectangleGrabZoneBottomLeft:
                {
                    // Make the view's frame taller or shorter based on yDelta
                    // Make the view's frame wider or narrower PLUS move origin based on xDelta
                    frame.origin.x      = frame.origin.x    + xDelta;
                    frame.size.height   = frame.size.height + yDelta;
                    frame.size.width    = frame.size.width  - xDelta;

                }
                    break;

                case kMSSRectangleGrabZoneBottomRight:
                {
                    // Make the view's frame taller or shorter based on yDelta
                    // Make the view's frame wider or narrower based on xDelta
                    frame.size.height   = frame.size.height + yDelta;
                    frame.size.width    = frame.size.width  + xDelta;

                }
                    break;

                case kMSSRectangleGrabZoneLeft:
                {
                    // Make the view's frame wider or narrower PLUS move origin based on xDelta
                    frame.origin.x      = frame.origin.x    + xDelta;
                    frame.size.width    = frame.size.width  - xDelta;

                }
                    break;

                case kMSSRectangleGrabZoneNone:
                    // Do nothing
                    break;

                case kMSSRectangleGrabZoneRight:
                {
                    // Make the view's frame wider or narrower based on xDelta
                    frame.size.width    = frame.size.width  + xDelta;
                }
                    break;

                case kMSSRectangleGrabZoneTop:
                {
                    // Make the view's frame taller or shorter PLUS move origin based on yDelta
                    frame.origin.y      = frame.origin.y    + yDelta;
                    frame.size.height   = frame.size.height - yDelta;
                }
                    break;

                case kMSSRectangleGrabZoneTopLeft:
                {
                    // Make the view's frame wider or narrower PLUS move origin based on xDelta
                    // Make the view's frame taller or shorter PLUS move origin based on yDelta
                    frame.origin.x      = frame.origin.x    + xDelta;
                    frame.origin.y      = frame.origin.y    + yDelta;
                    frame.size.width    = frame.size.width  - xDelta;
                    frame.size.height   = frame.size.height - yDelta;
                }
                    break;

                case kMSSRectangleGrabZoneTopRight:
                {
                    // Make the view's frame wider or narrower based on xDelta
                    // Make the view's frame taller or shorter PLUS move origin based on yDelta
                    frame.origin.y      = frame.origin.y    + yDelta;
                    frame.size.height   = frame.size.height - yDelta;
                    frame.size.width    = frame.size.width  + xDelta;
                }
                    break;

                default:
                    break;
            }
        }
            break;

        default:
            break;
    }
    // Any frame changes made above should be animated here
    [UIView animateWithDuration:VIEW_PLACEMENT_ANIMATION_DURATION
                     animations:^{
                         self.selectionView.frame = frame;
                     }
                     completion:^(BOOL finished) {
                         [self.selectionView setNeedsDisplay];
                     }
     ];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    // Nothing much to do, just make the border black to indicate activity is done
    self.currentGrabZone                = kMSSRectangleGrabZoneNone;
    self.currentStatus                  = kMSSRectangleStatusNone;
    self.selectionView.borderColor      = [UIColor blackColor];
    self.selectionView.currentLineType  = kMSSLineTypeSolid;
    [self.selectionView setNeedsDisplay];

}
#pragma mark - Rectangle helper methods
- (BOOL)location:(CGPoint)location inGrabZoneForRect:(CGRect)rect {
    if (CGRectContainsPoint(rect, location)) {

        // The point is inside the rectangle, so determine if it's in the grab zone or the interior
        CGRect nonGrabZoneRect = CGRectInset(rect, GRAB_DISTANCE, GRAB_DISTANCE);

        if (CGRectContainsPoint(nonGrabZoneRect, location)) {
            // This point is in the interior (non-grab zone)
            return NO;

        } else {
            // This point is in the grab zone
            return YES;

        }

    } else {
        // The point is not inside the rectangle, which means they didn't grab the edge/border
        return NO;

    }

}
- (MSSRectangleGrabZone)zoneGrabbedForPoint:(CGPoint)point inRect:(CGRect)rect {
    CGRect topLeftGrabZone      = CGRectMake(rect.origin.x,                                     rect.origin.y,                                      GRAB_DISTANCE,                          GRAB_DISTANCE);
    CGRect topGrabZone          = CGRectMake(rect.origin.x + GRAB_DISTANCE,                     rect.origin.y,                                      rect.size.width - (2 * GRAB_DISTANCE),  GRAB_DISTANCE);
    CGRect topRightGrabZone     = CGRectMake(rect.origin.x + rect.size.width - GRAB_DISTANCE,   rect.origin.y,                                      GRAB_DISTANCE,                          GRAB_DISTANCE);

    CGRect leftGrabZone         = CGRectMake(rect.origin.x,                                     rect.origin.y + GRAB_DISTANCE,                      GRAB_DISTANCE,                          rect.size.height - (2 * GRAB_DISTANCE));

    CGRect rightGrabZone        = CGRectMake(rect.origin.x + rect.size.width - GRAB_DISTANCE,   rect.origin.y + GRAB_DISTANCE,                      GRAB_DISTANCE,                          rect.size.height - (2 * GRAB_DISTANCE));

    CGRect bottomLeftGrabZone   = CGRectMake(rect.origin.x,                                     rect.origin.y + rect.size.height - GRAB_DISTANCE,   GRAB_DISTANCE,                          GRAB_DISTANCE);
    CGRect bottomGrabZone       = CGRectMake(rect.origin.x + GRAB_DISTANCE,                     rect.origin.y + rect.size.height - GRAB_DISTANCE,   rect.size.width - (2 * GRAB_DISTANCE),  GRAB_DISTANCE);
    CGRect bottomRightGrabZone  = CGRectMake(rect.origin.x + rect.size.width - GRAB_DISTANCE,   rect.origin.y + rect.size.height - GRAB_DISTANCE,   GRAB_DISTANCE,                          GRAB_DISTANCE);

    if (CGRectContainsPoint(topLeftGrabZone, point)) {
        return kMSSRectangleGrabZoneTopLeft;

    } else if (CGRectContainsPoint(topGrabZone, point)) {
        return kMSSRectangleGrabZoneTop;

    } else if (CGRectContainsPoint(topRightGrabZone, point)) {
        return kMSSRectangleGrabZoneTopRight;

    } else if (CGRectContainsPoint(leftGrabZone, point)) {
        return kMSSRectangleGrabZoneLeft;

    } else if (CGRectContainsPoint(rightGrabZone, point)) {
        return kMSSRectangleGrabZoneRight;

    } else if (CGRectContainsPoint(bottomLeftGrabZone, point)) {
        return kMSSRectangleGrabZoneBottomLeft;

    } else if (CGRectContainsPoint(bottomGrabZone, point)) {
        return kMSSRectangleGrabZoneBottom;

    } else if (CGRectContainsPoint(bottomRightGrabZone, point)) {
        return kMSSRectangleGrabZoneBottomRight;

    } else {
        return kMSSRectangleGrabZoneNone;

    }
}
@end
于 2014-02-07T14:42:05.820 に答える
-1

プログラムでイメージビューを作成し、タッチの動きに合わせてフレームのサイズを変更できます。以下のリンクを参照してください。

iOSのtouchMoveイベントに従って、画面上に動的な長方形を描画するにはどうすればよいですか

于 2013-09-24T10:30:39.720 に答える