I have a UITableView instance variable. I want to be able to register my view controller to be the UIScrollViewDelegate for my UITableViewController. I have already tried
tableView.delegate = self;
But when scrolling, my methods
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
don't get called. Any suggestions?
Now UITableViewDelegate conforms to UIScrollViewDelegate !
(I write this answer because many people are going to find this page googling..)
UITableViewDelegate will implement UIScrollViewDelegate protocol also.
This is officially unsupported. UITableView and UIWebView do not expose their internally managed scrollviews.
You can descend into the subview hierarchy and make undocumented calls, but that's not recommended, as it's officially prohibited and can break under future OS versions if the underlying (undocumented) API changes.
Related
Is there any notification sent when UIScrollView changes its scroll state? I would like to listen to that notification rather than using delegate methods.
If you don't want to use delegate methods you can observe contentOffset value changes using KVO (key-value-observing)
You can subclass UIScrollView, overload touchesMoved:withEvent:, and send this notification every time your scroll view will scroll.
As the scrolls need to be lightweight events I would not recommend using notifications for every scroll as it will impact your performance much greater than using a delegate method.
These are the delegates that handle scrolling for UIScrollView.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
Is there any specific reason you dont prefer delegates & want notifications? So you can use scrollViewDidScroll for any changes in scroll state.
So I just have a standard UIViewController with a UIWebView in it that displays a pdf. For the app functionality, I have need to be able to respond to the UIWebView's nested UIScrollView events like scrollViewWillBeginDragging, scrollViewDidScroll, etc.
The only way I can get access to the scrollView is to (it seems like a hack) go in and get it by the subviews array:
for (id subview in webView.subviews){
if ([[subview class] isSubclassOfClass: [UIScrollView class]]) {
UIScrollView * s = (UIScrollView*)subview;
s.delegate = self;
s.tag = 1;
scrollView = s;
}
}
But that seems to introduce more problems than it's worth, because I lose native UIScrollView stuff like zooming.
So to sum up what I'm needing:
What is the best way to set my UIViewController class as the delegate of the UIScrollView inside of the UIWebView? Is there something I need to do with subclassing my own UIWebView so that it handles events from it's built in UIWebView a certain way and then pass it along somehow to the UIViewController? How does that passing thing work anyway?
Please advise!
Thank you!
Have you checked there is only one UIScrollView subclass in the subviews? Bung in a log in your loop to see. If there is more than one, then you'll only pick up the last one using your code.
If there is just one UIScrollView subclass, you could try saving a reference to its delegate and then in your own delegate methods passing messages on after you have done your business.
So, in your loop, something like
originalDelegate = s.delegate
And then for the delegate methods, something like:
- (void) scrollViewDidScroll: (UIScrollView*) scrollView;
{
// do your stuff
[originalDelegate scrollViewDidScroll: scrollView];
}
You might need to check whether originalDelegate responds to the selector before calling it, i.e. if ([originalDelegate respondsToSelector: #selector(scrollViewDidScroll:)) etc. If it were me, I'd start by implementing all twelve delegate methods defined in the UIScrollView delegate protocol.
Not tested this, so will be interested to know if it can be made to work. Do note, the docs explicitly say that UIWebView "should not be subclassed"
If I add a view as a subview like so
[self.view addSubview:mySubview];
Will there be called any method on mySubview, that I could override to add some custom behavior?
Adding a view to a (new) superview triggers
- (void)willMoveToSuperview:(UIView *)newSuperview
and
- (void)didMoveToSuperview.
See the UIView Reference for more.
You can override these two:
- (void)willMoveToSuperview:(UIView *)newSuperview
- (void)didMoveToSuperview
Take a look in the documentation for UIView for similar methods.
Yes, There is a method which get called if one change the superview . you need to override the below method in your subview class.
- (void)willMoveToSuperview:(UIView *)newSuperview
- (void)didMoveToSuperview
From UIView Doucumentation
willMoveToSuperview:,
didMoveToSuperview—Implement these
methods as needed to track the
movement of the current view in your
view hierarchy.
exep for special purpose is far better to customize you view in init phase, you have all you need and (more important) is a synchronous call.
i need to add NSViewBoundsDidChangeNotification to my iphone application to check if user has scrolled the tableview,however to add this i think i need to import the nsview class.from where should i add this class to my project.and i need to confirm is this the best way to check if my tableview is scrolled by user?
NSView does not exist on the iPhone, as it uses Cocoa-Touch and not Cocoa.
If you want to get notifications about a UITableView's scroll events, just implement the UIScrollView delegate. It's documented here.
The delegate method you'll want to use is this one:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
}
There are other handy methods in there though, like:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
}
NSView has nothing to do with IOS development.
UITableView is a subclass of UIScrollView, and UITableViewDelegate conforms to UIScrollViewDelegate. This means that the delegate you set on your UITableView will get all the calls defined for UIScrollViewDelegate, including scrollViewDidScroll:.
I made a custom UITableView subclass and implemented this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// scrolled...
}
Now, what I think is that UITableView may also love to get this message for some obvious reasons. However, when I don't forward that to super, for some reason, everything still works fine. Must I forward that guy to super? I mean...it's a delegate method implementation, but as far as I'm aware of, this would still override anything implemented in UITableView, or not?
Edit: I see...the delegate could be anyone. Never mind about this. BUT: What I have such a thing in a superclass, and make a subclass. How would I even know that the superclass does implement that method and I must forward it to super?
Short answer: no.
Those methods are defined in the UIScrollViewDelegate Protocol.
They are meant to be implemented in a delegate, which maybe only has NSObject as parent.
It does not override anything, as it's a delegate method.
The UIScrollView just does it's stuff, and calls the delegate method if a delegate is set.
This is a delegate method which means it gets called by your instance of UITableView for your convenience.
The scrolling happens and the UITableView internal code will call.
if ([delegate respondsTo:#selector(scrollViewDidScroll:)]) {
[delegate performSelector:#selector(scrollViewDidScroll:) withObject:[self scrollView]];
}
And so you use this method to implement additional functionality, for example activating a control when the tableView has scrolled a certain amount.
Hope this helps!