How to hide a search field on top of a UIScrollview - ios

I am trying to hide the search field by default in my app like seen in multiple Apple apps.
(Image credit: OS X Daily http://osxdaily.com/2017/07/27/search-notes-ios/)
Right now, the search field is on top of the contained view and it works fine. I could set a default offset to hide the search bar, but it won't prevent being shown when the scroll content size length is smaller than the scrollview.
By the way, I am NOT using a UITableView inside the UIScrollView, it's a custom view with subviews.

Hook the height constraint of you custom search view as IBOutlet and make this to hide it
self.searHeightcon.constant = 0
self.view.layoutIfNeeded()
Show
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.contentOffset.y == 0)
{
self.searHeightcon.constant = 50
}
else
{
self.searHeightcon.constant = 0
}
self.view.layoutIfNeeded()
}

If you always set the contentHeight to be same or larger than the scroll view’s height you can hide it by starting at an offset.

Related

How to change the height of the collection view in swift

I have a collection view and a text field on a ui view.
Initially, I have a text field at the top of the ui view and then I set the collection view top Anchor constraint to the bottom of the text field.
I want to implement a behavior where if I scroll down the collection view, the text field should disappear and the collection view's top should be at the top of the same ui view (this would hide the text field). When I scroll up, I want the constraints to be like the initial ones (container view's top Anchor should be set to the bottom of the text field). Any hint at how I might implement this behavior? I was hoping to implement this by updating the constraints when scrolling up and scrolling down happens. How can I implement this?
UICollectionView subclasses UIScrollView, so you can implement a UIScrollViewDelegate to get the scroll events.
Here is some code I use in one of my apps
The bottom of the text field is constrained to the top of the collection view
The top of the text field is constrained to the view's top layout guide - This is the constraint that is modified by the scroll view delegate code
As the collection view scrolls up the text field will move up and fade out
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let textHeight = self.textField.frame.size.height + 2
let offset = min(scrollView.contentOffset.y, textHeight)
if offset >= 0 || self.textFieldConstraint.constant != 0 {
self.textFieldConstraint.constant = -offset
let percent = max(1 - offset/textHeight,0)
self.textField.alpha = percent
}
}
}
Essentially you "push" the text field off the top of the screen, no more than its height+2
I think this solution can work full for you try this, just add a UIScrollView view as parent and put your text field and collection view in scroll view, as set the constraint as you set.

Set label text in navigation title when scrolling

In the storyboard, I have a label and many other objects in a UIScrollView. (The UIScrollView is in the view).
I want to set the navigation bar's title to the title of the label when the label scrolls past it.
I've tried this code but it doesn't work:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(self.lbl.frame.origin.x==60) {
self.navigationController!.navigationBar.topItem!.title = lbl.text
}
}
What should i do? I am new to Swift.
First off, I suspect you're actually trying to find the label's y value (i.e. vertical offset) as opposed to its x value, i.e. self.lbl.frame.origin.x==60.
Secondly you don't want the label's frame since that CGRect represents the label's position within the scrollview (which won't change); instead, you want the label's position within the superview.
That said, try this:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.convert(lbl.frame.origin, to: self.view).y <= 60) {
navigationController!.navigationBar.topItem!.title = lbl.text
}
}
There are several problems with your code:
self.lbl.frame.origin.x==60 What are the chances that this will ever be true? That's like flipping a coin and hoping it lands on its edge. The top of the label will never be exactly at a certain point.
The label's origin will never change; scrolling a scroll view doesn't change the frame of its subviews. You need to look at the scroll view's content offset (i.e. how far is it scrolled).
You need to complete your tests. What should happen when the user scrolls back the other way? Also, do you want to change the navigation item title repeatedly, every instant the user is scrolling, or just once?

Make UITableView Header "stickier", harder to pull down

I have added header with custom view to my TableView. It is used as a search bar, I set contentOffset so it is hidden in beginning.
Everything works as expected but I am wondering if there is any way to make it harder to pull down? (should be stickier) Now it opens with just regular scrolling which is too easy.
EDIT: ScrollViewDidScroll Code
if tableView.contentOffset.y < 80 && tableView.contentOffset.y > 40 {
subscriptionsTableView.contentOffset.y += 0.23
print("Content offset")
print(tableView.contentOffset.y)
}
I had a similiar problem and solved in quite easily in the end. I set the table view top inset to the height of the header
tableView.contentInset.top = -1 * headerView.frame.size.height
This makes the header be shown "off screen", the user is now not being able to scroll to it. I added a code to change the top inset to 0, showing the header, when the user scrolls to the top over the header
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 {
UIView.animate(withDuration: 0.25, animations: {
self.tableView.contentInset.top = 0
})
} else if scrollView.contentOffset.y > headerView.frame.size.height {
UIView.animate(withDuration: 0.25, animations: {
self.searchBar.resignFirstResponder()
self.tableView.contentInset.top = -1 * self.headerView.frame.size.height
})
}
}
I also set the top inset back when the user scrolls the table view.
My 2 cents: observe the contentOffset property of the table view (or implement the scrollViewDidScroll: method) and adjust the position of the view you want to stick.
Here is a reference to something that uses the same principle:
make UIView in UIScrollView stick to the top when scrolled up
Is it possible to add fixed content to a UIScrollView?
Make static UIView sticky when UIScrollView is scrolling

