UIScrollView on scroll update method - iphone

is there a method / possibility to run a function when the scrollview is scrolling?
i found scroll start and scroll end solutions but nothing like a onIsScrolling ...
is there a built in solution? or whats the best workaround (nstimer)?
thanks
Alex

UIScrollViewDelegate provides the following:
– scrollViewDidScroll:
– scrollViewWillBeginDragging:
– scrollViewDidEndDragging:willDecelerate:
– scrollViewShouldScrollToTop:
– scrollViewDidScrollToTop:
– scrollViewWillBeginDecelerating:
– scrollViewDidEndDecelerating:
in particular:
– scrollViewDidScroll:

Thanks a lot for the scrollViewDidScroll tip.
heres the implemtation sample:
#interface YourClass : UIViewController <UIScrollViewDelegate>
{
UIScrollView *theView;
}
#end
in .m file:
- (void)loadView
{
theView = [[UIScrollView alloc] initWithFrame:
CGRectMake(0, 10, 300, 300)];
theView.delegate = self;
[self.view addSubview:theView];
theView.contentSize = CGSizeMake(500, 500);
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(#"SCROLL SCROLL SCROLL YOUR BOAT");
}

Related

How can i set content offset on multiple scrollviews with one method?

I am having a little problem. I want to make all my scrollview scroll to the top when I press a UITableViewCell. Following is the code in didSelectRowAtIndexPath:
[self.tableView setContentOffset:CGPointZero];
[verbTableView setContentOffset:CGPointZero];
[seinhabenScrollView setContentOffset:CGPointZero];
[mdhPresensScroll setContentOffset:CGPointZero];
[mdhPreteritumScroll setContentOffset:CGPointZero];
[mhdScroll setContentOffset:CGPointZero];
....
There are more of those scrollview, and I want to put the all in one single object or something... I have tried following code:
for (UIScrollView *scrolls in topLayer.subviews)
{
[scrolls setContentOffset:CGPointZero];
}
Thanks!
The basic idea is right. It just depends upon how you identify the scroll views. You could do something like the following, which explicitly tests whether the subview is a kind of UIScrollView:
for (UIScrollView *scrollView in self.view.subviews)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
Or you can explicitly reference the specific scrollviews in question (in which case the class membership test isn't strictly needed):
for (UIScrollView *scrollView in #[seinhabenScrollView, mdhPresensScroll, mdhPreteritumScroll])
{
scrollView.contentOffset = CGPointZero;
}
Or, if you create an IBOutletCollection in IB, you can use that, too:
for (UIScrollView *scrollView in self.scrollViews)
{
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
(Note, in that final example, I'm scrolling to the location in question with animation, providing the user some visual cue as to what just happened; that's completely up to you.)
In a comment above, you say that topView has subviews which, themselves, have subviews that are scrollviews, you'd have to do something like the following to handle this subview-of-subview situation:
for (UIView *subview in topLayer.subviews)
{
for (UIScrollView *scrollView in subview)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
}
Avoiding the dynamic type check, just place the views that can scroll into an array. Then, a little fancier, add an extension to scroll view so they can scroll to zero using no params, that let's us do the scrolling with an NSArray one-liner (makeObjectsPerform...)...
#interface UIScrollView (ScrollToZero)
- (void)scrollToZero; // a no-param method for scrolling to zero offset
#end
#implementation UIScrollView (ScrollToZero)
- (void)scrollToZero {
[self setContentOffset:CGPointZero animated:YES];
}
#end
NSArray *allMyScrolls = #[verbTableView, seinhabenScrollView, // and so on. put ONLY scrollViews in here
// you can make this array a property, initialized when the views are created
[allMyScrolls makeObjectsPerformSelector:#selector(scrollToZero)];

Overlay View with Subview, don't know calling VC

I need a view (infoView) to be displayed as an overlay on top of another view. As this infoView should be callable from every view of the app(e.g. introView), I'd like the code to be in the infoViews VC and just call its methods when an action at the currentView (introView) happens. I can't use push and pop, as I need to change the background color (infoView) and especially the alpha of the calling view (introView), so right now I do it with insertSubview.
My Code by now:
introVC .h
- (IBAction) openInf:(id)sender;
IBOutlet InfoVC *infoScreenVC;
introVC .m
- (IBAction) openInf:(id)sender {
[infoScreenVC openInfoMethod];}
infoVC .h
- (IBAction) closeInfoPressed;
- (void) openInfoMethod;
- (void) closeInfoMethod;
infoVC .m
- (IBAction) closeInfoPressed {
[self closeInfoPressed];}
- (void) closeInfoMethod {
[self.view removeFromSuperview];
[self.xx.view setAlpha:1.0f];}
- (void) openInfoMethod {
self.view.backgroundColor = [UIColor clearColor];
[self.xx.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.xx.view];}
When I push the button to show the infoView, my NSLogs tell me the method was called, but I can see the Subview wasn't added. I have absolutely no clue what to insert where right now it says xx in my code, as a VC reference from intro doesn't show me the screen.
If I put that code in introVC an modify it, it does show the infoView, calls the correct method to close, but again can't close (when I'm in introVC). I can't figure out how to tell my app who was the calling VC to get back there.
At some point, when all the code was in introVC I managed to even remove the Subview, but couldn't set the Alpha of introVC back to one.
I do struggle with that since two days.. -.- Or is there maybe an easier solution even?
Thank you very much!
//Edit after sergios answer:
intro.m
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];}
info.h
- (void) openInfoMethod:(introViewController *introVC);
info.m
- (void) openInfoMethod:(introViewController *introVC) { //error occurs here
self.view.backgroundColor = [UIColor clearColor];
[self.introVC.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.introVC.view];}
and the occurring error says
Expected ')' before 'introVC'
I'm not sure how to pass the VC reference properly.
Thank you for your help!!
//EDIT Working Code:
As it works now, I'd like to sum things up:
- I give the calling VC (introVC) to openInfoMethod on the Action openInf like [infoVC openInfoMethod:introVC].
In openInfoMethod I "save" the calling VC in a local variable of type introVC (?) and add the overlay etc.
When the Action of the infoViewController named closeInfoPressed occurs, it calls infoViewController's method closeInfoMethod like self closeInfoMethod:introVC.
In that method I remove self.view from Superview and set introVC.view's Alpha to 1 like introVC.view setAlpha:1.0f
So the codesnippets are
intro.h
IBOutlet InfoscreenViewController *infoScreenVC;
#property (nonatomic, retain) IBOutlet InfoscreenViewController *infoScreenVC;
- (IBAction) openInf:(id)sender;
intro.m
#synthesize infoScreenVC;
- (IBAction) openInf:(id)sender {
UIViewController *introVC = self;
[infoScreenVC openInfoMethod:introVC];
}
info.h:
- (void) openInfoMethod:(UIViewController *)rootVC;
- (void) closeInfoMethod:(UIViewController *)callingVC;
info.m
- (void) closeInfoMethod:(UIViewController *)callingVC;{
[self.view removeFromSuperview];
[callingVC.view setAlpha:1.0f];
}
- (IBAction) closeInfoPressed{
[self closeInfoMethod:introVC];
[self.view removeFromSuperview];
}
If your problem is "figure out how to tell my app who was the calling VC to get back there", why don't you add a parameter to openInfo selector, like here:
info.h
- (void) openInfoMethod:(introViewController *)introVC;
info.m
- (void) openInfoMethod:(introViewController *)introVC {
<your implementation here>
}
would this work for you?
EDIT: your code from intro.m has got a small problem,
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];
}
indeed, you are not initializing your introVC variable, so that when you pass it into -openInfoMethod: it will have some weird value and cause a crash.
As far as I can grasp from your code, intro.m should be the implementation file for your introViewController, therefore you can simply call:
[infoScreenVC openInfoMethod:self];
but please, before doing this, confirm that self is actually your introViewController.
This should be ilke this
(void) openInfoMethod:(introViewController *)introvc you are passing parameters in a wrong way.
If I understand your question correctly, your infoView should be a subclass of UIView and instantiated from any of your view controllers using:
InfoView *infoView = [[InfoView alloc] initWithFrame:CGRectMake(originX,originY,width,height)];
Then you simply add it as a subview of your view controllers view:
[self.view addSubView:infoView];
[infoView release]; // It's safe to release it here as your view controller's view is retaining it
And when you are done with it, simply call
[infoView removeFromSuperview];
As an aside, you could create some simple methods inside infoView that include introducing animation when the view is presented or removed. Here's an example for fade in and out which assume you set the alpha to zero initially when you create the view:
- (void)fadeIn {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 1.0f}];
}
And fade out
- (void)fadeOut {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 0f}
completion:^(BOOL finished){self removeFromSuperView}];
}

