Multiple UIScrollviews at different speeds - iphone

I have 4 UIScrollViews that overlay each other, and they all scroll when you drag a finger across. I however want to make one of them scroll at a different speed than the others.
I have tried using
- (void)scrollViewDidEndDecelerating: (UIScrollView *)scrollView
- (void)scrollViewWillBeginDecelerating: (UIScrollView *)scrollView
- (void)scrollViewDidScroll: (UIScrollView *)scrollView
- (void)scrollViewDidEndDragging: (UIScrollView *)scrollView
- (void)scrollViewDidEndScrollingAnimation: (UIScrollView *)scrollView
to capture when a scroll occurs but none of them are called during or after the scroll.
I have also tried setting the decelerationRate to be different for one of the views but they still all scroll at the same time?
Any ideas?

I guess,you're not implementing UIScrollViewDelegate method.
See the delegate property of UIScrollView.
#property(nonatomic, assign) id<UIScrollViewDelegate> delegate
and set it with the object of the class where you have implemented
UIScrollViewDelegate
methods,
myfirstScrollView.delegate = self;
mysecondScrollView.delegate = self;
.......
....

Related

iOS iPad App: Delegates not called for ViewController with two UIScrollViews and a UIPageControl (delegate functions for paging NOT CALLED)

For my iPad App, I have a main ViewController which contains two UIScrollviews and a UIPageControl.
The Problem is that the delegates for the paging are not getting called.
Here is the layout:
Selecting a button in the lower thumbScrollView needs to update the image in the mainScrollView (this works) Swiping the thumbScrollView or picking a dot on the pageControl needs to "page" the thumbScrollView to show the next previous set of buttons. The swiping does not work because the delegate functions are just not getting called.
I declare the scrollviews and pagecontrol as follows in my VC
#property (strong, nonatomic) IBOutlet UIScrollView *mainScrollView;
#property (strong, nonatomic) IBOutlet UIScrollView *thumbScrollView;
#property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
The ViewController implements UIScrollViewDelegate
#interface MyViewController : UIViewController<UIScrollViewDelegate>
And I implement the following UIScrollViewDelegate delegate functions in my VC's .m file.
- (void)scrollViewDidScroll:(UIScrollView *)sender;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
The view appears but when I swipe across the buttons I do not see the delegate functions above getting called.
I have not found a solution to this in StackOverflow although I have factored in advise from other related posts for other aspects of this (ex. the logic to distinguish which scrollview has initiated the action etc)
ADDING DETAILED CODE HERE (as requested by #HeWas)
This is the header file for the Main View Controller that controls the two scrollviews and pagecontrol (RELEVANT EXCERPTS - TELL ME IF YOU NEED MORE)
// ImageBrowseViewController.h
// (NOTE - In Interface Builder I have added a tag attribute of 0 to mainScrollView
// and 1 to thumbScrollView, to enable me to distinguish which scrollView the delegate
// needs to respond to)
#define TAG_MAIN_SCROLLVIEW 0
#define TAG_THUMB_SCROLLVIEW 1
#interface ImageBrowseViewController : UIViewController<UIScrollViewDelegate>
{
UIButton* currentlySelectedButton;
UIScrollView *mainScrollView;
UIScrollView *thumbScrollView;
UIPageControl* pageControl;
BOOL pageControlBeingUsed;
}
#property (strong, nonatomic) IBOutlet UIScrollView *mainScrollView;
// … connected as outlet in IB to mainScrollView
#property (strong, nonatomic) IBOutlet UIScrollView * thumbScrollView;
// … connected as outlet in IB to thumbScrollView
#property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
// … connected as outlet in IB to pageControl
…
-(IBAction)changePage; //Touch up Inside IBAction connected to pageControl
…
#end
This is the implementation file for the Main View Controller that controls the two scrollviews and pagecontrol (RELEVANT EXCERPTS - TELL ME IF YOU NEED MORE)
//
// ImageBrowseViewController.m
//
…
#synthesize mainScrollView;
#synthesize thumbScrollView;
#synthesize pageControl;
// UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if ( [sender tag] == TAG_THUMB_SCROLLVIEW ) {
// This is the thumbScrollview
// Update the page when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.thumbScrollView.frame.size.width;
int page =
floor((self.thumbScrollView.contentOffset.x - pageWidth / 2) / pageWidth)
+ 1;
self.pageControl.currentPage = page;
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (IBAction)changePage {
// Update the scroll view to the appropriate page
CGRect frame;
//frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.x = self.thumbScrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.y = 0;
frame.size = self.thumbScrollView.frame.size;
[self.thumbScrollView scrollRectToVisible:frame animated:YES];
// Keep track of when scrolls happen in response to the page control
// value changing. If we don't do this, a noticeable "flashing" occurs
// as the the scroll delegate will temporarily switch back the page
// number.
pageControlBeingUsed = YES;
}
You code all looks 100% (aside from this typo: #synthesize floorplanThumbScrollView;, but that isn't your problem).
I am sure that the answer is that you have not correctly wired your scrollview DELEGATES in IB.
This is the clue:
"Yes I have set all three in Interface Builder. So mainScrollView, thumbScrollView, and pageControl are wired in IB to the above declarations in the VC's .h file."
You need 2 connections between your ViewController and your scrollViews.
(1) ctrl-drag FROM viewController TO scrollView, connect to IBOutlet property.
This is what you have done.
(2) ctrl-drag FROM scrollView TO viewController, connect to delegate.
I do not think you have done this.
Explanation of step 2
UIScrollView has a built-in property called 'delegate'. The scrollView uses this property to send messages to it's delegate. You set this delegate in interface builder (step 2) or you can do it in code. For example in your viewController you could do this:
[myScrollView setDelegate:self];
which would set the viewController as the delegate for myScrollView. If you do it by linking in Interface Builder you don't need this code (and IB doesn't create any).
Either way what this actually does is set scrollView's delegate iVar to a pointer to the viewController. The great thing about using delegates like this is that the delegator (UIScrollView) doesn't have to know anything about the delegatee (in this case your UIViewController). This allows us to reuse UIScrollView so long as we observe it's delegate protocol.
Whenever the scrollView needs to notify it's delegate, internally it sends a message like this..
[self.delegate scrollViewDidScroll:self];
(you don't see that, it's in the scrollView's implementation).
The object that you have set as the delegate to scrollView needs to implement all of the required methods that the scrollView's delegate protocol declares, and can choose to implement any of the optional delegate methods. Here is the protocol
To work out which methods are required, read the UIScrollView class reference, which tells you this:
The UIScrollView class can have a delegate that must adopt the UIScrollViewDelegate protocol. For zooming and panning to work, the delegate must implement both viewForZoomingInScrollView: and scrollViewDidEndZooming:withView:atScale:; in addition, the maximum (maximumZoomScale) and minimum (minimumZoomScale) zoom scale must be different.
Everything else in the protocol is optional.
This delegate pattern is one you can easily implement yourself for your own object reuse, and is one of the most common ways of passing messages between decoupled objects in objective-C.

Why does a UIWebView instance not call scrollViewDidScroll?

iOS documention says, that the UIWebView class conforms to UIScrollViewDelegate. But an UIWebView instance does not call the scrollViewDidScroll method of its controller. The delegate is set just right by
[webView setDelegate:self];
and webViewDidFinishLoad is called successfully. The controller implements both delegates, UIWebViewDelegate and UIScrollViewDelegate, like this:
#interface WebviewController : UIViewController<UIWebViewDelegate, UIScrollViewDelegate>{
UIWebView *webView;
}
Browsing SO leads to that category solution:
#implementation UIWebView(CustomScroll)
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[self.delegate scrollViewDidScroll: scrollView];
}
#end
That category approach does basically the same: Calling the delegate's scrollViewDidScroll method. So why does the the first approach not work?
My guess is you set up delegate only for UIWebView.
Try setting delegate of scrollView.
webView.scrollView.delegate = self
it should be ok.
This is not correct. If you will use:
#implementation UIWebView(CustomScroll)
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[self.delegate scrollViewDidScroll: scrollView];
}
#end
You will lose focus when try to enter data on page on iOS7 and more
You need to implement custom class for UIWevView and overwrite scrollViewDidScroll:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[super scrollViewDidScroll:scrollView];
[((id<UIScrollViewDelegate>)self.delegate) scrollViewDidScroll:scrollView];}