Nested Scroll view vs Table View or something else for this requirement

I have a requirement in which I need to have the following functionality -
1)I have a custom segmented control. In order to implement paging to the segmented control I have used horizontal scroll view. Each page has its own vertical scroll view.
Requirement
1)The image should hide as user scrolls up in the respective pages and should show down when user scrolls down in respective pages but keeping the custom segment always at the top of the screen when image is hidden irrespective of the individual page selection-
What I have tried so far -
1st Method
I tried putting the image as header of a table view.
Created a single section with one cell & gave the section header as the custom segment. And in the cell I placed the horizontal scroll view with the cell's height adjusted to cover all portion left out of the superview but it didn't work out as when I scroll the vertical scrolling of individual pages it was not in sync with the table view.
2nd Method
I tried setting the segment initially with a fixed distance from the top & I increased & decreased the constraint inside scrollViewDidScroll(). But it too didn't work as when the user scrolled rapidly ,the changing of constraint value didn't follow correctly.
So is there any other way to achieve the same ?
Please suggest as I can't make out what to do?
You add a tableView and your UIImage on top of it inside a scrollView. The tableView must have the same height & width than your scrollView. Then you disable the pan gesture of the scrollView :
self.scrollView.panGesture.active = false
Then you have to implement a custom scroll in scrollViewDidScroll' of yourtableView`'s delegate:
func scrollViewDidScroll(scrollView: UIScrollView) {
if self.scrollView.contentOffset.y <= 100 {
self.scrollView.contentOffset.y += scrollView.contentOffset.y
self.tableView.contentOffset.y = 0
} else {
// let the tableView scroll normally
}
}
Or, you can have a try with https://github.com/bryankeller/BLKFlexibleHeightBar ;)
It's a great component that can handle many type on animation in the header based on the position of a scrollView.

How to maintain a minimum height of content size of UIScrollView?

I have a UIScrollView A (in fact a UICollectionView) filling the screen inside a UINavigationController B. The controller B's adjustScrollViewInsets is set to true.
I want to hide the navigation bar when user scrolls up, and show it when down. Following is my code:
func scrollViewDidScroll(scrollView: UIScrollView) {
if (self.lastContentOffset < scrollView.contentSize.height - scrollView.frame.size.height && self.lastContentOffset > scrollView.contentOffset.y) {
// dragging down
if self.navigationController!.navigationBarHidden {
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
} else if (self.lastContentOffset > 0 && self.lastContentOffset < scrollView.contentOffset.y) {
// dragging up
if !self.navigationController!.navigationBarHidden {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
}
self.lastContentOffset = scrollView.contentOffset.y
}
Now the problem is, since the screen of iPhone 6+ is too large, the contentSize of the scroll view A is smaller than its frame(i.e. the full screen frame) when the navigation bar is hidden. In such circumstance, the scroll view will not be scrollable, and the navigation bar will never be back again.
I want to manually maintain the height of the contentSize of A to screen at least height + 1, but don't know how to do this. Could anyone help? Or provide a better solution?
BTW, I am using iOS 8 and Swift.
Lets say you need to keep the minimum content size of scroll view to 100(of course this will be dynamic and vary according to device)
NSInteger minScrollViewContentHeight = 100;
After populating the scroll view with content, you need to check if the scroll view's content size is less than minimum required scroll views content size. If its lesser than the required content size than you need to set the minimum content size of the scroll view as follows -
if(scrollView.contentSize.height < minScrollViewContentHeight)
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, minScrollViewContentHeight)];
Off the top of my head (I'm on a phone), contentSize is not read-only I think.
How about changing it manually to the desired amount depending on the circumstances of scrolling direction etc?
Something like:
IF navbar is hidden THEN contentSize = whatever
An option would be to use the appearance and disappearance of cells to trigger the show/hide.
Use the delegate methods collectionView:willDisplayCell:forItemAtIndexPath: and collectionView:didEndDisplayingCell:forItemAtIndexPath: to detect movement. You can work out the direction from the index change of the cells being shown or removed. If you cannot scroll off screen then nothing happens.
You have to change no offset (which is actually just scrolling position), but contentSize itself. That means, that when you hide navigation bar, increase contentSize by navigation height (don't remember numbers) and when you show navigation bar, decrease contentSize. Or... Use AutoLayout and layoutIfNeeded method after showing/hiding navigation bar.
I stumbled upon a similar problem. I needed a minimum scrollable area for a tableview i was using.
ScrollView might be a bit easier since you can directly modify the contentView size.
If you're using autoLayout, try adding equal heights constraint between the contentView and the scrollView itself. Something along the lines of contentView.height = scrollView.height + scrollMin;
For my tableView i had to subclass UITableView and override the contentSize setter.
#define MIN_SCROLL 60
- (void)setContentSize:(CGSize)contentSize {
//take insets into account
UIEdgeInsets insets = self.contentInset;
CGFloat minHeight = self.frame.size.height - insets.top - insets.bottom + MIN_SCROLL;
if(contentSize.height < minHeight) {
contentSize.height = minHeight;
}
[super setContentSize:contentSize];
}

Resources