Images are not setting properly to the collectionview cell - uicollectionview

I am using a collection view and it contains an imageview. Images are in url format so I have written a function to convert the url into Image but images are not looking properly.
I have tried all the modes like aspect fit, aspect fill, scale to fill.
I have searched a lot on the internet but not come up with answer.
This is my code :
extension HomeDemoViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bannerArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeAddCollectionViewCell", for: indexPath)
as! HomeAddCollectionViewCell
cell.imageview.setImageFromURl(stringImageUrl: imageArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
self.navigationController!.pushViewController(vc, animated: true)
}
}
func setImageFromURl(stringImageUrl url: String){
if let url = NSURL(string: url) {
DispatchQueue.global(qos: .default).async{
if let data = NSData(contentsOf: url as URL) {
DispatchQueue.main.async {
self.image = UIImage(data: data as Data)
}
}
}
}
}

Describe your problem please, attach screenshot what’s wrong.
Seems like the problem is in the image, try setting the different content mode and if needed — clipsToBounds = true

Related

Select first Item in CollectionView Swift4

I'm trying to select the first Item in CollectionView when the Collectionview loads. I found many solutions for Swift 3 but nothing of that worked for me in Swift4. What I tried(viewDidAppear):
import UIKit
import SDWebImage
class PostsTab_Details: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var PostsSelectRarityCollectionView: UICollectionView!
#IBOutlet weak var RarityTypeLbl: UILabel!
//Center my Collectionview Horizontal
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let totalCellWidth = 100 * (selectedPosts?.rarity.count)!
let totalSpacingWidth = 10 * (3 - 1)
let leftInset = (PostsSelectRarityCollectionView.frame.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (selectedPosts?.rarity.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = PostsSelectRarityCollectionView.dequeueReusableCell(withReuseIdentifier: "PostssTab_DetailCollectionCell", for: indexPath) as! PostsTab_DetailsCollectionViewCell
cell.PostssTab_DetailCollectionImage.sd_setImage(with: URL(string: (selectedPosts?.PostsImageURL)!))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
RarityTypeLbl.text = selectedPosts?.rarity[indexPath.row].rarity
}
//Tried this also with IndexPath(item: 0, section: 0)
override func viewDidAppear(_ animated: Bool) {
let selectedIndexPath = IndexPath(row: 0, section: 0)
PostsSelectRarityCollectionView.selectItem(at: selectedIndexPath, animated: true, scrollPosition: .right)
}
var selectedPosts: Posts?
override func viewDidLoad() {
PostsSelectRarityCollectionView.delegate = self
PostsSelectRarityCollectionView.dataSource = self
}
}
But this is not working... I hope someone knows what I'm doing wrong..
Thanks in advance
Update:
This worked for me now, thanks to Razib's answer:
override func viewWillAppear(_ animated: Bool) {
self.collectionView(PostsSelectRarityCollectionView, didSelectItemAt: IndexPath(row: 0, section: 0))
}
Your code seems okay to me. If you like to trigger the didSelectItemAt method, use the following code.
override func viewDidAppear(_ animated: Bool) {
self.PostsSelectRarityCollectionView(self.PostsSelectRarityCollectionView, didSelectItemAt: IndexPath(row: 0, section: 0))
}
To programmatically select the first Item in CollectionViewCell when the Collectionview loads you should code in viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
let indexPath:IndexPath = IndexPath(row: 0, section: 0)
collectionView?.selectItem(at: indexPath, animated: false, scrollPosition: .top)
}
Try this (Swift 5):
let indexPath:IndexPath = IndexPath(row: 0, section: 0)
collectionView?.selectItem(at: indexPath, animated: false, scrollPosition: .top)

Collection view cell not appear after resize the CollectionView height

