Hide UIView using alpha when user starts scrolls on UITableView? - ios

viewController is composed of 2 main views. A container view and a table view.
The container view is the top section with all the labels such as the day and score.
I want this container view to hide when a user starts scrolling through the days of the table view.
So far I have:
Hooked up an IBOutlet for this container view so I could reference it in the code.
Conformed to the UIScrollViewDelegate
Implimented all required methods for the UITableView
I know UITableView is a subclass of UIScrollView. Without a "proper" UIScrollView I am confused how to go about using the scrollViewDidScroll method and changing the container view alpha to 0 when I am scrolling in the tableView.
I also want the alpha to return to 1 when the user stops scrolling.
thanks.
Note I am not using a UITableViewController

You should use a UITableViewController instead of a UIViewController and then drag a UIView in the header section of the UITable. This will cause the UIView to get out of the way on scrolling right out of the box with no coding at all.

If you already set your UITableViewDelegate IBOutlet your controller you will receive all UITableViewDelegate methods from your UITableView as well as all UIScrollViewDelegate methods, should you implement them.
If you would like to hide a particular view when the user starts scrolling I'd use the -scrollViewWillBeginDragging method
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
{
[UIView animateWithDuration:0.5f animations:^{
someView.alpha = 0.0f;
}];
}
If you would like to show it again after the user stops scrolling, just use the method -scrollViewDidEndDragging:willDecelerate:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
[UIView animateWithDuration:0.5f animations:^{
someView.alpha = 1.0f;
}];
}

Use the following methods directly in controller. They will work :
// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

What have you made UIScrollViewDelegate?
I just took a UITableViewController in my current project and added UIScrollViewDelegate
#interface YourTableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate,UIScrollViewDelegate>
then stuck a comment in
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
and it called once as required (scrollViewDidScroll: will fire repeatedly). So I presume calling one of the UIView animateWithDuration: methods will complete the task you require?

Related

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

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

Observe the transition state of UIPageViewController

I would like to tweak the visual state of a view based on how much it is "on screen". These views are managed by a UIPageViewController, using the stock .Scroll transition style.
The behavior I would like is to have the title be 100% opacity when it is 100% on screen and 0% opacity when it is 0% on screen, transitioning between the two as a function of the panning navigation gesture/animation.
I am hoping I can plug into the x-coordinate or a percentage animation complete, but I don't see a property anywhere. I understand the page view controller is using a scroll view behind the scenes but am a little concerned about reaching into a private API, and I don't see a public method to access it.
Is there any way to hook into the existing interactive transition so that I can add some additional behaviors to the child view controllers that scale based on the completion percentage?
Update:
Tried implementing UIScrollViewDelegate's scrollViewDidScroll. No luck. I think page view controller does to call methods on this delegate.
Tried using viewWillDisappear/viewDidAppear in the child view controllers. This is functional but the animation is not responsive since these are called as single events at the start/end of user behaviors.
You already update your question about UIScrollViewDelegate but, for simillary problem I use UIScrollViewDelegate like this:
for(UIView *aView in self.pageViewController.view.subviews){
if([aView isKindOfClass:[UIScrollView class]]){
UIScrollView* sv = (UIScrollView*)aView;
sv.delegate = self;
}
}
in my case UIPageViewController is inside a container view controller. That's why I added a delegate (PagerDelegate) in my class to call ContainerViewController when scroll view did scrolls:
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self.pagerDelegate viewDidScroll:scrollView];
}
at ContainerViewController:
#pragma mark - PagerDelegate
- (void)viewDidScroll:(UIScrollView*)scrollView {
// calculate the transition percentage and do anything you need...
}
Hope I understand correctly and it helps someone else. (probably you fixed this problem already because asked Jun 16 '15)

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
}

Cross Directional UIScrollViews - Can I Modify the Scrolling Behaviour?

