I have a UIViewController with a UIScrollView in it. When running in the simulator, I drag the UIScrollView and it starts moving correctly, but when I release the drag, there's a small delay (around half a second) then the view continues moving to finish the momentum.
This delay only happens when the touch release happens in the view. So if I drag and release outside the simulator, there is no delay.
Here's the code for creating the UIScrollView:
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = NO;
//scrollView.delaysContentTouches = NO;
//scrollView.userInteractionEnabled = YES;
scrollView.delegate = self;
[self.view addSubview:scrollView];
// Add some sub views here
// ...
// 2 pages
scrollView.contentSize = CGSizeMake(self.view.frame.size.width*2, self.view.frame.size.height);
I have not overridden any touch events in the app.
I have not implemented any of the UIScrollViewDelegate methods.
Enabling and disabling paging doesn't make a difference.
I have not run this on a physical device, just in the simulator.
What's the problem?
Thanks.
Answering my own question in case someone else was wondering.
This is a side effect of using the touchpad on the MacBook. When doing three-finger dragging, the OS adds a delay after releasing to allow you to take your fingers up and quickly put them back down to continue dragging. This doesn't happen when using a mouse.
No problem with code or the simulator.
Silly me :)
Related
I am struggling to hide a banner view when a purchase is made.
I have 2 separate versions, one is an Admob banner (bannerView_), the other is actually a view which I called _adView they share the same place but rotate around depending on what is viewing.
Anyhow, the Admob banner hides no problem, but the _adView does not, here is hiding code;
-(void)removeBanner:(NSNotification *) notify {
NSLog(#"Removing:");
if ([MKStoreManager isFeaturePurchased:#"com.fredsworld.ubercool.removeads"]) {
[bannerView_ setHidden:YES];
[_adView setHidden:YES];
NSLog(#"Removed:");
}
}
Basically that runs on a purchase, so it updates the screen instantly,
The _adView code to call it in the viewDidLoad is;
CGFloat y = self.view.frame.size.height - 50.0;
TapForTapAdView *adView = [[TapForTapAdView alloc] initWithFrame: CGRectMake(0, y, 320, 50) delegate: self];
[self.view addSubview: adView];
I have synthesized adView and created it as an object, but still no joy, it does not disappear when the purchase is made.
Although, it DOES work, as if you close the app, then re open, it has gone but obviously I want it to disappear immediately upon purchase.
Any ideas?
it was solved by removing the TapForTapAdView *adView on line 2 and simply changing to self.adView =
I've got a strange bug whereby two UIButtons inside a UIView, which is in turn inside a UIScrollView view are not clickable on iOS 5, but work perfectly fine on iOS 6 (screenshot shows scroller and map underneath)
The only other detail is the scroller view 'slides up' to reveal buttons when a station is selected. I've tried selecting the buttons on iOS 5, and they do get hit (visually), but the event isn't fired.
Edit: If I tap and hold on the button in the simulator, then move the cursor up the screen and release (e.g. to the part of the UIView that was always visible), the event fires.
The scroll view itself has the following settings, the latter two have only been added in order to try and make the buttons work on iOS 5 (tried various combinations):
self.scrollView.clipsToBounds = YES;
self.scrollView.scrollEnabled = YES;
self.scrollView.pagingEnabled = YES;
self.scrollView.delaysContentTouches = NO;
self.scrollView.canCancelContentTouches = NO;
The button events are all wired up correctly, with suitable targets etc:
[_updatePriceButton addTarget:self action:#selector(showPriceUpdateBoxWithPrice:) forControlEvents:UIControlEventTouchUpInside];
[_stationDetailsButton addTarget:self action:#selector(stationDetailsSelected:) forControlEvents:UIControlEventTouchUpInside];
And handlers (here's one as a sample):
- (void)stationDetailsSelected:(id)sender {
if ([self.delegate respondsToSelector:#selector(stationDetailsSelected:)]) {
[self.delegate stationDetailsSelected:_station];
}
}
Any help would be great!
Found the culprit - a misconfigured UITapGestureRecognizer on the UIView the UIButtons sit on:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(stationInfoViewTapped:)];
[infoController.view addGestureRecognizer:tap];
Simply adding the following after init of 'tap' solves the issue in iOS 5:
[tap setCancelsTouchesInView:NO];
I have a subclassed UIView which I can get to scroll but not to zoom. I'm using autolayout so wondered if anything had changed in IOS6. In particular when are the scrollViewWillBeginZooming and scrollViewDidEndZooming methods implemented. My code looks like
- (void)viewDidLoad
{
[super viewDidLoad];
self.ringSet2 = [[RingView alloc] initWithFrame:CGRectMake(0, 0, 800, 800)];
[self.ringSet2 setDefaults];
/// ... more setup for other views but only ringSet2 is scrolled.
self.scrollview1.delegate=self;
self.scrollview1.scrollEnabled=YES;
self.scrollview1.contentSize=self.ringSet2.bounds.size
self.scrollview1.minimumZoomScale=0.2;
self.scrollview1.maximumZoomScale=5.0;
self.ringSet2.userInteractionEnabled=YES;
// ... needed elsewhere so other views can pick up their dimensionts
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
/// ... code for additional views
[self.scrollview1 zoomToRect:CGRectMake(0, 0, 200, 200) animated:YES];
[self.scrollview1 addSubview:self.ringSet2];
}
with
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return self.ringSet2;
}
and scrollViewWillBeginZooming etc. implemented just to trace what is happening. Interesting,
viewForZoomingInScrollView appears to get called only once, as is scrollViewDidEndZooming with a scale value just under one but scrollViewWillBeginZooming is never called. The property ringSet2 is defined
#property (strong, nonatomic) IBOutlet RingView *ringSet2;
as the view does not appear if it's defined as weak.
Apologises for this. The answer is really stupid. I'm currently developing under IOS 6.0 on the simulator whilst my phone is still on IOS 5. The simulator allows you to simulate pinches but only centred on the centre of the screen. The scrollview however only receives this signal if it too is in the centre which was not the case in my initial build. Moving the scroll view's rectangle into the centre fixed the problem. You would not make this mistake testing on a real device. The code is thus OK. Lost 3 or 4 evenings pulling my hair over this one.
I am trying to implement an adWhirl view in the same view as one that has an MKMapView object. If I follow the standard steps that work fine with my tableViews, that is
awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
[self.view addSubview:awView];
then the funny behavior starts. In the simulator it receives the touch and sends you on. But when running on my test device (running 3.1.3) the touch passes through to the map.
I have been told that this is because awView is being cast as a subView of mapView and that it must be its own view. But how? I have tried creating a separate UIView and then placing awView in it, then locating it at a fixed location, but instead of the fixed location, it loads relative to mapView and still does not receive touches.
Any suggestions?
Addendum: I thought that I was adding both as subviews but have not had any success. What I had done is to create two views in IB. The top one (firstView) has two subviews (bannerForAd and mapView.) This is what I have now
self.awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
self.awView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[bannerForAd addSubview:awView];
mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
mapView = (MKMapView*)self.view;
mapView.delegate = self;
[firstView addSubview:mapView];
[firstView bringSubviewToFront:bannerForAd];
Now the map shows fine, but the ad is not even visible.
Stick both the AdWhirlView and the MKMapView as a subview of a UIView.
It looks like a problem which could have simple solution, but I haven't found anything what could lead the way to it. I'm using UIWebView inside of UIScrollView and tapping on statusBar (to scroll content to top) is not working.
I've made simple test application to see if it's really UIWebViews fault. And it really is.
// scrolls to top on status bar tap
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
[self.view addSubview:sv];
// doesn't scroll
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
UIWebView *wv = [[UIWebView alloc] init];
wv.frame = CGRectMake(0, 0, 320, 100);
[sv addSubview:wv];
[self.view addSubview:sv];
So, I think maybe there's something I could disable to make UIWebView not to mess with scrollToTop? Or some kind of workaround also would be nice.
Any ideas?
I ran into this last night until I finally found the answer buried in a comment to a comment. The idea of that original post is that when you add the UIWebView to your UIScrollingView, you use the following:
- (void) ensureScrollsToTop: (UIView*) ensureView {
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
}
This seemed fishy to me since the first sub-view of a UIWebView claims to be a UIScroller which is not a subclass of UIScrollView. However, since UIScroller supports the scrollsToTop property, the cast just gives us a way past the compiler warning:
Class List:
Class = UIScroller
Class = UIView
Class = UIResponder
Class = NSObject
Supported Methods:
...
Method _scrollToTop
Method setScrollsToTop:
Method scrollsToTop
...
Supported Properties:
Property scrollsToTop
EDIT:
Just another quick note about where this actually needs to occur: in the webViewDidFinishLoad callback. Calling it on UIWebView construction isn't good enough because at that time the UIWebView hasn't created it's child views yet, which are the ones causing the problem:
- (void)webViewDidFinishLoad:(UIWebView *) wv {
[self ensureScrollsToTop: wv];
}
EDIT #2:
now, in iOS 5, as noted in iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back use UIWebView's new #property scrollView, making ensureScrollsToTop implementation unnecessary for projects that aren't using deployment targets lower than iOS 5.0 .
In iPhone OS, if there is more than one UIScrollView (or its subclass, for example UITableView, UIWebView) in the current viewController, the system doesn't know which UIScrollView should be scrolled to the top.
Quick fix: for all the UIScrollViews that you don't want to support scrollsToTop, just set the scrollsToTop as NO, then every thing works perfect.
self.scrollView1.scrollsToTop = NO;
self.scrollView2.scrollsToTop = NO;
self.scrollView1.scrollsToTop = YES; // by default scrollsToTop is set as YES, this line is not necessary
Webviews by default will have YES for scrollsToTop-value. I've written a simple class for this specific issue. In my app we're having multiple webviews and scrollviews. This makes it all much easier.
https://gist.github.com/hfossli/6776203
It basically sets scrollsToTop to NO on all other scrollViews than the one you are specifying.
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr said:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];