I am facing the UICollectionView cell size issue. I am using two collection_view and one table_view 1:- Main CollectionView ,which is use for swipe and only display one cell at one time 2:- Inside Main Collection_View, i use table_view and now further inside table_view I am using Collection view which display 6 cell at one time.
Now the whole process is I am using a layout which is swipable and display 6 item at one page and so on.
The problem is when I set main cell height 200 then inside collectionview cell not appearing as expected.
Outer CollectionView Class
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionMain: UICollectionView!
#IBOutlet weak var tableView: UITableView!
let itemsPerRow: CGFloat = 1
let sectionInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate {
//1
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//2
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 3
}
//3
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:cellCollectionCollectionViewCell! = collectionView.dequeueReusableCell(withReuseIdentifier: "cellSwipe",
for: indexPath) as! cellCollectionCollectionViewCell
switch indexPath.item {
case 0:
cell.backgroundColor = UIColor.black
cell.setupCollectionTableCell(indexPath)
break
case 1: cell.backgroundColor = UIColor.red
cell.setupCollectionTableCell(indexPath)
break
default:
cell.backgroundColor = UIColor.yellow
cell.setupCollectionTableCell(indexPath)
break
}
// Configure the cell
return cell
}
}
extension ViewController : UICollectionViewDelegateFlowLayout {
//1
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
//2
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = self.collectionMain.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
//3
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
// 4
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
Model Constant class
import UIKit
class Constant {
static let totalItem: CGFloat = 9
static let column: CGFloat = 3
static let minLineSpacing: CGFloat = 1.0
static let minItemSpacing: CGFloat = 1.0
static let offset: CGFloat = 1.0 // TODO: for each side, define its offset
static func getItemWidth(boundWidth: CGFloat) -> CGFloat {
let totalWidth = boundWidth - (offset + offset) - ((column - 1) * minItemSpacing)
return totalWidth / column
}
}
Table Cell Class
import UIKit
class CollectionCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.sectionInset = UIEdgeInsetsMake(
Constant.offset, // top
Constant.offset, // left
Constant.offset, // bottom
Constant.offset // right
)
layout.minimumInteritemSpacing = Constant.minItemSpacing
layout.minimumLineSpacing = Constant.minLineSpacing
}
collectionView.isScrollEnabled = false
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension CollectionCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Int(Constant.totalItem)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BoxCell", for: indexPath)
return cell
}
}
extension CollectionCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = Constant.getItemWidth(boundWidth: collectionView.bounds.size.width)
return CGSize(width: itemWidth, height: 50)
}
}
Main CollectionCell class
import UIKit
class cellCollectionCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var tblView: UITableView!
var indexPath:IndexPath?
func setupCollectionTableCell(_ row:IndexPath){
self.indexPath = row
self.tblView.delegate = self
self.tblView.dataSource = self
// self.tblView.estimatedRowHeight = 300
self.tblView.reloadData()
}
}
extension cellCollectionCollectionViewCell:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
return 50
case 1:
let itemHeight = Constant.getItemWidth(boundWidth: tableView.bounds.size.width)
let totalRow = ceil(Constant.totalItem / Constant.column)
let totalTopBottomOffset = Constant.offset + Constant.offset
let totalSpacing = CGFloat(totalRow - 1) * Constant.minLineSpacing
let totalHeight = ((itemHeight * CGFloat(totalRow)) + totalTopBottomOffset + totalSpacing)
print("total height \(totalHeight)")
return totalHeight
default:
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// switch indexPath.row {
// case 0:
// let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath)
// return cell
// default:
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
// return cell
// }
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
}
When I set height of Main Collection view 200
Bellow are the link of images
When I set height 300, working fine

Swift iOS- How to Add Button to the outside a CollectionView Cell

