【问题标题】:How to create a dynamic rectangle on uiimage in ios?如何在ios中的uiimage上创建一个动态矩形?
【发布时间】:2013-09-24 10:26:24
【问题描述】:

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

【问题讨论】:

    标签: ios core-graphics nsbezierpath


    【解决方案1】:

    你需要使用 Core Graphics,试试这个教程:

    Quartz 2D Programming Guide

    【讨论】:

      【解决方案2】:

      听起来您可能想要一个选择矩形在 UIImage 之上,而不仅仅是调整图像大小的能力。

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

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

      根据我的经验,与 Autolayout 和 UIGestureRecognizers 相比,使用 YMMV 时,这种性质的动画在使用减震器和支柱以及 -touchesBegan 等时更容易实现。

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

      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
      

      【讨论】:

      • 你有可以分享给这个例子的 github 项目吗?
      【解决方案3】:

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

      How can I draw dynamic rectangle on screen according to touchMove event on iOS

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-02
        相关资源
        最近更新 更多