Tạo amination cho header table view
Bài đăng này đã không được cập nhật trong 3 năm
1. Bài toán đặt ra
Giả dụ ta muốn làm 1 cái header tableview khi scroll xuống thì 1 phần header sẽ được mở rộng ra để hiển thị thêm thông tin, khi scroll lên phần mở rộng đó sẽ được đóng lại để chúng ta có nhiểu không gian hơn hiển thị nội dung trong tableview.
2. Chọn cách giải quyết bài toán
Nhìn vào hình vẽ trên ta có thể hình dung lúc này header của chúng ta sẽ có 2 khu vực hiển thị data
- Data 1: là phần hiển thị khi chúng ta tiến hành scroll tableview từ dưới lên
- Data 2: khi scroll từ trên xuống thì khu vực này mới hiện ra còn nếu scroll từ dưới lên thì nó sẽ được ẩn đi
3. Thực hiện
3.1 Xây dựng UI storyboard
Trong file storyboard, ta kéo 1 view to chứa 2 view nhỏ chính là data 1 và data 2 lên trên tableview như hình vẽ. Tiếp đó ta kéo 2 constraint vào trong viewcontroller
- Contraint thứ nhất là chiều cao của view cha chứ cả 2 view con
- Constraint thứ hai là khoảng cách từ data 1 đến top layout
@IBOutlet weak var headerHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var titleTopConstraint: NSLayoutConstraint!
3.2 Xây dựng code
Để khi scroll xuống header của chúng ta sẽ mở rộng ra thêm chúng ta sẽ cần 1 hàm expandHeader(), khi scroll lên chúng ta sẽ thu gọn header tableview chúng ta viết hàm collapseHeader()
let maxHeaderHeight: CGFloat = 88
let minHeaderHeight: CGFloat = 44
func collapseHeader() {
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.2, animations: {
self.headerHeightConstraint.constant = self.minHeaderHeight
self.updateHeader()
self.view.layoutIfNeeded()
})
}
func expandHeader() {
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.2, animations: {
self.headerHeightConstraint.constant = self.maxHeaderHeight
self.updateHeader()
self.view.layoutIfNeeded()
})
}
func updateHeader() {
let range = self.maxHeaderHeight - self.minHeaderHeight
let openAmount = self.headerHeightConstraint.constant - self.minHeaderHeight
let percentage = openAmount / range
self.titleTopConstraint.constant = -openAmount + 10
self.logoImageView.alpha = percentage
}
Ở đây chúng ta có thêm hàm updateHeader(), hàm này có tác dụng update lại vị trí của vùng data 1 khi chúng ta scroll tableview lên hoặc xuống. Để việc scroll tableview tác dụng lên các constraint chúng ta cần dùng phương thức func scrollViewDidScroll(scrollView: UIScrollView)
func scrollViewDidScroll(scrollView: UIScrollView) {
let scrollDiff = scrollView.contentOffset.y - self.previousScrollOffset
let absoluteTop: CGFloat = 0;
let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height;
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom
// Tinh toan lai do cao cua header view
var newHeight = self.headerHeightConstraint.constant
if isScrollingDown {
newHeight = max(self.minHeaderHeight, self.headerHeightConstraint.constant - abs(scrollDiff))
} else if isScrollingUp {
newHeight = min(self.maxHeaderHeight, self.headerHeightConstraint.constant + abs(scrollDiff))
}
// Neu height khong giong nhau thi update
if newHeight != self.headerHeightConstraint.constant {
self.headerHeightConstraint.constant = newHeight
self.updateHeader()
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, position)
}
self.previousScrollOffset = scrollView.contentOffset.y
}
Ở đoạn code trên mỗi khi chúng ta scroll tableview, nó sẽ tính toán lại độ chênh lệch giữa contentOffset của tableview và vị trí trước đó để biết được chungs ta đang scroll tableview lên hay xuống
- chênh lệch contentOffset vị trí hiện tại so với vị trí trước đó > 0 và contentOffset tableview tăng -> scroll tableview down (xuống)
- chênh lệch contentOffset vị trí hiện tại so với vị trí trước đó < 0 và contentOffset tableview giảm -> scroll tableview up (lên)
3.2 Thêm animation
Nếu chỉ như vậy chúng ta sẽ thấy là khi scroll tableview mà không lên hết khoảng cần thiết thì header của chungs ta sẽ không che hết được hoặc không lên hết được phần data 2, để xóa bỏ lỗi này chungs ta cần thêm 2 phương thức của scroll view là
func scrollViewDidEndDecelerating(scrollView: UIScrollView)
và
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool)
chúng ta sẽ tính toán lại ở 2 phương thức này, nếu khoảng scroll không lên quá 1 nửa chiều cao của header chúng ta sẽ scroll ngược trở lại header view, còn nếu khoảng scroll đã lên hơn 1 nửa chiều cao của header view thì sẽ scroll hẳn lên trên.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
self.scrollViewDidStopScrolling()
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.scrollViewDidStopScrolling()
}
}
func scrollViewDidStopScrolling() {
let range = self.maxHeaderHeight - self.minHeaderHeight
let midPoint = self.minHeaderHeight + (range / 2)
if self.headerHeightConstraint.constant > midPoint {
self.expandHeader()
} else {
self.collapseHeader()
}
}
All rights reserved