Reputation: 13890
assume we have a UITableViewCell with an inner big custom UIImageView, like the image below:
I have added UILongPressGestureRecOgnizer
to the UITableViewCell, so after longPress user can move this big image. but I want this movement be in the bound of UITableViewCell
.
What I've done right now:
UIView *view = sender.view;
CGPoint point = [sender locationInView:view.superview];
if (sender.state == UIGestureRecognizerStateChanged)
{
CGPoint oldCenter = view.center;
CGPoint newCenter = oldCenter;
CGFloat deltaX = point.x - _priorPoint.x;
CGFloat deltaY = point.y - _priorPoint.y;
newCenter.x += deltaX;
newCenter.y += deltaY;
CGRect oldFrame = view.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x + deltaX, oldFrame.origin.y+deltaY, view.width, view.height);
if (CGRectContainsRect(newFrame, self.bounds)) {
self.customImageView.center = newCenter;
}
else
{
CGFloat newX = newFrame.origin.x;
CGFloat newY = newFrame.origin.y;
if (newX<view.x) {
newX = oldFrame.origin.x;
}
else if ((newFrame.origin.x + newFrame.size.width)>view.right)
{
newX = oldFrame.origin.x;
}
if (newY<view.y) {
newY = oldFrame.origin.y;
}
else if ((newY + newFrame.size.height)>view.bottom)
{
newY = view.y;
}
NSLog(@"newX:%f, newY:%f", newX, newY);
newFrame = CGRectMake(newX, newY, view.width, view.height);
self.customImageView.frame = newFrame;
}
_priorPoint = point;
the problem is when I move my finger diagonally, the image movement is a little jerky. while moving diagonally, for example when X
is out of bound, if Y
is valid, Y
point should be updated.
what's wrong here? do you have any idea?
Upvotes: 1
Views: 581
Reputation: 6211
What I do for this is a little hard to follow, but here goes...
I do the touch interaction inside the view that is moving. In touchesBegan
drawingFrame = self.frame;
initialViewOrigin = self.frame.origin;
startingTouch = [[touches anyObject] locationInView:[self superview]];
These are all class variables. Then in touchesMoved
:
lastTouchPoint = [[touches anyObject] locationInView:[self superview]];
float newLocationX = initialViewOrigin.x + (p.x - startingTouch.x);
float newLocationY = initialViewOrigin.y + (p.y - startingTouch.y);
//Do some location checks for sending it too far off the screen or whatnot
drawingFrame.origin = [self scrollLimit:newLocationX y:newLocationY];
CGRect frame = self.frame;
frame.origin.x = drawingFrame.origin.x;
frame.origin.y = drawingFrame.origin.y;
self.frame = frame;
All the fun stuff happens in the scrollLimit
function:
-(CGPoint)scrollLimit:(float)x1 y:(float)y1
{
//My app always requires landscape, so make sure the parent's sizes are taken accordingly
int parentHeight = MIN(self.superview.frame.size.width,self.superview.frame.size.height);
int parentWidth = MAX(self.superview.frame.size.width,self.superview.frame.size.height);
if(self.frame.size.width < parentWidth)
{
if(x1 < 1)
{
x1 = 1;
}
else if(x1 >= parentWidth - self.frame.size.width)
{
x1 = parentWidth - self.frame.size.width;
}
}
else{
x1 = initialViewOrigin.x;
}
if(self.frame.size.height < parentHeight)
{
if(y1 < 1)
{
y1 = 1;
}
else if(y1 > parentHeight - self.frame.size.height)
{
y1 = parentHeight - self.frame.size.height;
}
}
else{
y1 = initialViewOrigin.y;
}
return CGPointMake(x1,y1);
}
All of this makes sure that the view stays inside the bounds that you set (in my case just the superview bounds) and it also makes the dragging experience smooth and realistic. Some other methods I have seen can cause your finger to get off of the item you are scrolling and never sync back up. I'm sure my code won't work for you as is, but it should get you in the right direction.
In my methods I also have simulated inertia for view "throwing" while still keeping the bounding superview box. Since that is outside of your question and it took a very long time to get perfect, I'll leave that as an exercise to the reader...
Upvotes: 2