I'm trying to create a specific layout in an iOS App, where the "background" is a MKMapView and the overlay is a UIScrollView. The idea is that there are two screens, one with a map, and another with some additional information on. The user can scroll down to see this general information, and this view covers up the map and has a blurred background to create some depth.
Here's an image showing the layout:
As you can see, the map is fixed in its position. It will always be behind the content, even if you scroll. I want the map to respond to gestures, but only when used directly on the map. When the user "scrolls" over the bottom bar, I want the content to scroll up, revealing the second page which then covers the map.
I'm lost at what to do to achieve this. I tried putting the map on the original UIView and then covering it up with a scrollview, but this causes the map not to respond to gestures. I only want the UIScrollView to respond to gestures when it's on either the bottom bar, or the second page (each is its own separate view). Otherwise I want the Map to respond to the gestures.
I hope I managed to explain it well, if not, please do not hesitate to ask questions. I appreciate all help!
It sounds like you are adding a full screen UIScrollView on top of a MKMapView and the scrollview is picking up all the touches.
What you are asking about is not necessarily standard so there are multiple ways to implement it and you have to decide what works best for your use case.
Here is what I would do:
Use constraints on the scrollview to ensure that it is only covering the bottom bar area.
Make sure you can toggle the constant of the constraint controlling the scroll view's height (hook up an IBOutlet if you're using storyboard).
Add both a swipe gesture recognizer and a tap gesture recognizer that will fire toggleScrollViewFullScreen if recognized. Ensure that these recognizers can only be recognized while the scrollView is the bottom bar.
Have an X-out button display in the top corner while the scrollview is in full screen. This button can call toggleScrollViewFullScreen to dismiss the view back down.
Example toggleScrollViewFullScreen method:
//Toggle size of scroll view
- (void) toggleScrollViewFullScreen {
CGFloat bottomBarHeight = 100;
if (self.scrollViewHeightConstraint.constant > bottomBarHeight){
self.scrollViewHeightConstraint.constant = bottomBarHeight
}else {
self.scrollViewHeightConstraint.constant = self.view.bounds.size.height;
}
//Animate constraint change:
[UIView animateWithDuration:1 animations:^{
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];
}];
}
Related
I have been trying to create a scrollable view using UIScrollView. I want this view to be a scratchpad where I can do rough work with touch gestures.
But, doing a drag gesture makes the UIScrollView move the page.
This is why I want to disable scrolling on gesture and enable scrolling only when I drag the scroll bars on the screen.
I have tried Googling, but haven't found any result so far.
It would be great if you could guide me to a solution or help me with some pointers.
Not sure you can or that it would be usable.
How about enabling scrolling only with 2 fingers? By setting the scroll view pan gesture minimumNumberOfTouches To 2.
Otherwise, think about acting as the delegate of the scroll view pan gesture, specifically for gestureRecognizer:shouldReceiveTouch: so that you can examine the touch position and only allow the gesture to start of significantly close to the edge of the view.
I world recommend using this library: https://github.com/BasheerSience/BRScrollBar
1- Use instance method to add the scrollBar
2- in your UIViewController add these lines of code
// First intit by using the instance method
_brScrollBarController = [BRScrollBarController initForScrollView:self.scrollView
inPosition:kIntBRScrollBarPositionRight
delegate:self];
// show the scrollBar always, do not hide
_brScrollBarController.scrollBar.hideScrollBar = NO;
// disable scrolling for your scrollView
self.scrollView.scrollEnabled = NO;
3- now your scrollView will not respond to gestures, and you will use BRScrollView to scroll by dragging the bar
let me know if you have any questions
I have an app which has a uiscrollview, which in turn has two uiimageviews.
The scrollview works fine in sliding between both imageviews, by making the content size twice the width. like so
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height)];
Now the client wants the user to be able to zoom into any image in those two images. He does not want another modal view with the selected picture zoomed in, but rather on the same uiscrollview he wants this to happen. Is this doable? or a good Idea?
The problem I am having is that when I implement the zooming logic ( implementing the delegate
UIScrollViewDelegate
the moment I set the value of
self.scrollView.zoomScale
I end up calling this method
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [self getCurrentVisibleImage];
}
And with that happening, I end up with the UIscrollview that after zooming back to the normal size of the image, the scrollview simply doesn't slide left or right?
Any help is appreciated.
Answer was simple, I was manipulating contentsize and not setting it properly. that fixed it.
I have many controls in the UIScrollView including few buttons. For an example I have a button at position (300,200) from where I am popping UIPopOverController to do required tasks but when I scroll scrollview is scrolled, popover still pops up from the location (300,200) which is wrong! Is there anyway to get button position in visible scroll view?
This is how I get the exact position of button while knowing it's initial position in UIScrollView. I just need to subtract current scrollview offset from button's Y coordinate! For me X coordinate doesn't change - as no horizontal scrolling supported.
CGPoint point = CGPointMake(self.button.frame.origin.x,
self.button.frame.origin.y - self.scrollView.contentOffset.y)
Maybe it pops ut at the wrong position because it is not added at the UIScrollView, but at its superview. Try to check in the views hierarchy the position of the button. Another thing you can do to retrieve the button position is to go inside the view hierarchy and extract the arrays of subviews, and check the position of the button here.
Take a look at this link http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW17
Use UIView convertRect:toView: or convertRect:fromView: method.
I have a situation similar to these two posts (1907297 AND 689684) and to describe my situation most concisely, I present this text/graphical layout (similar to what you'd see in IB, dots used to enforce indent levels)
UIView (MainView: 320x460)
. .UIScrollView (ScrollView: 320x460)
. .UIView (OverlayView: 320x40)
. . . .UIButton (ArbitraryButton1)
. . . .UILabel (ArbitraryLabel1)
. . . .UILabel (ArbitraryLabel2)
The goal here is for the OverlayView to serve as a unified, transparent container to position and display some arbitrary buttons/labels on top of the ScrollView. These buttons/labels should remain stationary while the content in the ScrollView beneath moves with user swipes. The buttons/labels may sometimes be hidden/unhidden/scaled in unison (with animation) which is what makes it handy to have them all grouped in the single OverlayView.
The trouble is that, while taps on the OverlayView seem to transmit right through to the underlying ScrollView just nicely, swiping motions have no effect. I can detect/intercept the swipes by overriding the
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
method in the OverlayView, however I haven't yet found a way to properly pass those along to the ScrollView in a way that makes it scroll. Evidently the touchesMoved method is not what UIScrollView uses to detect/interpret swipes?
All the other similar posts I've researched have either found a different solution that wouldn't work in my case or have just gone unsolved. I've also seen mention of employing touchesShouldBegin / touchesShouldCancel though I don't grasp how that would be implemented. Anyhow, still hopeful that there's some insight from the community that can allow me to come up with an elegant solution for this - any sample code would be fantastic.
Thanks in advance, Joel.
P.S. - I should also mention that I need to make this compatible with iOS 3.0 so I think trying to use UIGestureRecognizers is out.
Here's an easier solutions that worked well for me:
In the OverlayView (the view on top of UIScrollView), make the width and height both 0 (so that the view is no longer technically on top of the scrollview) and set clipsToBounds = NO (so that the contents of the OverlayView still show up on top of the scrollview). It worked like a charm for me.
self.OverlayView.clipsToBounds = NO;
CGRect frame = self.OverlayView.frame;
self.OverlayView.frame = CGRectMake(frame.origin.x, frame.origin.y, 0, 0);
Note that if OverlayView contains interactive controls (like the button above) then they will no longer work. You'll need to move it into it's own view above the UIScrollView.
How about, at runtime in viewDidLoad you take the buttons out of the container view and place them in the view as subviews directly (and get rid of the container view)? Then there's no container view to intercept swipes but you can still use a view to group things in IB.
Also potentially you could put the container view in as a subview of the scroll view instead, and in the scroll view delegate keep re-positioning the view whenever the user scrolls. That would seem to have a high potential for being jittery but may be worth a try.
Also if the containing view is a visual container and you need to see it, you could instead use a CALayer that was placed in the superview on top of the CALayer for rendering the scroll view, since CALayers have nothing to do with input and would not each touches.
You should subclass UIScrollView and override the touchesShouldCancelInContentView: method
-(BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if ([view isKindOfClass:[UIButton class]]) {//or whatever class you want to be able to scroll in
return YES;
}
if ([view isKindOfClass:[UIControl class]]) {
return NO;
}
return YES;
}
I am creating an application for the iPhone which involves having buttons which animate a image view, I created another view in which the buttons are held, however I would like to be able to horizontally or vertically, scroll this view of buttons. I have looked into adding scroll views and I have even followed a tutorial, But I just can't figure out how to add it to my app. Any Ideas anyone? In the tutorial I followed the guy adds the scroll view to the MainWindow.xib, now my app is created and designed in the viewcontroller.xib. So after following the tutorial when I hit build and go it loads that nib and all you see is a white background and a scroll view. (also in that tutorial he scrolled an image where as I would like to scroll a long view of buttons) I realize the newbie-ness of my question could be crazy, but I'm new to programming all together. Here's another additional question, if someone helped me get this scroll view working where would you design the contents of that scrolled view if it's length is longer than the iphone screen? Because It is my understanding that the space to design with in interface builder is the size of the iphone screen and designing interfaces longer than the iphone screen isn't do-able. (of course I know it is do-able I just don't know how to do it).
You can set the content view (scrolling area) dimensions programmatically:
[scrollView setContentSize:CGSizeMake(contentViewWidth, contentViewHeight)];
And then add you view components to the scroll view using the coordinate system of the content view. So say your scroll view was 100x100 pixels and you wanted the scroll view to be twice as wide:
[scrollView setContentSize:CGSizeMake(200.0f, 100.0f)];
You could then add a button to appear on each half of the scroll view:
// First half of content view
button1.frame.origin.x = 10.0f;
button1.frame.origin.y = 50.0f;
[scrollView addSubView:button1];
// First half of content view
button2.frame.origin.x = 110.0f; // NOTE that 110 is outside of
button2.frame.origin.y = 50.0f; // the scroll view frame
[scrollView addSubView:button2];
You could probably design each page of the scroll view as a separate sub view in the NIB and then shift the sub views origin to the correct page location either in Interface Builder or programmatically - but I have never tried this. If this works you'd then be able to layout your buttons using IB.
I would be interested to know if this works.
most views have a .hidden property.
set it to YES to hide -> myscrollview.hidden = YES;
set to NO to show -> myscrollview.hidden = NO;
you can put this hide/show inside an animation and fade out the scrollview.
look-up "simple quartz animation" - it only a few lines of code.