I tried this:
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
But it didn't fire when I scrolled the table view to the top.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
Does fire so the delegate isn't the problem.
In viewDidLoad I also set [myTbl setDoesScrollToTop:YES];
The scrollViewDidScrollToTop: method fires when the user clicks on the status bar and the scrollsToTop property is set to YES. From the docs:
The scroll view sends this message when it finishes scrolling to the top of the content. It might call it immediately if the top of the content is already shown. For the scroll-to-top gesture (a tap on the status bar) to be effective, the scrollsToTop property of the UIScrollView must be set to YES.
It does not fire if the user manually scrolls to the top. If you want to handle this case you will have to implement the scrollViewDidScroll: method and check to see whether the scroll is at the top yourself.
You can check this through the contentOffset property e.g.:
if (scrollView.contentOffset.y == 0) { // TOP }
When the table view goes under navigation bar and safe area layout guides are enabled, the following check can be done:
if (tableView.contentOffset.y + tableView.safeAreaInsets.top) == 0 { ... }
Bonus: Check for contentSize if you want to avoid getting 0 before the content is load:
if tableView.contentSize.height > 0 &&
((tableView.contentOffset.y + tableView.safeAreaInsets.top) == 0) { ... }
Related
Evening: I have a scroll view with 3 views inside..
I have a problem with the scrollview delegates.
The didscrolltotop is never called, while the did scroll yes...
I can't understand the reason...
Any help?
Looks like it is only called under certain circumstances, the documentation talks about the scroll-to-top gesture meaning it may only work after a tap on the status bar and not basic scrolling. Also setting the scrollsToTop property to true seems to be required.
The scroll view sends this message when it finishes scrolling to the top of the content. It might call it immediately if the top of the content is already shown. For the scroll-to-top gesture (a tap on the status bar) to be effective, the scrollsToTop property of the UIScrollView must be set to YES.
You could also simply detect the top of the content using the contentOffset
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("The current Y offset is \(scrollView.contentOffset.y)")
if scrollView.contentOffset.y == 0 {
print("we are at the top")
}
}
You might also want to consider using the scrollViewDidEndDecelerating method for this as it will mean you only get one event after the scroll view has settled down.
hi... really how do they implement this? there are several tutorial for Twitter profile page. but they don't handle all possibilities...
first... when you scroll top or bottom any where, top view start scrolling until the segmented control, reach at top of the page...then scroll doesn't stop and subtable start scrolling until touching down and middle of way tableview start loading other rows dynamically ... so I don't think that they set content of scrollview statically
second things how do they handle sub tables... are they containerView?
if so, then the structure would be like this
ScrollView
TopView (User Info)
Segmented Controll
scrollView(to swipe right or left changing tables)
ContainerView For TWEETS
ContainerView For TWEETS & REPLIES
ContainerView For MEDIA
ContainerView For LIKES
am I right?
so how do they handle scrolls between sub tables and Top Scroll View to implementing topview position change base on scrolling...
it's mind blowing
this is How I Handel Nested ScrollViews...
i made a childDidScroll Protocol and my child tableviews implement that and in my profile page i can receive all child didscroll event then in
childDidScroll method :
//if child scrollview going up
if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0)
{
//check top scrollview if it is at bottom or top
//then disable the current scrollview
if mainScrollView.isAtBottom && scrollView.isAtTop{
scrollView.isScrollEnabled = false
}else{
//else enable scrolling for my childs
featuresVC.tableView!.isScrollEnabled = true
categoriesVC.tableView!.isScrollEnabled = true
shopsVC.tableView!.isScrollEnabled = true
}
print("up")
}
else
{
if mainScrollView.isAtTop {
scrollView.isScrollEnabled = false
mainScrollView.scrollToBottom()
}else{
featuresVC.tableView!.isScrollEnabled = true
categoriesVC.tableView!.isScrollEnabled = true
shopsVC.tableView!.isScrollEnabled = true
}
print("down")
}
but this solution has a some cons... and one of the is that first when child scrollview is at top or button, there should be two try to call my parent scrollview handle the scrolling, in first try i disable the child scrollview, and in second try parent scrollview handle the scrolling
** how can i say when you , my child, scrolling up, check if your parent is at top, then let him handle the scroll and when he touching the bottom, you can handle remain up scrolling, or tell the parent scrollview , if you are at top (user info is visible) if you or your child getting up scrolling, first you handle the scroll and when you rich at bottom(user info is not visible), let the remain scrolling on you child**
After a long long investigation that is how i achieve the twitter profile behaviour.
UnderlayScrollView
MasterScrollView
Header ViewController
Bottom ViewController
PagerTabItems [CollectionView]
UIPagerController or any other horizontal scroll (Parchment, XLPagerTabStrip).
UnderlayScrollView is responsible of controlling the scroll gesture. its contentoffset is used to adjust inner scroll contentOffsets. Contentsize of the underlaying scroll is same as the masterscroll's contentsize.
See the source code on github for more. click
I believe you are mostly right, except for the topmost scroll view.
In a recent app, I implemented something similar following this tutorial:
Basically, the trick is to have a class be the scrolling delegate of the bottom UITableViews, listen to the scrollViewDidScroll modifications, and modify the top inset of the UITableView and the TopView.
The structure I would use is like this:
Topview
ScrollView (horizontal scroll)
Segmented Control
ScrollView (horizontal, paging scroll)
UITableView
UITableView
UITableView
UITableView
You are totally right in it being mind blowing. Looks so simple.
I found a library,
https://github.com/maxep/MXSegmentedPager
Its totally works fine
I am adding a UISearchBar to my UITableView. Like in many apps, the search bar would initially be hidden behind the navigation bar until the user scrolls upwards, revealing it. I use the code bellow to initially hide the search bar which works very well when the table view has enough cells to need scrolling, but does not hide the bar when there are only a few cells in the table view. How can I go about hiding the search bar when there are less than enough cells to cause the table view to scroll.
Current Code:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (!self.layedOutHeader) {
CGPoint contentOffset = self.alertsTableView.contentOffset;
if (contentOffset.y == -64 || contentOffset.y == 0) {
contentOffset.y += CGRectGetHeight(self.alertsTableView.tableHeaderView.frame);
self.alertsTableView.contentOffset = contentOffset;
}
self.layedOutHeader = YES;
}
}
Here is an example of how when only a few cells are present, the search bar is not hidden:
Try to add tableFooterView with the required height to fill the screen when you don't have enough cells.
There is a button at the bottom of my view controller. When the user scrolls down the button has to be attached to the scrollview at certain height.
I need to attach a button to the scrollview, immediately when the contentOffset.y reaches a particular value. -(void) scrollviewDidScroll doesn't help me as there might be a jump in contentOffset when the user is scrolling fast. Any leads on this are helpful.
Also, whenever I add a subview to the scrollview, -(void) viewDidLayoutSubviews is called. Which in turn sets the contentOffset to {0,0}. How can I achieve the functionality I need?
I needed to do the same thing with a UITableView and for me using scrollViewDidScroll worked.
I created a view called staticBar and added it as a subview of the tableView, but I had to rearrange the tableview subviews for it to appear in the right place. I don't have my code in front of me, but in -scrollViewDidScroll: it looked something like this:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
CGFloat staticBarAdjustedY = _staticBarY - scrollView.contentOffset.y;
CGFloat scrollViewYFloor = scrollView.frame.size.height - _staticBar.frame.size.height;
// This way maximum Y the view can have is at the base of the scrollView
CGFloat newY = MIN( staticBarAdjustedY, scrollViewYFloor);
_staticBar.frame = (CGRect){ { _staticBar.frame.origin.x, newY}, _staticBar.frame.size}
}
I will check my code later today and add more details here.
Also, you said the scrollviewDidScroll has jumps in contentOffset, but it's worth mentioning that these jumps are the same that the scrollView uses to scroll its own view. So it's not like you are "losing" frames on this delegate method.
Hope it helps.
PS: So, here is the rest of my code.
//I place my custom view as a subview of the tableView below it's last subview
//The last subview is for scroll indicators.
WTButtonsBar *buttonBar = [[WTButtonsBar alloc] init];
[self.tableView insertSubview:buttonBar belowSubview:self.tableView.subviews.lastObject];
In scrollViewDidScroll:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//In my app I needed my view to stick to the top of the screen
//thats why I use MAX here
//self.buttonsBarOriginalY is the view's position in the scrollView when it isn't attached to the top.
CGFloat newY = MAX(scrollView.contentOffset.y, self.buttonsBarOriginalY)
[_buttonsBar setFrame:(CGRect){{0, newY}, _buttonsBar.frame.size}];
}
I have a UIScrollView inside a UICollectionViewCell an I'm trying to perform an action when a UIScrollView scrolls to a certain -x value.
I've tried
CGPoint lastOffset;
if (lastOffset.x < -50 && scrollView.contentOffset.x >= -50) {
// Animate the star
NSLog(#"Animate");
}
but the problem is that it only gets called when the scrollVIew is returning to its normal state.
for the heck of it, I've also tried
if (scrollView.contentOffset.x >= -50) {
// Animate the star
NSLog(#"Animate");
}
but this doesn't always get called.
Basically, what I am trying to create is something like the pull to refresh, but on the scrollViews's x access.
Another example if what I am trying to do is what Tweetbot 3 for iPhone does. If you swipe right on a cell you get the options to reply, star, etc etc.
Whats the best way to solve this?
Update: I'm using a UICollectionViewCell.
The way the scrollview is set up is something like this:
What I'm trying to do is to bring the gutter view in :
and animate a little star when the scrollView reaches -50 on the x axis.
The reason why I'm placing this view and the animating the star in the negative part of the scrollView's content bounds, is to allow the scrollView to snap back into place.
Update 2: I've figured it out. I'll accept my answer soon as I am allowed to. Thanks for everyone's input!
I've also have the same problem,this is my solution。
1:addsubview into scrollview,not full screen. because scrollview and tableview will call touch event(ps: U can get touch object in touch event).
just like this :## Heading ##
2:U can detect user touch time,such as >=3s call scrollview another call tableview. but that is less than method。
About Tweetbot3
U just add uiview and uipangesturerecognizer into coustom tableview cell. and try this SWTableViewCell
You can get the value during scroll using the UIScrollViewDelegate method scrollViewDidScroll:
self.scrollView.delegate = self;
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
if (scrollView.contentOffset.x >= -50) {
// Animate the star
NSLog(#"Animate");
}
}
Just be careful with your animation because the user could scroll back and forth between a contentOffset of 50 which may mess up your animation depending on how you've set it up.
if (lastOffset.x > -50 && scrollView.contentOffset.x <= -50) {
// Animate the star
NSLog(#"Animate");
}
I wasn't checking to see if the lastOffest.x was greater than -50, I was checking if it was less.