I want to get a deleteButton that is a delete image to sit on the outside of a collectionViewCell (it can be partially inside).
I looked at other SO answers and they said just play with the button's frame's Rect's x & y values which I did. When I set the x & y values to 0,0 I get:
class CustomCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
var deleteButton: UIButton!
var deleteButtonImg: UIImage!
override func awakeFromNib() {
super.awakeFromNib()
deleteButton = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width/4, height: frame.size.width/4))
deleteButtonImg = UIImage(named: "delete-icon")!.withRenderingMode(.alwaysTemplate)
deleteButton.setImage(deleteButtonImg, for: .normal)
deleteButton.tintColor = UIColor.red
contentView.addSubview(deleteButton)
}
When I try to set the the Rect's x & y to -10,-10 the deleteButton gets clipped inside the cell's imageView. I don't have clipsToBounds set.
deleteButton = UIButton(frame: CGRect(x: -10, y: -10, width: frame.size.width/4, height: frame.size.width/4))
I even tried setting clipToBounds to false but I get the same effect as pic # 3.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.imageView.image = myImageArray[indexPath.row]
cell.imageView.clipsToBounds = false
return cell
}
Where am I going wrong?
The problem was inside storyboard I had a:
CollectionView
-CustomCell (type collectionViewCell)
-imageView
Under the Attributes Inspector, in the Drawing section, all 3 of these have the property clipsToBounds.
I overlooked the fact that I had clipsToBounds set to false (unchecked) on the imageView but set to true (checked) on the CustomCell and the CollectionView.
If anyone else has this problem make sure you uncheck clipsToBounds on the collectionView, collectionViewCell, and the imageView.
okay u can do like below, first create a xib file and replace default view with collection view cell and set up like below,
in the above image set the class name to CustomCell (In my case) and place image view (green ) and button (blue).
and in View controller,
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//register the nib to collectionview
self.aColectionView.register(UINib(nibName: "CustomCell", bundle: nil), forCellWithReuseIdentifier: "CUSTOM_CELL")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 40
}
//cell creation as u are doing
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:CustomCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CUSTOM_CELL", for: indexPath) as! CustomCell
//set the image for custom cell
return cell
}
//return the required size
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 200, height: 150)
}
and output like below,
and in custom cell class, u add any other features like action for a button and other views related code
class CustomCell:UICollectionViewCell {
#IBOutlet weak var deleteButton: UIButton!
#IBOutlet weak var imageView: UIImageView!
//other view related code
}

UICollectionView cell needs to be tapped twice for segue to happen

I know this will be something simple; however, I have created a UICollectionView that displays just some colours for now. When a cell is tapped I want it to perform a segue with the cell number that was tapped.
At the moment, if I tap a cell nothing happens. If I touch the same cell again nothing happens, but if I touch any other cell the segue occurs successfully and the cell clicked gets passed on, albeit with the first cells touched number.
It is in a navigation stack. Here is my code:
//Everything Collection View
//header text
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "SectionHeader", for: indexPath as IndexPath) as! SectionHeaderPractice
header.headerLabel.text = "SELECT A TOPIC..."
return header
}
//number of cells
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
//height and width of cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellWidth = (view.frame.width/2)-20
let cellHeight = view.frame.height/4
return CGSize(width: cellWidth, height: cellHeight)
}
//cell content
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let content = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
//set text
let desc = content.viewWithTag(3) as! UILabel
desc.text = shieldTextArray[(indexPath as NSIndexPath).row]
//set color scale
let score = scoreArray[(indexPath as NSIndexPath).row]
let redC = 2*score
let greenC = 2*(1-score)
content.backgroundColor = UIColor.init(red: CGFloat(redC), green: CGFloat(greenC), blue: 0.45, alpha: 1)
return content
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
//sets variable to clicked cell
//cellClicked = indexPath.row
//changes background colour on clicking
//let content1 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
//content1.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 1)
//Performs segue
//print(cellClicked)
performSegue(withIdentifier: "practiceSegue", sender: self)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(10,10,10,10)
}
//End Everything Collection View
Any pointers appreciated.
Your issue is with this line didDeselectItemAt, make sure you use didSelectItemAt.
didDeselectItemAt is the reason why you have to tap twice for segue, you select the cell then deselect the cell, once the cell is deselected, your code perform segue.

hidesBarsOnSwipe never shows navbar again when scrolling up

