0

我正在尝试在 imageview 上创建一个动态矩形。这意味着矩形应该从触摸开始,只要用户移动触摸,它就应该在那个方向上更大。请朋友推荐我。

4

3 回答 3

0

You need to use Core Graphics for that, try this tutorial:

Quartz 2D Programming Guide

于 2013-09-24T10:29:07.180 回答
0

听起来您可能希望在 UIImage顶部有一个选择矩形,而不仅仅是调整图像大小的能力。

如果是这种情况,我建议使用以下结构:

  1. 将 UIImage 加载到 UIImageView 并将其放置在屏幕上。
  2. 创建一个作为 UIImageView 兄弟的 UIView
  3. 覆盖 #2 中 UIView 的 -drawRect: 方法以简单地绘制带边框的轮廓。
  4. 使用 -touchesBegan:/-touchesMoved:/-touchesEnded: 等检测用户的触摸。
  5. 根据 #4 中的逻辑和数学,在动画块中调整 UIView 的框架。

根据我的经验,与 Autolayout 和 UIGestureRecognizers 相比,这种性质的动画在使用冲击和支柱和 -touchesBegan 等时更容易实现功能,但 YMMV。

当然,根据您回答以下问题的方式,您正在做的事情可能需要一些高级数学:

  1. 用户可以移动选择矩形吗?
  2. 我是否希望用户抓住“边缘”来调整它的大小?
  3. 用户必须离多近才能“抓住”边缘?
  4. 如果不是,用户是否只是向一个方向“推动”以使矩形变大,而不管他们的手指在哪里?

以下代码执行以下操作:

  1. 将图像加载到 UIImageView
  2. 允许用户放置一个 100x100 的选择矩形(起初)
  3. 允许用户通过在矩形内部触摸/拖动来移动选择矩形
  4. 允许用户通过抓取 8 个边缘区域之一来调整选择矩形的大小
  5. 更新选择矩形的绘图以从“非活动”模式指示“活动”模式

代码做出的假设:

  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 回答