[英]Snap to center of a cell when scrolling UICollectionView horizontally
[英]Align cell in center(horizontally) in UICollectionView
我第一次使用UICollectionView不知道如何做到這一點。 我正在嘗試為tvOS創建一個應用程序,並希望顯示像airbnb tvos app這樣的菜單。 我以某種方式嘗試實現特定格式didUpdateFocusInContext
但問題是關於第一次出現,因為第一次出現發生在默認點上,即0,0的集合視圖導致混亂。 繼承了我迄今為止所做的工作。
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as? ShowCell {
menuData = dataArray[indexPath.row] as! NSDictionary
cell.configureCell(menuData.objectForKey("name") as! String)
return cell
}
else {
return ShowCell()
}
}
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
if let previousItem = context.previouslyFocusedView as? ShowCell {
UIView.animateWithDuration(0.2, animations: { () -> Void in
previousItem.showImg.frame.size = self.originalCellSize
})
}
if let nextItem = context.nextFocusedView as? ShowCell {
UIView.animateWithDuration(0.2, animations: { () -> Void in
nextItem.showImg.frame = CGRectMake(
self.view.frame.width/2 - self.focusCellSize.width/2,
169.0,
self.focusCellSize.width,
self.focusCellSize.height)
})
}
}
這是我想要實現的視圖,我已經實現了它,但是后來的索引意味着1,2之后的索引
這是第一次出現時的起始行為,當我將控件移動到它時,它就像這樣發生
這就是我真正想要的,但我正在努力將我的專注單元格放到屏幕中間,同樣地,我的前一個和下一個單元格。 我知道我明確給出了幀坐標這是不正確的這只是我正在運行的測試用例而沒有其他但我找不到這樣做的方法
我將分別控制焦點和集合內容偏移(滾動位置)。
對於內容偏移,您應設置截面邊距和項目間間距,以便您有一個單元格居中,並且邊緣可見相鄰單元格。 您可以獲得此設置並進行測試而不顯示任何焦點。
當你滾動(焦點改變)時,可能很難讓物品准確地移動到中心。 為了解決這個問題,實現- scrollViewWillEndDragging:withVelocity:targetContentOffset:
找到在該項目targetContentOffset
並獲得其中心點(從布局屬性)。 有了它,您可以修改targetContentOffset
,使滾動與項目居中完全結束。
現在,重點應該由單元本身管理,而不是集合視圖。 下面是一個(稍大)細胞焦點變化動畫的例子。 它使用制圖來更改圖像視圖約束並將變換應用於標簽。 您可以執行類似的操作,具體取決於您希望圖像和標簽彼此交互的方式。
請注意,當UIImageView
具有焦點並且調整了adjustsImageWhenAncestorFocused
設置時,下面的代碼也會應用類似於apple提供的庫存的運動效果變換。 如果您不希望這樣,您可以簡化和縮短代碼。
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
if (context.nextFocusedView == self) {
UIView.animateWithDuration(0.1,
animations: { () -> Void in
self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) {
$0.top == $0.superview!.top
$0.bottom == $0.superview!.bottom
$0.leading == $0.superview!.leading
$0.trailing == $0.superview!.trailing
}
self.itemLabel.transform = CGAffineTransformMakeTranslation(0, 60)
self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0).CGColor
self.layer.shadowOpacity = 1
self.layoutIfNeeded()
}, completion: nil)
let minMaxAngle = 10.0
let m34 = CGFloat(1.0 / -1250)
let angle = CGFloat(minMaxAngle * M_PI / 180.0)
var baseTransform = CATransform3DIdentity
baseTransform.m34 = m34
let rotateXmin = CATransform3DRotate(baseTransform, -1 * angle, 1.0, 0.0, 0.0);
let rotateXmax = CATransform3DRotate(baseTransform, angle, 1.0, 0.0, 0.0);
let rotateYmin = CATransform3DRotate(baseTransform, angle, 0.0, 1.0, 0.0);
let rotateYmax = CATransform3DRotate(baseTransform, -1 * angle, 0.0, 1.0, 0.0);
let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform",
type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateXmin)
verticalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateXmax)
let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform",
type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateYmin)
horizontalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateYmax)
let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
self.addMotionEffect(group)
}
else {
UIView.animateWithDuration(0.3,
animations: { () -> Void in
self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) {
$0.top == $0.superview!.top + 20
$0.bottom == $0.superview!.bottom - 20
$0.leading == $0.superview!.leading + 20
$0.trailing == $0.superview!.trailing - 20
}
self.itemLabel.transform = CGAffineTransformIdentity
self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0.75).CGColor
self.layer.shadowOpacity = 0
self.layoutIfNeeded()
}, completion: nil)
for effect in self.motionEffects {
self.removeMotionEffect(effect)
}
}
}
@Wain已經提出了實現上述風格的指導方針,這是我對此的准確答案:
override func didUpdateFocusInContext(context: UIFocusUpdateContext,
withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
if let focusedView = context.nextFocusedView as? ShowCell {
collectionView.scrollEnabled = false
let indexPath = collectionView.indexPathForCell(focusedView)!
focusedView.showImg.frame.size = self.focusImageSize
focusedView.showLbl.frame.size = self.focusLabelSize
focusedView.showLbl.font = UIFont.systemFontOfSize(75)
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .CenteredHorizontally, animated: true)
self.collectionView.layoutIfNeeded()
}
else if let lastFocuedView = context.previouslyFocusedView as? ShowCell{
collectionView.scrollEnabled = true
// let indexPath = collectionView.indexPathForCell(lastFocuedView)!
lastFocuedView.showImg.frame.size = self.originalImageSize
lastFocuedView.showLbl.frame.size = self.originalLabelSize
lastFocuedView.showLbl.font = UIFont.systemFontOfSize(70)
self.collectionView.layoutIfNeeded()
}
對於你要給UIEdgeInsets的第一個和最后一個單元格(它是流程布局的委托方法)
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets{
return UIEdgeInsets(top: 0.0, left: self.collectionView.frame.width/2 , bottom: 0.0, right: self.collectionView.frame.width/2)
}
真誠地感謝Wain為這個問題提供了准確的指導。 干杯!
解決方案是覆蓋滾動視圖委托方法scrollViewWillEndDragging
https://stackoverflow.com/a/42117107/1587729(Swift 3)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.