How do I change text depending on where I am in my scrollview? - ios

I have a makeshift custom "actionbar" at the top of my view, and a scrollView beneath it.
I was wondering if there is anyway to change the text displayed in the bar at the top depending on what is currently visible at my current position in my scrollView.
ANSWER
Make sure you have made your ViewController a ScrollView delegate, it should look like this:
#interface ViewController : UIViewController <UIScrollViewDelegate>
Once you have declared your ScrollView inside your .h file and synthesised it in the .m file make sure you tell it that it's delegate is itself:
ScrollView.delegate = self;
Then use the following method to detect where you are in your current scrollview
- (void) scrollViewDidScroll:(UIScrollView *)scroll {
if(scroll.contentOffset.y > /*Your Y coordinate*/){
// What you want to do when it reaches your y coordinate.
}

Implement UIScrollViewDelegate, and use the scrollViewDidScroll function. This will notify you every time the scrollView is scrolled. You can get the current location of the scrollView, and update your text accordingly.
More help on Apple Documentation

Related

UIScrolllView scroll limit position

I have an UITableView inside an UIScrollView and I want that the user will be able to scroll just when he touches the tableView (I have a map in the background and I want that the user will be able to integrate with the map when the tableView doesn't covers all of it.
I've tried to set scrollViewHeightConstraint.constant to scrollView.contentOffset.y on -(void)scrollViewDidScroll:(UIScrollView *)scrollView but it didn't work, part of the map is still not touchable. Can anyone give me an advice what should I do? Thanks!
Screenshot: Screenshot
OK. I think I understand what you're trying to do. Here is the solution I have come up with. Let me know if this works for you or not.
First off, you need to set the contentInset of the table view in your view controller (or if it's possible in the storyboard, set it there. Not sure if it is though?). It's a simple one-liner in viewDidLoad or viewWillAppear:, like so:
self.tableView.contentInset = UIEdgeInsetsMake(400.f, 0.f, 0.f, 0.f);
The 400.f is just saying start the table view's content 400 points from the top. You can set it to whatever number you'd like or, if you know you want it 200 points from the bottom, do something like this:
self.tableView.contentInset = UIEdgeInsetsMake(self.view.bounds.size.height - 200.f, 0.f, 0.f, 0.f);
With your content situated OK, now you need to create a subclass of UITableView to use as your table view's class. This class should override one method: hitTest:withEvent:. You can set which class you're using for your table view in your storyboard (click on the table view, then go to the Identity Inspector), or you can just change it in your view controller if you're not using storyboards.
In the method you're overriding, you're checking to see if where the user has touched the screen is above the contentInset or not (which works for your design). For a more complex design, you'd need some more robust checking.
This should allow the MKMapView to intercept the scroll events from the table view (which is returning nil and disabling scrolling).
Here is the UITableView subclass (you can name it whatever you want):
EmbeddedTableView.h
#import <UIKit/UIKit.h>
#interface EmbeddedTableView : UITableView
#end
EmbeddedTableView.m
#import "EmbeddedTableView.h"
#implementation EmbeddedTableView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (point.y < 0.f) {
self.scrollEnabled = NO;
} else {
self.scrollEnabled = YES;
return [super hitTest:point withEvent:event];
}
return nil;
}
#end

Determine if button can be seen by user

I have an interesting requirement. I have a webview that expands in size when the user swipes up. This works well, but now I am trying to detect if the user has scrolled up to the top, so that I can minimize it again.
I am trying to do this by placing an image behind the webview, if the user scrolls past the top of the webview, the bounce effect takes place and the underlying image becomes visible. I was trying to use the "hidden" property thinking that the image is hidden when under the webview, but visible when the webview has been pulled down. This however, doesnt seem to work properly.
Anyone have any ideas on how to detect if a button/image is visible to the user?
Because the UIWebView implements UIScrollViewDelegate, it declares conformity to that protocol, you can use the ScrollViewDidScroll delegate method.
First make sure that your UIWebView is not inside a UIScrollView
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
Instead, you can access the UIScrollView through the UIWebView properties since we now know that UIWebView is based on a UIScrollView. Your view controller can implement the UIScrollViewDelegate.
#interface MyViewController : UIViewController<UIScrollViewDelegate>
#end
Then you have to set the scrollView property inside your webview to the UIScrollViewDelegate like so:
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the scrollView property's delegate protocol to self. This is so that this view controller will receive the delegate methods being fired when we interact with the scrollView.
webView.scrollView.delegate = self;
}
We're only interested in one of the ScrollView's delegate method - scrollViewDidScroll. Then you can detect when the scrollView has been scrolled inside your webview and ultimately have a simple mathematics equation that checks if the scrollView has been scrolled to the top:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scrollView.contentOffset.y <= 0.0){
NSLog(#"TOP REACHED so do the chicken dance");
}
}
Look for contentOffset of scroll view of Web view if it's Y==0 then it means that user has scrolled up to the top.
CGRect visibleRect;
visibleRect.origin = webView.scrollView.contentOffset;
if(visibleRect.origin.y == 0)
{
//t means that user has scrolled up to the top
}

