简体   繁体   English

如何继续drawRect:当手指在屏幕上时

[英]How to continue to drawRect: when finger on screen

I have the current code: 我有当前代码:

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

    self.objectPoint = [[touches anyObject] locationInView:self];
    float x, y;
    if (self.objectPoint.x > self.objectPoint.x) {
        x = self.objectPoint.x + 1;
    }
    else x = self.objectPoint.x - 1;
    if (self.fingerPoint.y > self.objectPoint.y) {
        y = self.objectPoint.y + 1;
    }
    else y = self.minionPoint.y - 1;
    self.objectPoint = CGPointMake(x, y);

    [self setNeedsDisplay];
}

My problem is that I want to keep the object follow your finger until you take your finger off the screen. 我的问题是我要让物体一直跟随您的手指,直到您将手指从屏幕上移开。 It will only follow if my finger is moving. 如果我的手指在移动,它只会跟随。 touchesEnded only works when I take my finger off the screen, so that's not what I want either. touchesEnded仅在我将手指从屏幕上touchesEnded时才有效,所以那也不是我想要的。 How can I enable something that would solve my problem? 如何启用可以解决我问题的功能?

If you want to touch a part of the screen and you want to move the drawn object in that direction as long as you're holding your finger down, there are a couple of approaches. 如果您想触摸屏幕的一部分,并且想要在不放开手指的情况下沿该方向移动绘制的对象,则有两种方法。

On approach is the use of some form of timer, something that will repeatedly call a method while the user is holding their finger down on the screen (because, as you noted, you only get updates to touchesMoved when you move). 进场方法是使用某种形式的计时器,这种方法会在用户将手指按住在屏幕上时重复调用一种方法(因为,正如您所指出的,移动时您只会获得touchesMoved更新)。 While NSTimer is the most common timer that you'd encounter, in this case you'd want to use a specialized timer called a display link, a CADisplayLink , that fires off when screen updates can be performed. 虽然NSTimer是您遇到的最常见的计时器,但在这种情况下,您需要使用一种称为显示链接的专用计时器,即CADisplayLink ,它可以在执行屏幕更新时触发。 So, you would: 因此,您将:

  • In touchesBegan , capture where the user touched on the screen and start the CADisplayLink ; touchesBegan ,捕获用户在屏幕上触摸的位置并启动CADisplayLink

  • In touchesMoved , you'd update the user's touch location (but only called if they moved their finger); touchesMoved ,您将更新用户的触摸位置(但只有在他们移动手指时才会调用);

  • In touchesEnded , you'd presumably stop the display link; touchesEnded ,您可能会停止显示链接; and

  • In your CADisplayLink handler, you'd update the location (and you'd need to know the speed with which you want it to move). CADisplayLink处理程序中,您将更新位置(并且您需要知道其移动速度)。

So, that would look like: 因此,它看起来像:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.velocity = 100.0;     // 100 points per second
    self.touchLocation = [[touches anyObject] locationInView:self];

    [self startDisplayLink];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.touchLocation = [[touches anyObject] locationInView:self];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self stopDisplayLink];
}

- (void)startDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
    self.lastTimestamp = CACurrentMediaTime();   // initialize the `lastTimestamp`
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stopDisplayLink
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
    // figure out the time elapsed, and reset the `lastTimestamp`

    CFTimeInterval currentTimestamp = CACurrentMediaTime();
    CFTimeInterval elapsed = currentTimestamp - self.lastTimestamp;
    self.lastTimestamp = currentTimestamp;

    // figure out distance to touch and distance we'd move on basis of velocity and elapsed time

    CGFloat distanceToTouch  = hypotf(self.touchLocation.y - self.objectPoint.y, self.touchLocation.x - self.objectPoint.x);
    CGFloat distanceWillMove = self.velocity * elapsed;

    // this does the calculation of the angle between the touch location and
    // the current `self.objectPoint`, and then updates `self.objectPoint` on
    // the basis of (a) the angle; and (b) the desired velocity.

    if (distanceToTouch == 0.0)                  // if we're already at touchLocation, then just quit
        return;
    if (distanceToTouch < distanceWillMove) {    // if the distance to move is less than the target, just move to touchLocation
        self.objectPoint = self.touchLocation;
    } else {                                     // otherwise, calculate where we're going to move to
        CGFloat angle = atan2f(self.touchLocation.y - self.objectPoint.y, self.touchLocation.x - self.objectPoint.x);
        self.objectPoint = CGPointMake(self.objectPoint.x + cosf(angle) * distanceWillMove,
                                       self.objectPoint.y + sinf(angle) * distanceWillMove);
    }
    [self setNeedsDisplay];
}

and to use that, you'd need a few properties defined: 并使用它,您需要定义一些属性:

@property (nonatomic) CGFloat velocity;
@property (nonatomic) CGPoint touchLocation;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic) CFTimeInterval lastTimestamp;

If you want to drag it with your finger, you want to: 如果要用手指拖动它,则需要:

  • In touchesBegan , save the starting locationInView as well as the "original location" of the object being dragged; touchesBegan ,保存起始locationInView以及要拖动的对象的“原始位置”;

  • In touchesMoved , get the new locationInView , calculate the delta (the "translation") between that and the original locationInView , add that to the saved "original location" of the view, and use that to update the view. touchesMoved ,获取新的locationInView ,计算该locationInView与原始locationInView之间的增量(“平移”),将其添加到视图的已保存“原始位置”,然后使用该值来更新视图。

That way, the object will track 100% with your finger as you're dragging it across the screen. 这样,当您在屏幕上拖动对象时,该对象将用手指跟踪100%。


For example, you might: 例如,您可能会:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.touchBeganLocation = [[touches anyObject] locationInView:self];
    self.originalObjectPoint = self.objectPoint;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint location = [[touches anyObject] locationInView:self];
    CGPoint translation = CGPointMake(location.x - self.touchBeganLocation.x, location.y - self.touchBeganLocation.y);
    self.objectPoint = CGPointMake(self.originalObjectPoint.x + translation.x, self.originalObjectPoint.y + translation.y);
    [self setNeedsDisplay];
}

Probably needless to say, you need properties to keep track of these two new CGPoint values: 可能无需多说,您需要一些属性来跟踪这两个新的CGPoint值:

@property (nonatomic) CGPoint originalObjectPoint;
@property (nonatomic) CGPoint touchBeganLocation;

Frankly, I might use gesture recognizer, but that's an example of dragging with touchesBegan and touchesMoved . 坦白地说,我可能会使用手势识别器,但这是使用touchesBegantouchesMoved拖动的示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM