UIScrollView got freeze when Back button pressed? - ios

I am having a (UIView and UICollectionView in a UIScrollView) as 1stVC. I have to scroll both at the same time for which I already unable the collection view scrolling. So first time When I launch that screen I am able to scroll the whole view, But when I push to (next ViewController) 2ndVC and then press Back Button to 1stVC my scroll view is not preforming it got Freeze.
Tried this Method:-
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^ {
CGRect contentRect = CGRectZero;
for(UIView *view in self.scrollView.subviews)
contentRect = CGRectUnion(contentRect,view.frame);
self.scrollView.contentSize = contentRect.size;
});
}
Tried this Method:-
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[_scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width, _scrollView.frame.size.height)];
}
And For Getting Dynamic Height of the Collection view I have Done This
CGFloat height = _collectionCompass.contentSize.height;
Which I Have provided to ScollView ContentSize.
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width, height);
Please help me.

What I really suggest it's to remove scroll view and do all stuff in collection view, since with scroll view you're missing some of benefits (e.g. cells reusing). Also collection view in scroll view it's a bad practice.
From Apple style guide:
Don’t place a scroll view inside of another scroll view. Doing so creates an unpredictable interface that’s difficult to control.
If your UI as list, you can add view as header of collection view or as another cell. With this approach you can remove the code from viewDidLayoutSubviews

Related

How to stop a UIView from scrolling with tableview?

I have a UITableViewController and I put a UIView right under the navigation item and above the actual table. The problem that I have is that the view scrolls with the tableview.
How would I get it to behave exactly like the nav bar, and have the items in the tableview scroll behind it.
Rather than having the view scroll, it should remain in its position and have everything go behind it. Sorry for reiterating, but I've found thats necessary sometimes.
The view you're placing above the cell in the storyboard becomes the table view's tableHeaderView.
You can make the header view appear fixed by resetting its frame.origin to the table view's bounds.origin every time the table view lays out its subviews:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIView *header = self.tableView.tableHeaderView;
CGRect frame = header.frame;
frame.origin = self.tableView.bounds.origin;
header.frame = frame;
}
Result:
Assuming you don't want the map view to move then you could set its user interaction to false.
Alternatively you could set the header of your tableView (if you only have one section) to the map view.

IOS - Keep UIView on top of UITableView on scroll

I have a UITableView with a UIView on top. I want the UIView to stick to the top as the tableView cells scroll over it.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.tableView.contentOffset.y > 0) {
CGRect newframe = self.publicTopView.frame;
newframe.origin.y = -self.tableView.contentOffset.y;
self.publicTopView.frame = newframe;
NSLog(#"After: %f", self.publicTopView.frame.origin.y);
}
}
You need to set your table view header view to the view you want on top.
Add this code to you viewDidLoad
self.tableView.tableHeaderView = self.publicTopView
I'm not certain what you're trying to accomplish, but I have a guess at what is wrong. As you scroll your contentOffset will continue to change and let's say your tableView has a content size height of 1500, then your contentOffset will eventually be larger than the height of your view controllers view. Now see that you are putting that contentOffset into the origin.y of your publicTopView. So your publicTopView could possibly be moving too much, even offscreen depending on how large your tableview's content size is.

ScrollviewDidScroll not called at each point

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}];
}

how to keep uiview in view

i have a view that is required to be stayed on the view when the user scroll up or down in a scrollview.
i managed to let it stay on top of the view but how can i allow it to stay at the bottom of the view when i scroll down ? EDIT: attached picture to explain better.
the view will alway be visible on the view.
-(void) scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog (#"Content Offset: %f", self.playlistTableview.contentOffset.y);
if (self.playlistTableview.contentOffset.y > playerPosition) // will keep the view at the top
{
CGRect newFrame = self.playerView.frame;
newFrame.origin.x = 0;
newFrame.origin.y = +self.playlistTableview.contentOffset.y;
[self.playerView setFrame: newFrame];
}
}
you can see how the NZD have a top overlay that stops
Try to add your ScrollView and Always Stay view in a container view. So it will not scroll when you do scroll the scroll view. and anytime you can change your always stay view to different frame to top or bottom as u needed
UIView--->
1st subview--->UIScrollView
2nd subview--->Don't ScrollMeView/Always Stay view
I think you have added your view in contain of UIScrollView.
I mean, main container for your view is UIScrollview, so it'll work as subview of UIScrollview and will follow scrollview properties.
Can you please try to add your view on main view.
[self.view addSubView:yourViewObj];
If that comes behind the scrollView, then please try with
[self.view bringSubviewToFront:yourViewObj];

Nested UIScrollViews and event routing

I have 2 scroll views, both of which are supposed to scroll vertically. The outer scroll view (red) contains a search bar and the inner scroll view (blue). The inner scroll view is supposed to scroll infinitely (it contains images/items and has an endless scrolling implementation).
The way I want this controller to work is as follows:
When I scroll down, the outer scroll view should scroll first and the search bar should disappear (scroll out of the content area). Only after that the inner scroll view should start scrolling.
When scrolling back up, the inner scroll view should scroll all the way to its top. Only then the outer scroll view should take the scroll events and finally scroll up to make the search bar visible again.
If I just nest them in IB without any modifications the inner scroll view catches all the scroll events and it works the other way around.
Please bear in mind that I'm using the inner scroll view as a simplifying metaphor here. In my app I actually have a control here, which has a scroll view with nested table views (scroll view lets me page horizontally, table views let me scroll vertically).
If you are able to, set a common UIScrollViewDelegate on the 2 scroll views, and implement the following:
- (void) scrollViewDidScroll: (UIScrollView*) scrollView
{
if (scrollView == self.mainScrollView)
{
/* Handle instances when the main scroll view is already at the bottom */
if ( scrollView.contentOffset.y
== scrollView.contentSize.height - scrollView.bounds.size.height)
{
/* Stop scrolling the main scroll view and start scrolling the
* inner scroll view
*/
self.innerScrollView.scrollEnabled = YES;
self.mainScrollView.scrollEnabled = NO;
}
else
{
/* Start scrolling the main scroll view and stop scrolling the
* inner scroll view
*/
self.innerScrollView.scrollEnabled = NO;
self.mainScrollView.scrollEnabled = YES;
}
}
else if (scrollView == self.innerScrollView)
{
/* Handle instances when the inner scroll view is already at the top */
if (self.innerScrollView.contentOffset.y == 0)
{
/* Stop scrolling the inner scroll view and start scrolling the
* main scroll view
*/
self.innerScrollView.scrollEnabled = NO;
self.mainScrollView.scrollEnabled = YES;
}
else
{
/* Start scrolling the inner scroll view and stop scrolling the
* main scroll view
*/
self.innerScrollView.scrollEnabled = YES;
self.mainScrollView.scrollEnabled = NO;
}
}
}
Please note that I haven't tested this, but the logic could be somewhat like this (either you set scrolling enabled or you disable user interaction, or something). Most probably this will not be enough of a solution as you would like, but I'm sure a common UIScrollViewDelegate is the solution to your problem.
I given the example for one scrollview, samething you have to create onemore scrollview and add based on dynamic height and content size it will work.
// .h file
#property (nonatomic, strong) UIScrollView *scrlSearch;
// .m File // ViewDidLoad
scrlSearch = [[UIScrollView alloc] init];
// For first scroll screen height was ((total screen height / 100 )* 10% )
// For Second scroll screen height was ((total screen height / 100 )* 90% )
scrlSearch.frame = CGRectMake(0, 0, (YourScreenWidth), (YourScreenHeight));
// YourVIEW = add any view to scrollbar
[scrlSearch addSubview:YourVIEW];
CGSize contentSize = scrlSearch.frame.size;
// YourContentHeight = dynamic content or static content height
contentSize.height = YourContentHeight;
// set the ContentHeight for scrolling
[scrlSearch setContentSize:contentSize];
// add the scrollview into delegate
[scrlSearch setDelegate:self];
Use just one scrollView and set the contentInset/contentOffset for the search bar. Something along this line:
UIEdgeInsets oldEdgeInset = [[self scrollView] contentInset];
CGRect f = [[self searchBar] frame];
UIEdgeInsets newEdgeInset = UIEdgeInsetsMake(CGRectGetMaxY(f), 0, 0, 0);
CGPoint offset = [[self scrollView] contentOffset];
offset.y += oldEdgeInset.top - newEdgeInset.top;
[[self scrollView] setContentOffset:offset];
[[self scrollView] setContentInset:newEdgeInset];
[[self searchBar] setFrame:f];
I am not sure about the structure you have and want to implement..
I have made a test project find here
But the project will definitely help you to manage different scrollviews all together..
The application might not be perfect though, but will give you some idea to achieve the solution.
Hope it helps..
Cheers
You should add inner scrollview on outer scrollview, but inner scrollview 'y' position should be content off set of outer scrollview like...
innerScrollView.frame = CGRectMake(10, outerScrollView.contentSize.height, 300, 440);
After this you can add any view on this innerScrollView, you can set contentOffset etc for innerScrollView.
Finally you should increase the contentSize for outer scrollview.
outerScrollView.contentSize = CGSizeMake(320, innerScrollView.frame.size.height+actualContentSizeOfOuterScroolView);
I think it helps for you!
Create a swipe gesture recognizer to your top-most view (above all the scroll views, on your view controller's view), and make it recognize UISwipeGestureRecognizerDirectionUp.
Then, you need to notify your controller whenever the outer scroll view scrolls.
Once it's scrolled down, add the gesture recognizer. When it hits the top again (outerScrollView.contentOffset == (0,0)), remove the gesture recognizer.
The gesture should 'eat' all the swiping events while it's present, making your inner scroll views to not receive the touch event and therefore will not scroll

Resources