我正在尝试在imageview上构建一个动态矩形。 这意味着矩形应该从触摸开始,只要用户移动触摸,它应该在这个方向上更大。朋友建议我,请。
您需要使用Core Graphics,请尝试本教程:
石英 2D 编程指南
希望在UIImage顶部有一个选择矩形,而不仅仅是调整图像大小的能力。
如果是这种情况,我建议使用以下结构:
- 将 UIImage 加载到 UIImageView 中,并将其放置在屏幕上。
- 创建作为 UIImageView 同级的 UIView
- 重写 #2 中 UIView 的 -drawRect: 方法,以简单地绘制边框轮廓。
- 使用 -touchesBegan:/-touchesMoved:/-touchesEnded:等检测用户的触摸。
- 根据 #4 中的逻辑和数学,在动画块中调整 UIView 的帧。
根据我的经验,这种性质的动画在使用冲击、支柱和触摸等时更容易发挥作用,而不是自动布局和 UIGestureRecognizers,而是 YMMV。
当然,你正在做的事情可能需要一些高等数学,这取决于你如何回答如下问题:
- 用户可以移动选择矩形吗?
- 我是否希望用户抓住"边缘"以便能够调整其大小?
- 用户必须离多近才能"抓住"边缘?
- 如果不是,用户是否只是向某个方向"推动"以使矩形变大,无论他们的手指在哪里?
以下代码执行以下操作:
- 将图像加载到 UIImageView 中
- 允许用户放置一个 100x100 的选择矩形(首先(
- 允许用户通过触摸/拖动矩形内部来移动选择矩形
- 允许用户通过抓取 8 个边缘区域之一来调整所选矩形的大小
- 更新选择矩形的绘图,以指示"活动"模式和"非活动"模式
代码所做的假设:
- 用户将使用一根手指与屏幕交互
- UIImageView占据了整个视图
此代码可能需要的更新:
- 用户可以将选择矩形部分移出屏幕
- 此代码不会对选择矩形执行任何操作(例如,拍摄选择矩形内容的快照/图像(
#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上根据触摸移动事件在屏幕上绘制动态矩形