psimekjr
psimekjr

Reputation: 325

UIView drag (image and text)

Is it possible to drag UIView around the iOS screen while it has both image and text? e.g. small cards. Could you point me to the similar (solved) topic? I haven't found any.

Upvotes: 27

Views: 23335

Answers (6)

Roman Bambura
Roman Bambura

Reputation: 177

This work for me. My UIView rotated and scaled

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

UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];

if (!CGAffineTransformIsIdentity(self.transform)) {
    location = CGPointApplyAffineTransform(location, self.transform);
    previous = CGPointApplyAffineTransform(previous, self.transform);
}
CGRect newFrame = CGRectOffset(self.frame,
                               (location.x - previous.x),
                               (location.y - previous.y));
float x = CGRectGetMidX(newFrame);
float y = CGRectGetMidY(newFrame);
self.center = CGPointMake(x, y);

}

Upvotes: 0

Arie Litovsky
Arie Litovsky

Reputation: 4983

This is what a neat solution, based on pepouze's answer, would look like (tested, it works!)

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *aTouch = [touches anyObject];
    CGPoint location = [aTouch locationInView:self];
    CGPoint previousLocation = [aTouch previousLocationInView:self];
    self.frame = CGRectOffset(self.frame, (location.x - previousLocation.x), (location.y - previousLocation.y));
}

Upvotes: 36

Alexander Farber
Alexander Farber

Reputation: 22988

Here is a solution to drag a custom UIView (it can be scaled or rotated through its transform), which can hold images and/or text (just edit the Tile.xib as required):

app screenshot

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];
    CGPoint previous = [touch previousLocationInView:self];

    if (!CGAffineTransformIsIdentity(self.transform)) {
        location = CGPointApplyAffineTransform(location, self.transform);
        previous = CGPointApplyAffineTransform(previous, self.transform);
    }

    self.frame = CGRectOffset(self.frame,
                              (location.x - previous.x),
                              (location.y - previous.y));
}

Upvotes: 2

Rok Jarc
Rok Jarc

Reputation: 18865

An addition to MHC's answer.

If you don't want the upper left corner of the view to jump under your finger, you can also override touchesBegan like this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *aTouch = [touches anyObject];

    offset = [aTouch locationInView: self];
}

and change MHC's touchesMoved to:

 -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 {
      UITouch *aTouch = [touches anyObject];
      CGPoint location = [aTouch locationInView:self.superview];

      [UIView beginAnimations:@"Dragging A DraggableView" context:nil];
      self.frame = CGRectMake(location.x-offset.x, location.y-offset.y, 
                              self.frame.size.width, self.frame.size.height);
      [UIView commitAnimations];
  }

you should also define CGPoint offset in the interface:

@interface DraggableView : UIView
{
    CGPoint offset;
}

EDIT:

Arie Litovsky provides more elegant solution that allows you to ditch the ivar: https://stackoverflow.com/a/10378382/653513

Upvotes: 24

MHC
MHC

Reputation: 6405

While UIView does not have a built-in support for moving itself along the user dragging, it should be not so difficult to implement it. It is even easier when you are only dealing with dragging on the view, and not other actions such as tapping, double tapping, multi-touches etc.

First thing to do is to make a custom view, say DraggableView, by subclassing UIView. Then override UIView's touchesMoved:withEvent: method, and you can get a current dragging location there, and move the DraggableView. Look at the following example.

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *aTouch = [touches anyObject];
    CGPoint location = [aTouch locationInView:self.superview];
    [UIView beginAnimations:@"Dragging A DraggableView" context:nil];
    self.frame = CGRectMake(location.x, location.y, 
                            self.frame.size.width, self.frame.size.height);
    [UIView commitAnimations];
}

And because all subviews of the DraggableView object will be moved, too. So put all your images and texts as subviews of the DraggableView object.

What I implemented here is very simple. However, if you want more complex behaviors for the dragging, (for example, the user have to tap on the view for a few seconds to move the view), then you will have to override other event handling methods (touchesBegan:withEvent: and touchesEnd:withEvent) as well.

Upvotes: 34

pepouze
pepouze

Reputation: 171

Even though rokjarc solution works, using

CGPoint previousLocation = [aTouch previousLocationInView:self.superview];

avoids the CGPoint offset creation and the call to touchesBegan:withEvent:

Upvotes: 5

Related Questions