why UIScrollView doesnt call it's Delegate?

the problem is I make a new UIScrollView at Xib and then link the delegate to owner..
some how the delegate doesnt called.. any clue? or simple example for UIScrollView
sorry I am a new ios developer and thank in advance..
the code :
at header
#interface stageViewController : UIViewController<UIScrollViewDelegate>
at .m
#pragma mark drag delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
NSLog(#"scrollViewDidScroll");
} // any offset changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
NSLog(#"scrollViewDidZoom");
}
// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
NSLog(#"scrollViewWillBeginDragging");
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
NSLog(#"scrollViewWillEndDragging");
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
NSLog(#"scrollViewWillBeginDecelerating");
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
NSLog(#"scrollViewDidEndDecelerating");
}
Write scrollView.delegate = self; If you have made it pragmatically.
And if you have your ScrollView in XIB then ctrl+drag from your scrollView to your File's Owner and then set its delegate.

In UIScrollview restrict a particular delegate from the uiscrollview delegate list

From the list of available UIScrollview delegate list . I want to restrict a selective uiscrollview delegate function namely:
(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
I want to restrict it from calling by the compiler . can i accomplish this . Any suggestions & help are appreciated!!
As mentioned previously you can assign a tag to each of your UIScrollViews (or just the one you need), and then check for that specific tag, or you can compare the UIScrollView in your delegate methods to the one you are interested in.
With tags.
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if(scrollView.tag == 100){
//do something here
return imgView;
}
return nil;
}
Comparing scrollViews.
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if([myScrollView isEqual:scrollView]){
//do something here
return imgView;
}
return nil;
}

iOS - Scrolling two UITextViews simultaneously

I've done some looking around but I haven't been able to find anything that clearly explains how I could simultaneously scroll two un-editable UITextViews. I think I may need to use either scrollRangeToVisible, or setContentOffset, though I could not get either of them to work.
Does anyone have any examples/samples, or documentation regarding this that they could point me towards?
EDIT: To clarify, I would like to be able to scroll one UITextView, and have the changes as a result of the scrolling reflected on a second UITextView as well.
Thanks!
Use the UIScrollViewDelegate methods to get information about scroll actions of the first scroll view and then scroll the second programmatically like that:
- (void) scrollViewDidScroll:(UIScrollView *)view1 {
scrollView2.contentOffset = view1.contentOffset;
}
React in
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
and set the other's scrollView setContentVisible according to scrollView.contentOffset.
Just be aware that some methods of UIScrollView will invoke scrollViewDidScroll even if called programmatically. This applies to scrollRangeToVisible and will end up in a loop unless you take action to prevent this loop. I don't think that setContentOffset or setting scrollView2.contentOffset = CGPointMake(..,..) does call scrollViewDidScroll. However, I would not sign this in blood. Be prepared to see a loop and take actions to avoid it. (such as boolean instance variable set before calling setContentOffset and re-set in scrollViewDidScroll followed by return;)
Just continuing with previous answers, to give some more information, I generated this code:
In the interface (.h):
#import <UIKit/UIKit.h>
#interface DoubleTextViewController : UIViewController <UITextViewDelegate>
#property (strong, nonatomic) IBOutlet UITextView *textView1;
#property (strong, nonatomic) IBOutlet UITextView *textView1;
#end
In your implementation (.m):
Use this viewDidLoad function after defining the corresponding properties and global variables.
#import "DoubleTextViewController.h"
#define TEXT_VIEW_1_TAG 1001
#define TEXT_VIEW_2_TAG 1002
#interface DoubleTextViewController () {
BOOL isScrolling;
}
#end
#implementation DoubleTextViewController
#synthesize textView1, textView2;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view..
isScrolling = NO;
[self.textView1 setTag:TEXT_VIEW_1_TAG];
[self.textView2 setTag:TEXT_VIEW_2_TAG];
[self.textView1 setDelegate:self];
[self.textView2 setDelegate:self];
}
And add this function for simultaneous scroll.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (isScrolling) {
return;
}
isScrolling = YES;
if (scrollView.tag == TEXT_VIEW_1_TAG) {
[self.textView2 setContentOffset:scrollView.contentOffset animated:NO];
} else if (scrollView.tag == TEXT_VIEW_2_TAG) {
[self.textView1 setContentOffset:scrollView.contentOffset animated:NO];
}
isScrolling = NO;
}
As proposed by Hermann Klecker, the isScrolling variable stops scrolling loops and makes the user experience nicer. Using the code proposed by Fabian Kreiser makes the scroll stops as soon as the user leaves the finger, making it strange.