Swift: change tableview height on scroll

10,335

Solution 1

I haven't tested it but you can do this. Use Autolayout in this view. it will work better with that.

Set the tableview constraint as Top, Left, Bottom, Right => 0, 0, 0, 0 with the main view and put collectionView under the tableview with constraint as Top,Left,Right, height => 0, 0, 0, x with the main view.

Note: Tableview is on top of the collectionView.

Connect your height constraint outlet of CollectionView and also define your defaultOffset variable

@IBOutlet weak var defaultHeightConstraint: NSLayoutConstraint
var defaultOffSet: CGPoint?

In viewDidLoad,

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.contentInset = UIEdgeInsetsMake(collectionView.size.height, 0, 0, 0)
}

In viewDidAppear, write

override func viewDidAppear(_ animated: Bool) {
    defaultOffSet = tableView.contentOffset
}

In ViewDidScroll

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset = tableView.contentOffset

    if let startOffset = self.defaultOffSet {
        if offset.y < startOffset.y {
            // Scrolling down
            // check if your collection view height is less than normal height, do your logic.


            let deltaY = fabs((startOffset.y - offset.y))
            defaultHeightConstraint.constant = defaultHeightConstraint.constant - deltaY

        } else {
            // Scrolling up
            let deltaY = fabs((startOffset.y - offset.y))
            defaultHeightConstraint.constant = defaultHeightConstraint.constant + deltaY
        }

        self.view.layoutIfNeeded()
    }
}

Hope it helps.

Solution 2

Since UITableView is a subclass of UIScrollView, your table view's delegate can receive UIScrollViewDelegate methods. You don't need to use PanGesture

First implement UITableviewDelegate and in that

  var oldContentOffset = CGPoint.zero

  func scrollViewDidScroll(_ scrollView: UIScrollView) {

    let contentOffset =  scrollView.contentOffset.y - oldContentOffset.y

    if (self.oldContentOffset < scrollView.contentOffset.y) {
    // moved to top

    } else if (self.oldContentOffset > scrollView.contentOffset.y) {
        // moved to bottom
    } else {
        // didn't move
    }
        oldContentOffset = scrollView.contentOffset
   }

Here you can write you logic to change constant value of your constraint

UPDATE/EDIT

Another thing is don't use multiplier for tabelview height.with collection view it is fine you can give height constraint with self.view in ratio of 1/3 . for tableview just give leading ,trailing top (UICollectionView) and bottom. So when you change height constant of UICollectionView Tableview height automatically decrease and vice-versa for decrease.

You can not change the multiplier from the outlet as it is read only. so you have to constant value to self.view.frame.height / 3 will work for you

Hope it is helpful to you

Share:
10,335
Aryan Sharma
Author by

Aryan Sharma

Been writing code since '07. Started from VB now I'm here(Swift). Love to make apps with a superb UX. Love for animations. A firm believer of the fact that 'Looks Matter'. A beautifully designed app will surely sell. Proficiency in iOS Development. Good understanding of Firebase, Google Cloud functions(NodeJS). Handled complete technology wing of a startup for more than 10 months. From backend to frontend, handled everything. Now working as the Lead Engineer at Smartsense.

Updated on June 04, 2022

Comments

  • Aryan Sharma
    Aryan Sharma almost 2 years

    I have a VC as shown in the imageenter image description here

    It has a UICollectionView on top, and a UITableView at the bottom. CollectionView has 1:3 of the screen and TableView has 2:3 of the screen(set using equalHeight constraint).

    I want to change the height of the UICollectionView when the tableView is scrolled.

    When the tableView is scrolled up,I want to change the multiplier of equalHeights constraint to like 1:5 and 4:5 of collectionView and tableView respectively.This will ensure that height of tableView increases and collectionView decreases

    When the tableView is scrolled down, the multiplier of equalHeights constraint should reset to default.

    I've tried adding swipe and pan gestures to tableView, but they are unrecognised.

    How to achieve this functionality?

    P.S: Would love to achieve this functionality by using a pan gesture, so that dragging up and down changes the heights progressively.

    This is the view hierarchyenter image description here

    EDIT/UPDATE

    This is the code that I'm using.

    class MyConstant {
        var height:CGFloat = 10
    }
    
    let myConstant = MyConstant()
    

    MainScreenVC

    override func viewWillAppear(_ animated: Bool) {
        myConstant.height = self.view.frame.size.height
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if (self.lastContentOffset < scrollView.contentOffset.y) {
            NotificationCenter.default.post(name: Notifications.decreaseHeightNotification.name, object: nil)
            self.topViewConstraint.constant = -self.view.frame.height / 6
            UIView.animate(withDuration: 0.3, animations: {
                self.view.layoutIfNeeded()
            })
        } else if (self.lastContentOffset > scrollView.contentOffset.y) {
            NotificationCenter.default.post(name: Notifications.increaseHeightNotification.name, object: nil)
            self.topViewConstraint.constant = 0
            UIView.animate(withDuration: 0.3, animations: {
                self.view.layoutIfNeeded()
            })
        }
        self.lastContentOffset = scrollView.contentOffset.y
    }
    

    Cell.Swift

    override func awakeFromNib() {
        super.awakeFromNib()
    
        NotificationCenter.default.addObserver(self, selector: #selector(decreaseHeight), name: Notification.Name("decreaseHeightNotification"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(increaseHeight), name: Notification.Name("increaseHeightNotification"), object: nil)
    
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        heightConstraint.constant = (myConstant.height / 3) - 10
        widthConstraint.constant = heightConstraint.constant * 1.5
    }
    
    @objc func decreaseHeight() {
        heightConstraint.constant = (myConstant.height / 6) - 10
        widthConstraint.constant = (heightConstraint.constant * 1.5)
        self.layoutIfNeeded()
    }
    
    @objc func increaseHeight() {
        heightConstraint.constant = (myConstant.height / 3) - 10
        widthConstraint.constant = (heightConstraint.constant * 1.5)
        self.layoutIfNeeded()
    }
    

    Now when I scroll both simultaneously, the screen freezes. Also is there a better way of resizing the collectionViewCell size?

    • nothingwhatsoever
      nothingwhatsoever over 6 years
      Can you post your code snippet here? This question is incomplete without the approach you are using. Once that is available, you can expect relevant answers.
    • Aryan Sharma
      Aryan Sharma over 6 years
      @nothingwhatsoever check it out
    • Prashant Tukadiya
      Prashant Tukadiya over 6 years
      Why you are increasing height of your content view ?. it should be leading, trailing , top , bottom with cell so it will automatically increase height as per cell. after scroll on tableview instead of posting notification use collection view invalidate for this see this aplus.rs/2015/… .What are you doing in your height for item at Indexpath.
  • Aryan Sharma
    Aryan Sharma over 6 years
    So according to you, for collectionView: use multiplier with 1:3 value. For tableView: add top, bottom, left and right constraints. top being relative to collection view. On scroll: change only multiplier value so everything adjusts automatically?
  • Prashant Tukadiya
    Prashant Tukadiya over 6 years
    @AryanSharma yes !! , You just have to change height of collection view . since tableview top == collectionview.bottom so tableview automatically adjust as per collection view height changes !! . And you can not change multiplier value you have to change constat value :)