Hiding a toolbar element when UITableView scrolls (similar to Facebook's app?)

How I can achieve this effect?
This isn't immediately noticeable from your screenshots, but I believe you want the that header toolbar to slide up as the user scrolls, right? (I'd suggest clarifying on that part)
You can do this a few ways, and in all of them you will have to implement your own scrolling logic, meaning how much the header toolbar slides up depending on where you have scrolled. That said, here's how to do it:
1. If you're using UITableView, I assume you've got your view controller set as its delegate. Since UITableView is a subclass of UIScrollView already, just add the UIScrollViewDelegate to your view controller. That will give us scroll events as they happen. You'll want to do your logic in scrollViewDidScroll:.
2.. If you're simply using UIScrollView, just set your view controller as its delegate, implement UIScrollViewDelegate, and do your logic in scrollViewDidScroll:.
That said, your code might look something like this:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint scrollPos = scrollView.contentOffset;
if(scrollPos.y >= 40 /* or CGRectGetHeight(yourToolbar.frame) */){
// Fully hide your toolbar
} else {
// Slide it up incrementally, etc.
}
}
Anyway, hope I helped.
If you have properly set the delegate, your table will call scrollViewDidScroll: when scrolled.
So in your controller, you can add something like :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y >0) //means that the user began to scroll down the table
{
[UIView animateWithDuration:0.4 animations:^{
//animations you want to perform
}];
}
}
Here i implemented code for UIView Hide / Show when tableview scrolling. When tableview scrolling down then UIView is hidden and when scrolling up then UIView show. I hope it's working for you...!
Step 1:- Make one property in .h file
#property (nonatomic) CGFloat previousContentOffset;
Step 2:- Write down this code in scrollViewDidScroll Method.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat currentContentOffset = scrollView.contentOffset.y;
if (currentContentOffset > self.previousContentOffset) {
// scrolling towards the bottom
[self.subButtonView setHidden:YES];
} else if (currentContentOffset < self.previousContentOffset) {
// scrolling towards the top
[self.subButtonView setHidden:NO];
}
self.previousContentOffset = currentContentOffset;
}
I create simple class for this effect:
UIHidingView is an iOS class that displays UIView element on top UITableView which is hiding when Table View is scrolling.
This will answer your question :
iPhone: Hide UITableView search bar by default
same concept, different control. You can put a UIView on top row of tableview or any other relevant control such as button.
Good luck.

Getting subViews' frames in Storyboard