Open a view on image Click in cover flow

I am using cover flow library in my project.My cover flow consist of many images.What I want to do is when I click on that image another View Controller should gets open.
Please tell me how to open another view on that image click.
Any help will be highly appreciated.
I had the same problem yesterday. I had to change something in the framework.
Add these two methods in the interface
#interface AFOpenFlowView : UIView
- (AFItemView *)selectedCoverView;
- (UIScrollView *)scrollView;
Add the implementations of these two methods inside of the .m file
#implementation AFOpenFlowView
- (AFItemView *)selectedCoverView {
return selectedCoverView;
}
- (UIScrollView *)scrollView {
return scrollView;
}
Set a UITapGestureRecognizer in the view controller where you're using the AFOpenFlowView
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(screenTapped:)];
[[self view] addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
}
At the end implement the method to handle the tap on the screen
- (void)screenTapped:(UITapGestureRecognizer *)tap {
CGPoint point = [tap locationInView:[af scrollView]];
if (CGRectContainsPoint([[af selectedCoverView] frame], point)) {
// Write here the code to open your view
// Use [af selectedCoverView].number to get the index of the selected cover
NSLog(#"selected cover view: %d", [af selectedCoverView].number);
}
}
Hope it's going to save you some time! ;)
Please try other FlowCover this is very easy to use...
Thanks

How to detect zoom scale of UIWebView

I want to increase height of UIWebView while user zoom in (like default mail app in iPhone).
So, I have tried the code below to find scrollview in webview and add UIScrollViewDelegate to use scrollViewDidZoom for detecting zoom scale to increase height of webview on this method.
// MessageAppDelegate.h
#interface MessageAppDelegate : NSObject <UIApplicationDelegate,UIWebViewDelegate,UIScrollViewDelegate> {
UIWebView *webview;
UIScrollView *scrollview;
}
//MessageAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self.window makeKeyAndVisible];
webview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 150, 320, 100)];
webview.delegate = self;
webview.scalesPageToFit = YES;
webview.userInteractionEnabled = YES;
[webview loadHTMLString:#"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=6.0 user-scalable=yes\">test test" baseURL:nil];
[self.window addSubview:webview];
// Find scrollview in webview
for (UIView *view in webview.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
// Get UIScrollView object
scrollview = (UIScrollView *) view;
scrollview.delegate = self;
}
}
return YES;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
NSLog(#"scale %f",scale);
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
NSLog(#"scrollViewDidZoom %f",scrollview.zoomScale);
}
The problem is I cannot zoom in/out on the webview
but NSLog on scrollViewDisEndZooming method showed
scale 1.0
when I ended zooming
and scrollViewDidZoom method didn't show anything.
I want to detect zoom scale of webview for calculating its height on scrollViewDidZoom.
What I've done wrong?
Please help.
Thanks in advance.
I have done well for your code up,do following modificaitons:
you just get the scrollview class point ,then can get the scrollview.contentSize.width,which can change when you zoom in out,but scrollview.zoomScale always remains 1.so have to use contensize.width to calculate scale.
#interface dictViewController : UIViewController<UIWebViewDelegate,UITextFieldDelegate,UIGestureRecognizerDelegate,UIScrollViewDelegate>{
UIScrollView *scrollview;
......................
//scrollview.delegate = self;
for (UIView *view in webViewM.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
// Get UIScrollView object
scrollview = (UIScrollView *) view;
//scrollview.delegate = self;
}
}
/*
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
//NSLog(#"scale zooming %f",scale);
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
//NSLog(#"scrollViewDidZoom %f",scrollview.zoomScale);
}*/
- (void)swipeRightAction:(id)ignored
{
NSLog(#"wid=%f", scrollview.contentSize.width);
NSLog(#"zoomscale=%f", scrollview.zoomScale);
}
I don't think there's a proper way to do it from the exposed APIs, but there is a hacky way.
A UIWebView contains a UIScrollView which can be given a delegate. Then when zooming changes, you (the delegate) get a callback called scrollViewDidZoom:.
In order to find the scroll view, you can get the subviews collection from the web view and iterate to see which one isKindOfClass:[UIScrollView class].
Now, UIWebView also conforms to UIScrollViewDelegate. So that may mean you are changing the web view's implementation, and that could be a Bad Idea. Test well.

Manual positioning of titleLabel in a custom UIButton (using layoutSubviews)

i've create a UIButton subclass for my app and i need to manually reposition the titleLabel to be about 1/4 of the button's height. this post; http://forums.macrumors.com/showthread.php?t=763140 appears to directly address the same issue, and the solution is simple and perfectly understandable. however, i have failed to implement this because my override of layoutSubviews is never called. my button is static, so layoutSubviews only need be called the first time, but it never is. my code:
#interface MyButton : UIButton {}
#implementation MyButton
- (id)initWithFrame:(CGRect)frame
{
self = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[[self layer] setCornerRadius:14.0f];
[[self layer] setBorderWidth:3.0f];
[[self layer] setMasksToBounds:YES];
[self setBackgroundColor:[UIColor redColor]];
[self setFrame:frame];
return self;
}
- (void)layoutSubviews
{
NSLog(#"layout subs\n");
[super layoutSubviews];
}
#end
moving the label would be no problem, but layoutSubviews is never called. i've also tried adding layoutIfNeeded, but it made no difference. what's even weirder, is i've tried to call [self layoutSubviews] directly from the constructor but layoutSubviews is still not called!. i'm starting to think this might even be a bug in SDK 3.1.3
can anyone help?!
In layoutSubviews, you can do layout changes to your subviews. Make sure that inside the method:
√ Call [super layoutSubviews]
x Do not change value or rect of self.frame here. If you do so, it would recursively call layoutSubviews.
√ Make sure you only change frame of its subviews.
From UIView Class Reference
to answer my own question, it seems i was subclassing incorrectly. taking the following approach results in layoutSubviews being called correctly:
+ (id)buttonWithFrame:(CGRect)frame {
return [[[self alloc] initWithFrame:frame] autorelease];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame])
{
...
[self setFrame:frame];
}
return self;
}
hope that helps others