UIScrollview with paging like effect - iphone

I have a uiscrollview. Scrollview contains multiple uiview as subview.I want paging like animation effect to scrollview. I have set scrollview.pagingEnabled=NO.
Following is my code
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
lastContentOffset = scrollView.contentOffset.x;
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
ScrollDirection scrollDirection;
if (self.lastContentOffset >scrollView.contentOffset.x) {
scrollDirection = ScrollDirectionRight; } else if (self.lastContentOffset < scrollView.contentOffset.x) {
scrollDirection = ScrollDirectionLeft;
}
if (scrollDirection==ScrollDirectionRight) {
CGFloat xOffset = scrollview.contentOffset.x;
CGFloat yOffset = scrollview.contentOffset.y;
if (scrollview.contentOffset.x != scrollview.frame.origin.x)
{
[scrollview setContentOffset:CGPointMake(xOffset- 320, yOffset) animated:YES];
}
NSLog(#" ScrollDirectionRight custom x==%f %f", scrollview.contentOffset.x, scrollview.contentSize.width);
} else if(scrollDirection==ScrollDirectionLeft) {
CGFloat xOffset = scrollview.contentOffset.x;
CGFloat yOffset = scrollview.contentOffset.y;
if ((scrollview.contentOffset.x != scrollview.frame.origin.x) )
{
[scrollview setContentOffset:CGPointMake(xOffset + 320, yOffset) animated:YES];
}
NSLog(#"ScrollDirectionLeft custom x==%f %f", scrollview.contentOffset.x, scrollview.contentSize.width);
}
}
Through this code im getting paging like effect.but the effect is not smooth.
Thanks

Check out UIScrollViewDelegate method
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
In this callback you will modify 'targetContentOffset' to where you like to see scroll offset animation end.
Using it you can make custom pagination implementation a lot smoother.

Related

imageview in a scrollview not zooming in some portion of view

i've implemented imageview zooming in scrollview application in my app.
i want to set the scrollview and imageview on the right top of the view. but it's not zooming there. when i placed it on centre of view it's zooming.
The code is given below
#interface przoomViewController : UIViewController<UIScrollViewDelegate>
{
IBOutlet UIScrollView *scrollView;
IBOutlet UIImageView *image;
}
-(void)viewDidLoad
{
[image setUserInteractionEnabled:YES];
[scrollView addSubview:image];
scrollView.scrollEnabled = YES;
scrollView.minimumZoomScale=1.0;
scrollView.maximumZoomScale=4.0;
[scrollView setContentSize:CGSizeMake(320, 180)];
scrollView.delegate=self;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return image;
}
please help me.
I have implemented image zooming in my app. Try scrollviewDelegate Method
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
// The scroll view has zoomed, so we need to re-center the contents
[self centerScrollViewContents];
}
- (void)centerScrollViewContents
{
CGSize boundsSize = zoomingScrollView.bounds.size;
CGRect contentsFrame = ZImageView.frame;
if (contentsFrame.size.width < boundsSize.width)
{
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
}
else
{
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height)
{
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
}
else
{
contentsFrame.origin.y = 0.0f;
}
ZImageView.frame = contentsFrame;
}
No need to set userInterAction enabled on imageView. If this does not help, I will share my implementation.
You should set value for zoomScale property of scrollview to start zooming as given below.
scrollView.zoomScale=1.0; // this will enable zooming.

How to pass the touches to view from scrollview

