如何在 ios 中的 uiimage 上创建动态矩形



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

为此,

您需要使用Core Graphics,请尝试本教程:

石英 2D 编程指南

听起来您可能

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

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

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

根据我的经验,这种性质的动画在使用冲击、支柱和触摸等时更容易发挥作用,而不是自动布局和 UIGestureRecognizers,而是 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

您可以通过编程方式创建 imageview,并在触摸移动时调整其框架的大小。请参阅下面的链接,希望对您有所帮助。

如何在iOS上根据触摸移动事件在屏幕上绘制动态矩形

相关内容

  • 没有找到相关文章

最新更新