UIScrollView ContentOffset not Reaching Edge of Screen - iphone

I'm having a problem with UIScrollView, not sure if it's a bug or not, but it's occurring when I implement a UIScrollView with its delegate and a zoomable / pannable image.
First off, when I pan the image, it's possible that the contentOffset can be a non integer value (.5). For certain zoomScales, when I pan the image all the way to the edge, it's falling a half pixel shy of reaching the edge because of this.
It's a very small thing, but in my app I have to drag objects around the screen, and if I drag an object to the corner, you can notice it.
I've implemented the following to try and correct the problem and make it so the contentOffset has to be a whole value:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (targetContentOffset->x != ceilf(targetContentOffset->x))
{
if (velocity.x > 0)
{
targetContentOffset->x = ceilf(targetContentOffset->x);
}
else
{
targetContentOffset->x = floorf(targetContentOffset->x);
}
}
if (targetContentOffset->y != ceilf(targetContentOffset->y))
{
if (velocity.y > 0)
{
targetContentOffset->y = ceilf(targetContentOffset->y);
}
else
{
targetContentOffset->y = floorf(targetContentOffset->y);
}
}
}
However, it doesn't seem to be working as my targetContentOffset is completely different than the contentOffset property.
Does anyone a) why this bug is occurring or b) how to fix it using the above delegate method or some other means?

Alternatively this method implementation may work for you also.
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
Looking at your comments below, you may have to implement multiple methods. The one above or the one stated in the other answer post for when it slows to a stop, just to make sure you touch your edge condition, and the method you already have to process for the velocity points.

Related

Checking to see if point in child view is in parent view

I have the following set-up:
Where the light blue view, let's call it parentView, has a rectangular subview (the purple view) called childView. The user can use pan touches to rotate and stretch childView by putting their finger on the point exhibited by the red dot and pushing it or pulling it.
It's possible that the childView could be scaled small enough to that after the user is finished with its touches, the point denoted by the red dot would be inside of the parentView.
My goal is to create a method that can detect if the red point is in the parentView or not. I've written the following code:
CGPoint childViewRedPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height / 2);
CGPoint rotatedChildViewRedPoint = CGPointApplyAffineTransform(childViewRedPoint, CGAffineTransformMakeRotation(self.rotateAngle));
CGPoint convertedChildViewRedPoint = [self convertPoint:rotatedChildViewRedPoint toView:self.superview];
if (CGRectContainsPoint(self.superview.bounds, convertedChildViewRedPoint))
{
return YES;
}
else
{
return NO;
}
First I find the red point as defined within the childView, then I rotate it by the amount that the view has been rotated, then I convert it to be in the parentViews coordinates.
The points I'm getting don't seem to make sense and this isn't working. Was wondering if anyone knows where I'm going wrong here? Am I not taking parentViews superview into account?
I am not 100% sure, but I think that convertPoint: already takes a rotation (or any other transformation) into account, so you only need:
CGPoint childViewRedPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height / 2);
CGPoint convertedChildViewRedPoint = [self convertPoint:childViewRedPoint toView:self.superview];
if (CGRectContainsPoint(self.superview.bounds, convertedChildViewRedPoint))
...

UIScrollView determine scroll direction on scrollViewDidEndDragging when paging

