포커스에 따라 위아래로 움직이는 Sticky 섹션 헤더 구현
이것을 구현하고 싶습니다. 게다가 어차피라면 여러 섹션 있는 경우에는 Sticky인 헤더를 실현하고 싶네요.
라이브러리가 있을까라고 생각하면 의외로 횡방향이 없었기 때문에, UICollectionView의 커스텀 Layout로서 만들었습니다.
iOS에도 대응하고 있습니다.
toshi0383/HorizontalStickyHeaderLayout
먼저 제공되는 다음 6개의 delegate를 구현합니다. 각 셀과 헤더의 크기와 여백을 지정합니다.
@objc
public protocol HorizontalStickyHeaderLayoutDelegate: class {
func collectionView(_ collectionView: UICollectionView, hshlSizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
func collectionView(_ collectionView: UICollectionView, hshlSectionInsetsAtSection section: Int) -> UIEdgeInsets
func collectionView(_ collectionView: UICollectionView, hshlMinSpacingForCellsAtSection section: Int) -> CGFloat
func collectionView(_ collectionView: UICollectionView, hshlSizeForHeaderAtSection section: Int) -> CGSize
func collectionView(_ collectionView: UICollectionView, hshlHeaderInsetsAtSection section: Int) -> UIEdgeInsets
@objc optional func collectionView(_ collectionView: UICollectionView, hshlDidUpdatePoppingHeaderIndexPaths indexPaths: [IndexPath])
}
포커스로 위아래로 움직이는 애니메이션은 스스로 구현합니다.
왜냐하면, 커스텀 레이아웃내에서 레이아웃 처리를 하고 있는 뷰의 좌표를 바꾸면 화나기 때문입니다. 즉, 아래와 같이 헤더 뷰의 subview를 애니메이션 시킬 필요가 있습니다.
애니메이션 시키는 타이밍에 대해서는 hshlDidUpdatePoppingHeaderIndexPaths
의 delegate 로 통지됩니다만, 레이아웃측은 포커스의 갱신을 검지할 필요가 없기 때문에, didUpdateFocus
의 타이밍에서도 재계산시켜 애니메이션 시키면 됩니다.
// Popping Header
func collectionView(_ collectionView: UICollectionView, hshlDidUpdatePoppingHeaderIndexPaths indexPaths: [IndexPath]) {
let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths)
UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: {
unpop.forEach { $0.unpopHeader() }
pop.forEach { $0.popHeader() }
}, completion: nil)
}
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
layout.updatePoppingHeaderIndexPaths()
let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths)
UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: {
unpop.forEach { $0.unpopHeader() }
}, completion: nil)
coordinator.addCoordinatedAnimations({
pop.forEach { $0.popHeader() }
}, completion: nil)
super.didUpdateFocus(in: context, with: coordinator)
}
private func getHeaders(poppingHeadersIndexPaths indexPaths: [IndexPath]) -> (pop: [HeaderView], unpop: [HeaderView]) {
var visible = collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader)
var pop: [HeaderView] = []
for indexPath in indexPaths {
guard let view = collectionView.supplementaryView(forElementKind: UICollectionElementKindSectionHeader, at: indexPath) else {
continue
}
if let index = visible.index(of: view) {
visible.remove(at: index)
}
if let header = view as? HeaderView {
pop.append(header)
}
}
return (pop: pop, unpop: visible.flatMap { $0 as? HeaderView })
}
popHeader()
unpopHeader()
중에서는 HeaderView의 subview의 좌표를 바꾸고 있습니다.
이제 포커스에 따라 위아래로 움직이는 섹션 헤더를 구현할 수있었습니다. 여러 섹션의 경우의 Sticky적인 거동은 아무것도 하지 않아도 실현되고 있습니다.
요약
포커스에 맞추어 상하로 움직이는 Sticky인 섹션 헤더를 구현해 보았습니다.
htps : // 기주 b. 코 m / 0383
처음에는 레이아웃 측에서 헤더의 좌표를 바꾸어 collectionView.layoutIfNeeded()
를 애니메이션 블록에 넣는다는 접근이었습니다만, 셀마다 표시되지 않게 되는 문제가 있거나 했기 때문에 위와 같은 구현에 침착하고 있습니다.
tvOS 앱을 개발할 기회가 있으면 거의 반드시 이런 레이아웃은 한다고 생각하므로, 꼭 도입해 보세요.
Reference
이 문제에 관하여(포커스에 따라 위아래로 움직이는 Sticky 섹션 헤더 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/toshi0383/items/cb9e4b262a6a5964fa40
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
@objc
public protocol HorizontalStickyHeaderLayoutDelegate: class {
func collectionView(_ collectionView: UICollectionView, hshlSizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
func collectionView(_ collectionView: UICollectionView, hshlSectionInsetsAtSection section: Int) -> UIEdgeInsets
func collectionView(_ collectionView: UICollectionView, hshlMinSpacingForCellsAtSection section: Int) -> CGFloat
func collectionView(_ collectionView: UICollectionView, hshlSizeForHeaderAtSection section: Int) -> CGSize
func collectionView(_ collectionView: UICollectionView, hshlHeaderInsetsAtSection section: Int) -> UIEdgeInsets
@objc optional func collectionView(_ collectionView: UICollectionView, hshlDidUpdatePoppingHeaderIndexPaths indexPaths: [IndexPath])
}
// Popping Header
func collectionView(_ collectionView: UICollectionView, hshlDidUpdatePoppingHeaderIndexPaths indexPaths: [IndexPath]) {
let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths)
UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: {
unpop.forEach { $0.unpopHeader() }
pop.forEach { $0.popHeader() }
}, completion: nil)
}
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
layout.updatePoppingHeaderIndexPaths()
let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths)
UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: {
unpop.forEach { $0.unpopHeader() }
}, completion: nil)
coordinator.addCoordinatedAnimations({
pop.forEach { $0.popHeader() }
}, completion: nil)
super.didUpdateFocus(in: context, with: coordinator)
}
private func getHeaders(poppingHeadersIndexPaths indexPaths: [IndexPath]) -> (pop: [HeaderView], unpop: [HeaderView]) {
var visible = collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader)
var pop: [HeaderView] = []
for indexPath in indexPaths {
guard let view = collectionView.supplementaryView(forElementKind: UICollectionElementKindSectionHeader, at: indexPath) else {
continue
}
if let index = visible.index(of: view) {
visible.remove(at: index)
}
if let header = view as? HeaderView {
pop.append(header)
}
}
return (pop: pop, unpop: visible.flatMap { $0 as? HeaderView })
}
포커스에 맞추어 상하로 움직이는 Sticky인 섹션 헤더를 구현해 보았습니다.
htps : // 기주 b. 코 m / 0383
처음에는 레이아웃 측에서 헤더의 좌표를 바꾸어
collectionView.layoutIfNeeded()
를 애니메이션 블록에 넣는다는 접근이었습니다만, 셀마다 표시되지 않게 되는 문제가 있거나 했기 때문에 위와 같은 구현에 침착하고 있습니다.tvOS 앱을 개발할 기회가 있으면 거의 반드시 이런 레이아웃은 한다고 생각하므로, 꼭 도입해 보세요.
Reference
이 문제에 관하여(포커스에 따라 위아래로 움직이는 Sticky 섹션 헤더 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/toshi0383/items/cb9e4b262a6a5964fa40텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)