I have 3 tableviews placed upon scrollview at x = 0.0, x = 320.0 and x = 640.0.
When the user horizontally swipes the tableviews (as they are on top), I want to pass the swipe event to its superview and when the user vertically swipes tableviews the tableview must scroll vertically.
How can I achieve this?
To pass the touch from UIScrollView, use this code as a category:
#implementation UIScrollView (FixedApi)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
NSLog(#"touch view = %#", [[touch view].class description]);
if ([[[touch view].class description] isEqualToString:#"UITableViewCellContentView"]) {
//To pass the touch to UITableViewCell
} else if ([[[touch view].class description] isEqualToString:#"UITableView"] && isHorizntalSCroll == true && pageNumber == 2) {
//To pass the touch to UITableView
} else if ([[[touch view].class description] isEqualToString:#"UIView"]) {
//To pass the touch to UIView
} else {
[self.superview touchesBegan:touches withEvent:event]; // or 1 nextResponder, depends
[super touchesBegan:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if ( !self.dragging ) [self.nextResponder.nextResponder touchesEnded:touches withEvent:event];
[super touchesEnded:touches withEvent:event];
}
#end
To determine the vertical/Horizontal scrolling, you can use this code:
.h file <UIScrollViewDelegate>
BOOL pageControlIsChangingPage;
CGPoint startPos;
int scrollDirection;
int CX; //The width of the pages.
BOOL isHorizntalSCroll;
int pageNumber;
.m file
#pragma mark -
#pragma mark UIScrollViewDelegate stuff
- (void)scrollViewDidScroll:(UIScrollView *)_scrollView {
if (scrollDirection==0){//we need to determine direction
//use the difference between positions to determine the direction.
if (abs(startPos.x-scrollView.contentOffset.x)<abs(startPos.y-scrollView.contentOffset.y)){
NSLog(#"Vertical Scrolling");
scrollDirection=1;
isHorizntalSCroll = false;
[scrollView setPagingEnabled:NO];
} else {
NSLog(#"Horitonzal Scrolling");
scrollDirection=2;
isHorizntalSCroll = ture;
[scrollView setPagingEnabled:YES];
}
}
if (scrollDirection==1) {
[scrollView setContentOffset:CGPointMake(startPos.x,scrollView.contentOffset.y) animated:NO];
} else if (scrollDirection==2){
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x,startPos.y) animated:NO];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView {
if (pageControlIsChangingPage) {
return;
}
CGFloat pageWidth = _scrollView.frame.size.width;
int page = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
pageNumber = page;
NSLog(#"page number = %d",page);
if (page == 3 || page == 0) {
[scrollView setContentSize:CGSizeMake(CX, personalInfo.frame.size.height + 100)];
} else {
[scrollView setContentSize:CGSizeMake(CX, [scrollView bounds].size.height)];
}
pageControlIsChangingPage = NO;
}
#pragma mark -
#pragma mark PageControl stuff
- (IBAction)changePage:(id)sender {
/*
* Change the scroll view
*/
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
/*
* When the animated scrolling finishings, scrollViewDidEndDecelerating will turn this off
*/
pageControlIsChangingPage = YES;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollViews{
startPos = scrollView.contentOffset;
scrollDirection=0;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollViews willDecelerate:(BOOL)decelerate {
if (decelerate) {
scrollDirection=3;
}
}
That's it,
disable horizontal scroling for each tableview via IB or code and set the contentsize of the base scroll view to be 960,heightOfTableview and you should be just fine... this should get you going.

Scaling UIImageView inside UIScrollView with maintaining the rotation

I have a problem in scaling the uiimageview which is placed inside the uiscrollview. I have googled and checked all the questions related to my problem in StackOverflow as well. I tried all the answers that are posted in the StackOverflow also. Nothing worked for me.
First I am placing the uiimageview inside uiscrollview in nib file and I am taking the image from Camera roll and filling the image view. Then I am using uirotationgesturerecognizer to rotate the image.
Here is the code that I am trying to do.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#",[[UIDevice currentDevice] model]);
// Do any additional setup after loading the view, typically from a nib.
self.imagePicker = [[[UIImagePickerController alloc] init] autorelease];
self.picChosenImageView.layer.shouldRasterize = YES;
self.picChosenImageView.layer.rasterizationScale = [UIScreen mainScreen].scale;
self.picChosenImageView.layer.contents = (id)[UIImage imageNamed:#"test"].CGImage;
self.picChosenImageView.layer.shadowColor = [UIColor blackColor].CGColor;
self.picChosenImageView.layer.shadowOpacity = 0.8f;
self.picChosenImageView.layer.shadowRadius = 8;
self.picChosenImageView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.picChosenImageView.bounds].CGPath;
UIRotationGestureRecognizer *rotationRecognizer = [[[UIRotationGestureRecognizer alloc]initWithTarget:self
action:#selector(handleRotate:)] autorelease];
rotationRecognizer.delegate = self;
[self.picChosenImageView addGestureRecognizer:rotationRecognizer];
self.containerView.delegate = self;
self.containerView.contentSize = self.picChosenImageView.layer.frame.size;
self.containerView.maximumZoomScale = 4.0f;
self.containerView.minimumZoomScale = 1.0f;
angle = 0.0f;
useRotation = 0.0;
isRotationStarted=FALSE;
isZoomingStarted = FALSE;
}
-(void)lockZoom
{
maximumZoomScale = self.containerView.maximumZoomScale;
minimumZoomScale = self.containerView.minimumZoomScale;
self.containerView.maximumZoomScale = 1.0;
self.containerView.minimumZoomScale = 1.0;
self.containerView.clipsToBounds = false;
self.containerView.scrollEnabled = false;
}
-(void)unlockZoom
{
self.containerView.maximumZoomScale = maximumZoomScale;
self.containerView.minimumZoomScale = minimumZoomScale;
self.containerView.clipsToBounds = true;
self.containerView.scrollEnabled = true;
}
#pragma mark - ScrollView delegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.picChosenImageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
CGRect frame = self.picChosenImageView.frame;
frame.origin = CGPointZero;
self.picChosenImageView.frame = frame;
//self.picChosenImageView.transform = prevTransform;
}
-(void) scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
if(!isZoomingStarted)
{
self.picChosenImageView.transform = CGAffineTransformRotate(self.picChosenImageView.transform, angle);
NSLog(#"The zooming started");
isZoomingStarted = TRUE;
CGSize contentSize = self.containerView.bounds.size;
CGRect contentFrame = self.containerView.bounds;
NSLog(#"frame on start: %#", NSStringFromCGRect(contentFrame));
NSLog(#"size on start: %#", NSStringFromCGSize(contentSize));
//prevTransform = self.picChosenImageView.transform;
}
}
-(void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
if(isZoomingStarted)
{
self.picChosenImageView.transform = CGAffineTransformRotate(self.picChosenImageView.transform, angle);
isZoomingStarted = FALSE;
CGSize contentSize = self.containerView.contentSize;
CGRect contentFrame = self.containerView.bounds;
NSLog(#"frame on end: %#", NSStringFromCGRect(contentFrame));
NSLog(#"size on end: %#", NSStringFromCGSize(contentSize));
}
}
#pragma mark - GestureRecognizer methods
- (void) handleRotate:(UIRotationGestureRecognizer *)recognizer
{
if(isZoomingStarted == FALSE)
{
if([recognizer state] == UIGestureRecognizerStateBegan)
{
angle = 0.0f;
[self lockZoom];
}
useRotation+= recognizer.rotation;
while( useRotation < -M_PI )
{
useRotation += M_PI*2;
}
while( useRotation > M_PI )
{
useRotation -= M_PI*2;
}
NSLog(#"The rotated value is %f",RADIANS_TO_DEGREES(useRotation));
self.picChosenImageView.transform = CGAffineTransformRotate([self.picChosenImageView transform],
recognizer.rotation);
[recognizer setRotation:0];
if([recognizer state] == UIGestureRecognizerStateEnded)
{
angle = useRotation;
useRotation = 0.0f;
isRotationStarted = FALSE;
self.containerView.hidden = NO;
//prevTransform = self.picChosenImageView.transform;
[self unlockZoom];
}
}
}
My problem is, I am able to successfully do a zoom in and zoom out. I am able to rotate the uiimageview as I wanted to. After rotating the uiimageview to a certain angle, and when I am trying to zoom in, the imageview gets back to the original position (rotate itself back to zero degree) and then the zooming happens. I want to retain the rotation and also zoom. I tried saving the previous transform and assign in back scrollDidzoom and scrollDidBegin delegate methods. None worked. Please help me to spot my mistake which I am overlooking.
try using CGAffineTransformScale instead of just resizing the frame for zooming:
anImage.transform = CGAffineTransformScale(anImage.transform, 2.0, 2.0);
changing the transform for scaling might fix your rotation issue.
hope this helps.
I had the same problem. UIScrollView is taking control over UIImageView and it is using transform without rotation.
So I do not give image reference to scroll and I have added UIPinchGestureRecognizer for scaling.
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return nil
}
Dragging is still working :)
// viewDidLoad
var pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(pinchRecogniezed))
scrollView.addGestureRecognizer(pinchGestureRecognizer)
func pinchRecogniezed(sender: UIPinchGestureRecognizer) {
if sender.state == .Began || sender.state == .Changed {
let scale = sender.scale
imageView.transform = CGAffineTransformScale(imageView.transform, scale, scale)
sender.scale = 1
}
}

detect when uiscrollview frame touch the main screen bounds

how can i detect when a UIScrollViewframe intersect with the main screen (when scrolling) in both direction up and down? i was trying to do it like so :
- (void)detectScreenBoundsIntersect{
if (CGRectIntersectsRect([myScrollView frame], [[UIScreen mainScreen] bounds])) {
NSLog(#"COLLISION");
}
}
But this doesn't seem to work! Thanks.
Adopt the UIScrollViewDelegate protocol in the view controller and set the scroll view's delegate to the controller. Adopt the scrollViewDidScroll: method.
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
if ( [self hasReachedAVerticalEdge] ) {
NSLog(#"At World's End");
}
}
- (BOOL) hasReachedAVerticalEdge {
CGPoint offset = myScrollView.contentOffSet;
CGSize contentSize = myScrollView.contentSize;
CGFloat height = myScrollView.frame.size.height;
CGFloat width = myScrollView.frame.size.width;
if ( offset.y == 0 ||
(offset.y + height) == contentSize.height ) {
return YES;
}
return NO;
}
Is this what you are looking for?
Checking if an image view falls in the visible portion of the scroll view.
- (BOOL)isContentFrameVisible:(CGRect)aFrame {
CGRect visibleRect = CGRectZero;
visibleRect.origin = myScrollView.offset;
visibleRect.size = myScrollView.frame.size;
if ( CGRectIntersectsRect(visibleRect, aFrame) ) {
return YES;
}
}

reduce bouncing UITableView

is it possible to somehow reduce the bouncing height at the top or the end of an UITableView?
Thank you
You can check and set the contentOffset property in the scrollViewDidScroll method:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y <= -100)
{
CGPoint offset = scrollView.contentOffset;
offset.y = -100;
scrollView.contentOffset = offset;
}
}
Not without disabling it entirely, via the UIScrollView property bounces. It's pretty much an on-or-off thing.
I doubt so. The elasticity of scroll views is an implementation detail and it doesn't appear that the UIScrollView class exposes properties that let you adjust that.
As additional to René Fischer answer follow the full code to reduce bounce top and bottom.
Swift Version:
override func scrollViewDidScroll(scrollView: UIScrollView) {
var offset = scrollView.contentOffset;
if (offset.y < bounceLimit) {
offset.y = bounceLimit;
scrollView.contentOffset = offset;
}
let offsetY = scrollView.contentSize.height - scrollView.bounds.height - offset.y
if (offsetY < bounceLimit) {
offset.y = scrollView.contentOffset.y - (bounceLimit + abs(offsetY));
scrollView.contentOffset = offset;
}
}
Obj-C Version:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGPoint offset = scrollView.contentOffset;
if (offset.y <= -100)
{
offset.y = -100;
scrollView.contentOffset = offset;
}
CGFloat offsetY = scrollView.contentSize.height - scrollView.bounds.height - offset.y
if (offsetY < bounceLimit) {
offset.y = offset.y - (bounceLimit + abs(offsetY));
scrollView.contentOffset = offset;
}
}
Note: The height of the table (contentSize.height) should be at least the device screen height less the bounce limit.
You cannot changing bounceing property of scrollview either you can disable or enable