Here's how the scroll views work: One scroll view is paging enabled in the horizontal direction. Each 'page' of this scroll view contains a vertically scrolling UITableView. Without modification, this works OK, but not perfectly.
The behaviour that's not right: When the user scrolls up and down on the table view, but then wants to flick over to the next page quickly, the horizontal flick/swipe will not work initially - it will not work until the table view is stationary (even if the swipe is very clearly horizontal).
How it should work: If the swipe is clearly horizontal, I'd like the page to change even if the table view is still scrolling/bouncing, as this is what the user will expect too.
How can I change this behaviour - what's the easiest or best way?
NOTE For various reasons, a UIPageViewController as stated in some answers will not work. How can I do this with cross directional UIScrollViews (/one is a table view, but you get the idea)? I've been banging my head against a wall for hours - if you think you can do this then I'll more than happily award a bounty.
According to my understanding of the question, it is only while the tableView is scrolling we want to change the default behaviour. All the other behaviour will be the same.
SubClass UITableView. UITableViews are subClass of UIScrollViews. On the UITableView subClass implement one UIScrollView's UIGestureRecognizer's delegate method
- (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer *)otherGestureRecognizer
{
//Edit 1
//return self.isDecelerating;
//return self.isDecelerating | self.bounces; //If we want to simultaneous gesture on bounce and scrolling
//Edit 2
return self.isDecelerating || self.contentOffset.y < 0 || self.contentOffset.y > MAX(0, self.contentSize.height - self.bounds.size.height); // #Jordan edited - we don't need to always enable simultaneous gesture for bounce enabled tableViews
}
As we only want to change the default gesture behaviour while the tableView is decelerating.
Now change all 'UITableView's class to your newly created tableViewSubClass and run the project, swipe should work while tableView is scrolling. :]
But the swipe looks a little too sensitive while tableView is scrolling. Let's make the swipe a little restrictive.
SubClass UIScrollView. On the UIScrollView subclass implement another UIGestureRecognizer's delegate method gestureRecognizerShouldBegin:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
CGPoint velocity = [(UIPanGestureRecognizer *)gestureRecognizer velocityInView:self];
if (abs(velocity.y) * 2 < abs(velocity.x)) {
return YES;
}
}
return NO;
}
We want to make the "swipe is clearly horizontal". Above code only permits gesture begin if the gesture velocity on x axis is double than on y axis. [Feel free to increase the hard coded value "2" if your like. The higher the value the swipe needs to be more horizontal.]
Now change the `UiScrollView' class (which has multiple TableViews) to your ScrollViewSubClass. Run the project. :]
I've made a project on gitHub https://github.com/rishi420/SwipeWhileScroll
Although apple doesn't like this method too much:
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.
I've found a great way to accomplish this.
This is a complete solution for the problem. In order to scroll the UIScrollView while your UITableView is scrolling you'll need to disable the interaction you have it.
- (void)viewDidLoad
{
[super viewDidLoad];
_myScrollView.contentSize = CGSizeMake(2000, 0);
data = [[NSMutableArray alloc]init];
for(int i=0;i<30;i++)
{
[data addObject:[NSString stringWithFormat:#"%d",i]];
}
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[self.view addGestureRecognizer:tap];
}
- (void)handleTap:(UITapGestureRecognizer *)recognizer
{
[_myTableView setContentOffset:_myTableView.contentOffset animated:NO];
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
scrollView.userInteractionEnabled = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
scrollView.userInteractionEnabled = YES;
}
To sum up the code above, if the UITableView is scrolling, set userInteractionEnabled to NO so the UIScrollView will detect the swipe. If the UITableView is scrolling and the user taps on the screen, userInteractionEnabled will be set to YES.
Instead of using UIScrollView as a container for these multiple table views, try using a UIPageViewController.
You can even integrate this into your existing view controller setup as a child view controller (directly replacing the UIScrollView).
In addition, you'll likely want to implement the required methods from UIPageViewControllerDataSource and possibly one or more of the methods from UIPageViewControllerDelegate.
Did you try the methods : directionalLockEnabled of both your table and scroll and set them up to horizontal for one and vertical for the other ?
Edit :
1)
What you want to do is very complicate since the touch wait some time (like 0.1s) to know what your movement will be. And if your table is moving, it will take your touch immediately whatever it is (because it's suppose to be reactive movement on it).
I don't see any other solution for you but to override touch movement from scratch to detect immediately the kind of mouvement you want (like if the movement will be horizontal) but it will be more than hard to do it good.
2)
Another solution I can advise you is to make your table have left and right margin, where you can touch the parent scroll (pages thing so) and then even if your table is scrolling, if you touch here, only your paging scroll will be touched. It's simpler, but could not fit with your design maybe...
Use UIPageViewController and in the -viewDidLoad method (or any other method what best suits your needs or design) get UIPageViewController's UIScrollView subview and assign a delegate to it. Keep in mind that, its delegate property won't be nil. So optionally, you can assign it to another reference, and then assign your object, which conforms to UIScrollViewDelegate, to it. For example:
id<UIScrollViewDelegate> originalPageScrollViewDelegate = ((UIScrollView *)[pageViewController.view.subviews objectAtIndex:0]).delegate;
[((UIScrollView *)[pageViewController.view.subviews objectAtIndex:0]) setDelegate:self];
So that you can implement UIScrollViewDelegate methods with ease. And your UIPageViewController will call your delegate's -scrollViewDidScroll: method.
By the way, you may be obliged to keep original delegate, and respond to delegate methods with that object. You can see an example implementation in ViewPagerController class on my UI control project here
I faced the same thing recently. My UIScrollview was on paging mode and every page contained a UITableView and like you described it worked but not as you'd expected it to work. This is how solved it.
First I disabled the scrolling of the UIScrollview
Then I added a UISwipeGestureRecognizer to the actual UITableView for left and right swipes.
The action for those swipes were:
[scroll setContentOffset:CGPointMake(currentPointX + 320, PointY) animated:YES];
//Or
[scroll setContentOffset:CGPointMake(currentPointX - 320 , PointY) animated:YES];
This works flawlessly, the only down side is that if the user drags his finger on the UITableVIew that will be considered as a swipe. He won't be able to see half of screen A and half of screen B on the same screen.
You could subclass your scroll view and your table views, and add this gesture recognizer delegate method to each of them...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:
(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
I can't be sure this is exactly what you are after, but it may come close.

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.

Resources