I just want (for now) to get the dimensions of a subview on the view controller's instantiation.
[This is a reduction to as simple a case I can find of a previous question. I am trying to figure out why subViews of scenes in Storyboards are not behaving the way I expect, which is to say: like XIBs do - I just want to get dimensions of my subviews before anything is actually drawn to the screen]
To condense the problem down to a new, clean project, I do this:
create a new, single view project with "using Storyboard" checked
add a single UIView to the default existing MainStoryboard_iPad.storyboard (and change its background to green to make it more easily seen - beyond shrinking the dimensions some, this is the only change I make from the default UIView I drag onto the scene)
option-click the ViewController.h file in the navigator to bring it up in its own frame underneath the Storyboard frame and insert a pair of braces underneath the #interface directive
control-click-and-drag from the UIView in the Storyboard to ViewController.h and tell it to name the outlet firstViewFirstSubView
So we now have for ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UIView *firstViewFirstSubView;
}
#end
Then, I add this method to the ViewController.m:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"View Controller will appear. firstViewFirstSubView: %# ", firstViewFirstSubView);
NSLog(#"subView's dimmensions: %f by %f at %f, %f", firstViewFirstSubView.frame.size.width,
firstViewFirstSubView.frame.size.height,
firstViewFirstSubView.frame.origin.x,
firstViewFirstSubView.frame.origin.y);
}
At this point, I expect to be able to get the dimensions of the UIView subview. I get all 0s, though:
2012-11-15 15:21:00.743 StoryboardViewBounds[11132:c07] View Controller will appear. firstViewFirstSubView: <UIView: 0x9379730; frame = (0 0; 0 0); autoresize = TM+BM; layer = <CALayer: 0x9378e40>>
2012-11-15 15:21:00.744 StoryboardViewBounds[11132:c07] subView's dimmensions: 0.000000 by 0.000000 at 0.000000, 0.000000
What am I doing wrong? It seems like this should be very straightforward, so I think I must be missing something simple, whether throwing the right switch in the Storyboard editor or implementing a method that Storyboard needs.
Those dimensions are calculated and set when the call to layoutSubviews is made, which occurs after viewWillAppear. After layoutSubviews is called on the UIVIew you can get the dimensions.
Look at implementing this method in your view controller: viewDidLayoutSubviews. At this point you should be able to get dimensions of your subviews. Note that this call is available starting in iOS 5.0 but since you reference storyboards I assume you are working at or above that anyway.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSLog(#"View Controller did layout subviews. firstViewFirstSubView: %# ", firstViewFirstSubView);
NSLog(#"subView's dimmensions: %f by %f at %f, %f", firstViewFirstSubView.frame.size.width,
firstViewFirstSubView.frame.size.height,
firstViewFirstSubView.frame.origin.x,
firstViewFirstSubView.frame.origin.y);
}
There is a Related issue that I am compelled to address, which hopefully will save someone else a day of debugging:
I am finding out that in Storyboard:
segue-push does not cause subViews to be laid out at -viewDidLayoutSubviews (they are instead laid out at some other time just before -viewDidAppear).
Whereas...
segue-modal and [navController.storyboard presentViewController:] does cause subViews to be laid out at -viewDidLayoutSubviews.
The solution is to put [self.mySubView layoutSubviews] within the viewController's -viewDidLayoutSubviews method in order to manually load the subViews within mySubView.
My case was that I had a custom gradient button that was not properly initializing it's visual appearance.
The button was contained within a scrollView that contained a CustomView which contained the custom gradient button.
So, basically... a button within a view within a scrollView.
The app starts out with a UINavigationController having some other ViewController1 loaded.
ViewController1 contains a button which, when pressed, launches a storyboard segue-push to ViewController2.
(this was arranged in storyboard by control-dragging from the button in ViewController1 to ViewController2).
ViewController2 contains the scrollview/customView/customButton.
In ViewController2's -viewDidLayoutSubviews, I initialize the customButton which is a custom Gradient Button having it's own .h/.m files.
GradientButton.m has an initLayers method which configures it graphically and requires the bounds/frame property of the button to be initialized.
However...
in ViewController2's -viewDidLayoutSubviews, self.customButton had a frame of 0,0,0,0.
A few notes:
Yes, I am calling [super viewDidLayoutSubviews] at the beginning of -viewDidLayoutSubviews.
The only view that has been laid out at -viewDidLayoutSubviews is self.view (ViewController2's initial view, as connected in Storyboard's connections panel. in my case - self.view is a scrollView).
To resolve:
in ViewController2, I created an outlet self.bottomView for the view that contained self.customButton.
in ViewController2's -viewDidLayoutSubviews, I call [self.bottomView layoutSubviews]
This will then cause customButton's frame/bounds to be properly set.
Next, I call [self.customButton initLayers] which now properly initializes my custom gradient button.
A few notes about ViewController2's -viewDidLayoutSubviews: calling [self.view layoutSubviews] causes bottomView's frame to be initialized, but NOT customButton's frame.
In terms of a view hierarchy, -layoutSubviews applies only to the subViews of self.view and not to any subViews of those subViews.
This only appears to be the case with storyboard segue-push.
The storyboard segue-modal and the programmatic [navController presentViewController] both seem to correctly initialize all levels of the view hierarchy (all "subViews of subViews") by the time -viewDidLayoutSubviews is called.

UISearchDisplayController change dimmed view frame

In my iPad app I have an UITableView. Table's frame size is less than screen size, so to make search functionality look nice I have to adjust searchResultTableView's frame to fit my TableView. I'm doing it in my UISearchDisplayDelegate's -searchDisplayController:willShowSearchResultsTableView: method.
Everything works fine except dimming view. When I'm starting search dimming view's width is equal to screen width:
When I start entering search string or clear textfield my searchResultsTableView resizes properly and everything works as it should:
I tried to change searchResultsTableView frame inside -searchDisplayControllerWillBeginSearch: method using this line
controller.searchResultsTableView.frame = myFrame;
but it doesn't work as well. Any suggestions besides implementing my own search display controller?
I also needed to change the frame of the dimming view but for a different reason. In my case I created a UISearchDisplayController and UISearchBar programmatically in a regular UIViewController not a UITableViewController. I was also using MFSideMenu which added to the complexity of the problem. What ended up happening was the dimming view was in the correct position initially but the next time the search was cleared the dimming view shifted leftwards and upwards by exactly half of it's size. Given the UISearchDisplayController you can find the dimming view like so.
for(UIView * v in controller.searchContentsController.view.subviews)
{
if([v isMemberOfClass:[UIControl class]])
{
v.frame = newFrame; //This frame should account for the UISearchBar
}
}
To handle for the initial incorrect frame you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView;
To handle for an incorrect frame on any subsequent clears you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView;
Note: this solution runs through the subviews of the searchContentsController which is one of the reasons I used isMemberOfClass instead of isKindOfClass (UIButton is a subclass of UIControl). Further discrimination would be required if you added a UIControl instance into your view (you could use tags to help determine which ones are yours).

Resources