Does anyone know how to determine which direction a scroll view will move when the user lifts their finger, i.e. when scrollViewDidEndDragging gets called?
Specifically, when the scroll view is set to paging.
Most of the time, I can just track and check the contentOffset in scrollViewDidScroll, however, there are special cases where the user flicks the screen quickly. In some cases a LEFT-RIGHT-LEFT move will scroll to the next page, and in others, the same pattern will remain on the same page.
I'm guessing it has something to do the with acceleration (difference between the last few points) of the touch.
(I'm on iOS4.3 on an iPad)
You don't use timer, which is very expensive operation. Lock the direction of your scrollView first to move only up/down and left/right [I guess that's what you want]. And then use following code to determine...
CGPoint start, end;
- (void)scrollViewWillBeginDragging:(UIScrollView *)sender {
start = self.scrollView.contentOffset;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)sender willDecelerate:(BOOL)decelerate {
end = self.scrollView.contentOffset;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
NSLog(#"%d %d",(int)start.x,(int)start.y);
NSLog(#"%d %d",(int)end.x,(int)end.y);
}
Here is my solution works fine for me hope it helps
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat pageWidth = scrollView.frame.size.width;
//Old Solution
//Switch the indicator when more than 30% of the previous/next page is visible
//You can vary the percentage
//int page = floor((scrollView.contentOffset.x - pageWidth * 0.3) / pageWidth) + 1;
//New Solution
_pageControl.currentPage = (int)scrollView.contentOffset.x / (int)pageWidth;
}
I quit the old solution as the new one seems more slick
Implement the following UIScrollViewDelegate Method.
You can compare current content offset and targetContentOffset then get the direction.
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
CGPoint newOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y);
if (newOffset.x > scrollView.contentOffset.x) {
NSLog(#"Scrolling direction is left");
}else{
NSLog(#"Scrolling direction is right");
}
}
This is a tricky one, iOS 5 has the answer, but that no good for you.
Perhaps a hacky workaround is to set a NSTimer for a small time interval (say 0.1 seconds) after scrollViewDidEndDragging finished. Then compare the content offsets.
If you want to know if the scroll view will actually go to the next page, perhaps you could check if the content offset has gone more than 1/2 way. You could read the content offset on scrollViewDidScroll: and do a bit of maths to determine if its more than 1/2 way.
In addition to saurin response.
Her solution work fine but if you are using pagination and you are in the end of scroll content size you will have to test if we really have a scroll to the next 'page' or not:
CGPoint start, end;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
start = scrollView.contentOffset;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
end = scrollView.contentOffset;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (start.x > end.x && end.x>0)
{
NSLog(#"on the previous left page");
}
if (start.x < end.x && end.x < scrollView.contentOffset.x)
{
NSLog(#"on the next right page");
}
}

UIImage collision effect...??? Iphone

I need a way to create a collide effect, without the actual collision between the two images. Let me explain in more detail... If I have one fixed image and one image that is moving both images are on the same x coordinate at different positions. Basically I want the images appear to be colliding.I would want to run a check on the moving image like this...
If (front of moving image is clear)
{[move forward];}
else
{[stop];}
How would I implement this in code??? So that right before the moving image collides into the fixed image it stops, so that they appear to have collided.This check would also be running on a 1/60 NSTimer.
Any advice is welcome. Thank you.
Assuming the object is moving from the left
#define PIXELS_PER_FRAME 1
-(CGFloat) getCurrentX:(UIImage*)image
{
return image.frame.origin.x + image.frame.size.width;
}
-(void) moveImageToStableImage
{
CGFloat xTarget = stableImage.frame.origin.x;
if([self getCurrentX:movingImage] < xTarget)
{
movingImage.frame.origin.x += PIXELS_PER_FRAME;
[self performSelector:#selector(moveImageToStableImage) withObject:nil afterDelay:1.0/60];
}
}
But truth be told in this situation you would probably just be better off using an animation

iPhone: Scroll images infinitely

In my iPhone app I'm looking for a solution where I have some images scrolling horizontally, automatically and infinitely around and around. So if I have four images: first image 1 is shown, then it automatically scrolls out, image 2 is shown, then it scrolls out, ... image 4 is shown, then it scrolls out, and then image 1 is shown again and around it goes... (image1->image2->image3->image4->image1...)
I have been looking for a solution where I use a UIScrollView, but I'm not sure how to implement it. Is there a tutorial or anything on how to do this? How would you solve it? Thanks!
You can implement the ScrollViewDelegate's - (void)scrollViewDidScroll:(UIScrollView *)scrollView method and use the setContentOffset of the scroll view once the content offset is larger than some maximum or less than some minimum.
Before doing that you will have to duplicate the contents of the scroll view at least 3 times, like this: .
Once the scroll offset reaches the duplicated content you will have to set the offset to the original content offset...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.infiniteScrollView) {
CGFloat xOffset = scrollView.contentOffset.x;
CGFloat yOffset = scrollView.contentOffset.y;
if (xOffset > maxOffset) {
xOffset = origOffset + (xOffset - maxOffset);
}
else if (xOffset < minOffset) {
xOffset = origOffset + (xOffset - minOffset);
}
if (xOffset != scrollView.contentOffset.x) {
[scrollView setContentOffset:CGPointMake(xOffset ,yOffset)];
}
}
}

Changing X & Y of Button upon Rotation

Edited Mar 30 - Note: Monotouch used. When I rotate to LandscapeRight/Left I want to change the location of some of my buttons. Here's what I'm trying:
Have my ShouldAutorotateToInterfaceOrientation returning True.
In my WillRotate (I tried putting this in DidRotate as well) it doesn't show any difference, here's my code:
public override void WillRotate (UIInterfaceOrientation toInterfaceOrientation, double duration)
{
// As a test move one of the buttons somewhere different than where it should be
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(40, 1,
btn2.Bounds.Width, btn2.Bounds.Height);
btn2.Bounds = rect;
}
I figure that changing the bounds may not be the right way, but given that the Bounds.X and Bounds.Y are immutable, this was the only way I could find to change the position.
This is what you want...
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
It can be found here.
The idea is to adjust the X and Y of any objects you want to move around after you determine the direction of the move.