structure
UIViewController
- UIScrollview
- UIButton
I'm going to make scrollview can receive button event. So whenever user do scrolling(dragging) on the button, the scrollview react as scrolling itself.
I made button down and moved handler with event forwarding like below
- (IBAction)buttonTouchedMove:(id)sender withEvent:(UIEvent *)event {
[[sender nextResponder] touchesMoved:[event allTouches] withEvent:event];
}
- (IBAction)buttonTouchedDown:(id)sender withEvent:(UIEvent *)event {
[[sender nextResponder] touchesBegan:[event allTouches] withEvent:event];
}
and to move scrollview as touches change, I made below codes
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.oldPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint offset = self.scrollView1.contentOffset;
UITouch *touch = [touches anyObject];
self.newPoint = [touch locationInView:self.view];
int diffX = newPoint.x - oldPoint.x;
offset.x = offset.x - diffX;
[scrollView1 setContentOffset:offset animated:YES];
self.oldPoint = self.newPoint;
}
but, scrollview react strange.. not move enough as I touch moved.
// get the button width
CGFloat buttonWidth = self.theButton.frame.size.width;
// replace your button name here
// now get the view width
CGFloat viewWidth = self.view.frame.size.width;
// replace your view name here
// now get the multiplier which i said u as 10
CGFloat mult = viewWidth / buttonWidth;
// and now use it in your code
.
.
.
diffX = mult*(newPoint.x - oldPoint.x);
.
.
.
Final answer, Using UIView animation, I got what i want.
- (IBAction)buttonTouchedDown:(id)sender withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
self.oldPoint = [touch locationInView:self.view];
self.velocity = 0;
isButtonTouchedDown = YES;
}
- (IBAction)buttonTouchedMove:(id)sender withEvent:(UIEvent *)event {
CGPoint offset = self.scrollView1.contentOffset;
UITouch *touch = [[event allTouches] anyObject];
self.newPoint = [touch locationInView:self.view];
int diffX = self.newPoint.x - self.oldPoint.x;
velocity = diffX;
offset.x = offset.x - diffX;
[self.scrollView1 setContentOffset:offset animated:NO];
self.oldPoint = self.newPoint;
}
There is a trick..I calculated velocity by differentiating moved distance in TouchedMove function.
In Button TouchUp event handler, I controlled Scrollview with velocity value and CurveEaseout animation to scroll more. By offering very short duration of animation and repeating it if there is no event(button touched down). It becomes very similar with scrollview's animation.
- (IBAction)buttonTouchedUp:(id)sender withEvent:(UIEvent *)event {
CGPoint offset = self.scrollView1.contentOffset;
amountX = (self.velocity)*(abs(self.velocity));
dX = amountX;
isButtonTouchedDown = NO;
if (offset.x - amountX < 0) {
offset.x = 0;
[scrollView1 setContentOffset:offset animated:YES];
}
else if (abs(dX) < 70) { // 70: content item size
offset.x = roundf(offset.x/70)*70;
[scrollView1 setContentOffset:offset animated:YES];
}
else {
[self endScrollAnimation];
}
- (void)startAnimation:(float)x moveAmount:(float)moveAmount
{
CGPoint offset = self.scrollView1.contentOffset;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
offset.x = x < 0 ? offset.x + moveAmount : offset.x -moveAmount;
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(endScrollAnimation)];
[scrollView1 setContentOffset:offset animated:NO];
[UIView commitAnimations];
}
- (void)endScrollAnimation
{
CGPoint offset = self.scrollView1.contentOffset;
float slowMoveAmount = abs(amountX) * 0.05;
float fastMoveAmount = abs(amountX) * 0.1;
if (isButtonTouchedDown) {
return;
}
else if (abs(dX) > abs(amountX)*0.35 && offset.x > 0) {
[self startAnimation:dX moveAmount:fastMoveAmount];
dX = dX < 0 ? dX + fastMoveAmount : dX -fastMoveAmount;
}
else if (abs(dX) > slowMoveAmount && offset.x > 0) {
[self startAnimation:dX moveAmount:slowMoveAmount];
dX = dX < 0 ? dX + slowMoveAmount : dX - slowMoveAmount;
}
else {
offset.x = roundf(offset.x/70)*70;
[scrollView1 setContentOffset:offset animated:YES];
}
}