So I want to hide the navbar when scrolling down and bring it back when scrolling up. Hiding it works perfectly with
self.navigationController?.hidesBarsOnSwipe = true
But I expect it to be shown again when scrolling up. I made a test project where the view controller just has a single UICollectionView that covers the whole screen. Then showing the navbar is shown again as expected until I add this line to the viewDidLoad (adding cells to the collection view):
self.collectionView.delegate = self
And this is what the whole view controller looks like
class ViewController: UIViewController,UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Test")
self.navigationController?.hidesBarsOnSwipe = true
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCellWithReuseIdentifier("Test", forIndexPath: indexPath) as UICollectionViewCell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(300, 300)
}
}
So why does showing the navbar stop working when I add cells to my collection view?
I had the same problem but with a web view.
The problem was that the top constraint of the web view was "Top Layout Guide.Top" , after changing the top constraint to "Superview.Top" the problem was solved.
To expand on Oleg's answer...
If you are using Interface Builder to set a constraint to a view controller's primary view, Xcode defaults to showing options to set the vertical constraint against the top layout guide. However, if you press 'Option', you will see an alternate set of constraints. The constraint for 'Top Space to Container' is what you're looking for.
I had same issue. When I added the code for hiding status bar along with navigation bar, it worked.
- (BOOL)prefersStatusBarHidden {
return self.navigationController.isNavigationBarHidden;
}
I tried setting hidesBarsOnSwipe property to true in my ViewController class in ViewDidLoad function as given below, but it didn't work in handling hiding the navigation bar on swipe-up and unhiding the navigation bar on swipe-down.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.hidesBarsOnSwipe = true
}
}
Setting hidesBarsOnSwipe to true will have effect only if we are using the UITableViewController or UICollectionViewController as main screens, hidesBarsOnSwipe will not work if we have added a UITableView to the UIViewController for displaying the list of data.
Solution
class TestTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.hidesBarsOnSwipe = true
}
}
Hope this answer might help...!
I filed a bug report with Apple and ended up using AMScrollingNavbar instead which works really well and is easy to setup.
As per previous comments - this seems like a bug as of ios 10.3
as you are using a uicollectionview - I draw your attention to some code I re-wrote from APDynamicHeaderTableViewController
https://github.com/aaronpang/APDynamicHeaderTableViewController/issues/4
It's using snapkit https://github.com/SnapKit/SnapKit
(Apologies to all the IB + NSLayout Constraint lovers.)
class APDynamicHeaderTableViewController : UIViewController {
var largeWideSize = CGSize(width: UIScreen.main.bounds.width , height: 285 )
let headerView = APDynamicHeaderView () // Change your header view here
let cellLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
var feedCV:UICollectionView!
fileprivate var headerViewHeight:CGFloat = 80 // this will be updated by scrolling
fileprivate var headerBeganCollapsed = false
fileprivate var collapsedHeaderViewHeight : CGFloat = UIApplication.shared.statusBarFrame.height
fileprivate var expandedHeaderViewHeight : CGFloat = 100
fileprivate var headerExpandDelay : CGFloat = 100
fileprivate var tableViewScrollOffsetBeginDraggingY : CGFloat = 0.0
init(collapsedHeaderViewHeight : CGFloat, expandedHeaderViewHeight : CGFloat, headerExpandDelay :CGFloat) {
self.collapsedHeaderViewHeight = collapsedHeaderViewHeight
self.expandedHeaderViewHeight = expandedHeaderViewHeight
self.headerExpandDelay = headerExpandDelay
super.init(nibName: nil, bundle: nil)
}
init () {
super.init(nibName: nil, bundle: nil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
self.view.backgroundColor = .green
// Cell Layout Sizes
cellLayout.scrollDirection = .vertical
cellLayout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
cellLayout.itemSize = CGSize(width: UIScreen.main.bounds.width, height: 185 + 80)
// Header view
self.view.addSubview(headerView)
headerView.snp.remakeConstraints { (make) -> Void in
make.top.left.equalToSuperview()
make.width.equalToSuperview()
make.height.equalTo(headerViewHeight)
}
// CollectionView
feedCV = UICollectionView(frame: .zero, collectionViewLayout: cellLayout)
self.view.addSubview(feedCV)
self.feedCV.snp.remakeConstraints { (make) -> Void in
make.top.equalTo(headerView.snp.bottom) // this is pegged to the header view which is going to grow in height
make.left.equalToSuperview()
make.width.equalToSuperview()
make.bottom.equalToSuperview()
}
feedCV.backgroundColor = .red
feedCV.showsVerticalScrollIndicator = true
feedCV.isScrollEnabled = true
feedCV.bounces = true
feedCV.delegate = self
feedCV.dataSource = self
// YOUR COLLECTIONVIEW CELL HERE!!!!!
feedCV.register(VideoCollectionViewCell.self, forCellWithReuseIdentifier: VideoCollectionViewCell.ID)
}
// Animate the header view to collapsed or expanded if it is dragged only partially
func animateHeaderViewHeight () -> Void {
Logger.verbose("animateHeaderViewHeight")
var headerViewHeightDestinationConstant : CGFloat = 0.0
if (headerViewHeight < ((expandedHeaderViewHeight - collapsedHeaderViewHeight) / 2.0 + collapsedHeaderViewHeight)) {
headerViewHeightDestinationConstant = collapsedHeaderViewHeight
} else {
headerViewHeightDestinationConstant = expandedHeaderViewHeight
}
if (headerViewHeight != expandedHeaderViewHeight && headerViewHeight != collapsedHeaderViewHeight) {
let animationDuration = 0.25
UIView.animate(withDuration: animationDuration, animations: { () -> Void in
self.headerViewHeight = headerViewHeightDestinationConstant
let progress = (self.headerViewHeight - self.collapsedHeaderViewHeight) / (self.expandedHeaderViewHeight - self.collapsedHeaderViewHeight)
self.headerView.expandToProgress(progress)
self.view.layoutIfNeeded()
})
}
}
}
extension APDynamicHeaderTableViewController : UICollectionViewDelegate {
}
extension APDynamicHeaderTableViewController : UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
// Clamp the beginning point to 0 and the max content offset to prevent unintentional resizing when dragging during rubber banding
tableViewScrollOffsetBeginDraggingY = min(max(scrollView.contentOffset.y, 0), scrollView.contentSize.height - scrollView.frame.size.height)
// Keep track of whether or not the header was collapsed to determine if we can add the delay of expansion
headerBeganCollapsed = (headerViewHeight == collapsedHeaderViewHeight)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Do nothing if the table view is not scrollable
if feedCV.contentSize.height < feedCV.bounds.height {
return
}
var contentOffsetY = feedCV.contentOffset.y - tableViewScrollOffsetBeginDraggingY
// Add a delay to expanding the header only if the user began scrolling below the allotted amount of space to actually expand the header with no delay (e.g. If it takes 30 pixels to scroll up the scrollview to expand the header then don't add the delay of the user started scrolling at 10 pixels)
if tableViewScrollOffsetBeginDraggingY > ((expandedHeaderViewHeight - collapsedHeaderViewHeight) + headerExpandDelay) && contentOffsetY < 0 && headerBeganCollapsed {
contentOffsetY = contentOffsetY + headerExpandDelay
}
// Calculate how much the header height will change so we can readjust the table view's content offset so it doesn't scroll while we change the height of the header
let changeInHeaderViewHeight = headerViewHeight - min(max(headerViewHeight - contentOffsetY, collapsedHeaderViewHeight), expandedHeaderViewHeight)
headerViewHeight = min(max(headerViewHeight - contentOffsetY, collapsedHeaderViewHeight), expandedHeaderViewHeight)
let progress = (headerViewHeight - collapsedHeaderViewHeight) / (expandedHeaderViewHeight - collapsedHeaderViewHeight)
// Logger.verbose("headerViewHeight:",headerViewHeight)
headerView.expandToProgress(progress)
headerView.snp.updateConstraints { (make) -> Void in
make.height.equalTo(headerViewHeight)
}
// When the header view height is changing, freeze the content in the table view
if headerViewHeight != collapsedHeaderViewHeight && headerViewHeight != expandedHeaderViewHeight {
feedCV.contentOffset = CGPoint(x: 0, y: feedCV.contentOffset.y - changeInHeaderViewHeight)
}
}
// Animate the header view when the user ends dragging or flicks the scroll view
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
animateHeaderViewHeight()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
animateHeaderViewHeight()
}
}
extension APDynamicHeaderTableViewController : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: VideoCollectionViewCell.ID, for: indexPath) as! VideoCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return largeWideSize
}
}
To make hidesBarsOnSwipe working properly, your view controller's view must contain only UITableView instance and nothing else.