啰嗦幾句
起初我是想把這個demo做的和原版一摸一樣钓猬,但在印象筆記的ipa中并沒有找到那些關(guān)鍵的圖片吹零,網(wǎng)上也沒有相關(guān)的素材屑迂,而且當(dāng)我在百度搜索里面赫然敲下印象筆記四個大字的時候拇颅,百度搜索竟然給我推薦印象筆記面臨倒閉這樣的關(guān)鍵字荧恍!好吧镰烧,在當(dāng)下新技術(shù)大潮一波接一波的年代拢军,這種被面臨倒閉的公司還有很多,但我個人感情上希望那一天能來的晚一些拌滋,反倒是些世界500強(qiáng),民族企業(yè)之類的朴沿,我由衷的希望他明天就關(guān)門。我也斗膽嘗試過用sketch畫出所有的切圖败砂,但當(dāng)我畫完一個?后就徹底放棄了這個想法赌渣,索性也就弄成現(xiàn)在這個樣子。
不夸張的說我半路轉(zhuǎn)來做ios和印象筆記這兩個交互效果是有很大關(guān)系的昌犹,在沒有作出這個demo之前坚芜,我對evernote的這兩個交互效果特別的著迷,而在我轉(zhuǎn)做ios之后斜姥,這種感覺反而更加強(qiáng)烈了鸿竖,因為憑我當(dāng)時那點淺薄的ios經(jīng)驗,完全不知道這個效果是怎么做到的铸敏,我也像瘋子一樣在各種code網(wǎng)站瘋狂掃蕩一遍也沒有找到相應(yīng)的demo缚忧,趁著這段時間比較閑就把它實現(xiàn)了。
彈簧效果:
使用collectionView杈笔,自定義布局繼承UICollectionViewFlowLayout闪水,想要這些cell按照我們的意思動起來,首先重寫shouldInvalidateLayoutFor
BoundsChange返回true蒙具。
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
這個動畫只在collectionview滑動到頂部和底部會觸發(fā)球榆,重寫layoutAttributesForElementsInRect這個方法根據(jù)collectionview的contentoffset計算出cell的frame,這樣就ok了禁筏。
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let offsetY = self.collectionView!.contentOffset.y
let attrsArray = super.layoutAttributesForElementsInRect(rect)
let collectionViewFrameHeight = self.collectionView!.frame.size.height;
let collectionViewContentHeight = self.collectionView!.contentSize.height;
let ScrollViewContentInsetBottom = self.collectionView!.contentInset.bottom;
let bottomOffset = offsetY + collectionViewFrameHeight - collectionViewContentHeight - ScrollViewContentInsetBottom
let numOfItems = self.collectionView!.numberOfSections()
for attr:UICollectionViewLayoutAttributes in attrsArray! {
if (attr.representedElementCategory == UICollectionElementCategory.Cell) {
var cellRect = attr.frame;
if offsetY <= 0 {
let distance = fabs(offsetY) / SpringFactor;
cellRect.origin.y += offsetY + distance * CGFloat(attr.indexPath.section + 1);
}else if bottomOffset > 0 {
let distance = bottomOffset / SpringFactor;
cellRect.origin.y += bottomOffset - distance *
CGFloat(numOfItems - attr.indexPath.section)
}
attr.frame = cellRect;
}
}
return attrsArray;
}
轉(zhuǎn)場效果:
自定義類EvernoteTransition
遵守UIViewControllerAnimated Transitioning
和UIViewControllerTransitioningDelegate
持钉,
該類的對象作為transitioningDelegate
。實現(xiàn)
UIViewControllerAnimatedTransitioning
中
的transitionDuration
和animateTransition
方法前者返回動畫的時間篱昔,后者用來實現(xiàn)轉(zhuǎn)場時的具體動畫每强。
在UIViewControllerTransitioningDelegate
的present和dismiss代理方法中返回EvernoteTransition對象,這樣就ok了
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresent = true
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresent = false
return self
}
手勢互動:
實現(xiàn)UIViewControllerTransitioningDelegate中
的interactionControllerForDismissal
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
self.isPresent = false
return interactionController
}
給第二個controller加上一個UIScreenEdgePanGestureRecognizer手勢方向為left,實時的更新interactionController空执,這樣就ok了.
func handlePanGesture(recognizer:UIScreenEdgePanGestureRecognizer) {
let view = panViewController.view
if recognizer.state == UIGestureRecognizerState.Began {
panViewController.dismissViewControllerAnimated(true, completion: { () -> Void in
})
} else if recognizer.state == UIGestureRecognizerState.Changed {
let translation = recognizer.translationInView(view)
let d = fabs(translation.x / CGRectGetWidth(view.bounds))
interactionController.updateInteractiveTransition(d)
} else if recognizer.state == UIGestureRecognizerState.Ended {
if recognizer.velocityInView(view).x > 0 {
interactionController.finishInteractiveTransition()
} else {
interactionController.cancelInteractiveTransition()
listViewController.presentViewController(panViewController, animated: false, completion: { () -> Void in
})
}
interactionController = UIPercentDrivenInteractiveTransition()
}
}
具體源碼:
注:在我自認(rèn)為沒有任何商業(yè)意圖的前提下窘茁,從dribbble上面搬來了第一張GIF,如果這篇文章有幸被原制作者看到并且認(rèn)為我這種做法給他帶來了困擾脆烟,我便立即刪除,最后送大家一首克羅地亞狂想曲房待。