Swift實(shí)現(xiàn)3D輪播圖效果
本文實(shí)例為大家分享了Swift實(shí)現(xiàn)3D輪播圖效果的具體代碼,供大家參考,具體內(nèi)容如下
整天逛淘寶,偶爾有一天看到其中的展示頁有個(gè)看起來很炫的效果,閑來無事就試著寫一個(gè)出來,先來看效果:
簡單記一下思路,這里我選擇使用UICollectionView控件,先根據(jù)其復(fù)用和滾動(dòng)的特性做出無限輪播的效果,關(guān)鍵代碼:
//數(shù)據(jù)源數(shù)組 let totalCount = 100 var models: [String] = [String]() { didSet { //判斷元素個(gè)數(shù) if models.count < 2 { collectionView.isScrollEnabled = false } //網(wǎng)上的找來的一個(gè)辦法添加100組數(shù)據(jù)源對應(yīng)的索引數(shù)組indexArr for _ in 0..<totalCount { for j in 0..<models.count { indexArr.append(j) } } //開始就滾動(dòng)到第50組數(shù)據(jù)源 collectionView.scrollToItem(at: IndexPath(item: totalCount/2 * models.count, section: 0), at: .centeredHorizontally, animated: false) } }
滾動(dòng)停止時(shí)走的方法里做處理:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { //找到滾動(dòng)停止的點(diǎn)對應(yīng)的collectionView的indexPath let point = self.convert(collectionView.center, to: collectionView) let index = collectionView.indexPathForItem(at: point) let indexpath = (index?.row ?? 0) % models.count collectionView.scrollToItem(at: IndexPath(item: totalCount/2 * models.count + indexpath, section: 0), at: .centeredHorizontally, animated: false) }
以上是滾動(dòng)的處理,接下來就是item的漸變效果處理,看到這種情況就想到要寫一個(gè)UICollectionViewFlowLayout
類供collectionView使用,UICollectionViewFlowLayout是管理item怎么展示用的,首先重寫展示視圖內(nèi)的layoutAttributes方法,在此方法中找到attribute對應(yīng)的item及其屬性,和collectionView的偏移量和中心點(diǎn),進(jìn)行一系列的計(jì)算:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { //集合視圖的寬高(這里默認(rèn)寬高相等) let itemHeight = self.collectionView?.frame.height ?? 0 //可是視圖內(nèi)的attributes數(shù)組 let array = super.layoutAttributesForElements(in: rect) //item透明度開始變化時(shí)的item的中心點(diǎn)x let centerX = self.collectionView!.contentOffset.x + itemHeight/2 print(self.collectionView?.contentOffset.x ?? 0) for attributes in array! { //開始變化時(shí)的item的中心點(diǎn)x 與 實(shí)際中心點(diǎn)相比較 let value = attributes.center.x - centerX let delta = abs(value) //設(shè)置縮放比例,此處4*itemHeight可根據(jù)縮放效果進(jìn)行修改 let scale = 1 - delta/(4*itemHeight) //設(shè)置縮放比例 attributes.transform = CGAffineTransform.init(scaleX: scale, y: scale) //層次關(guān)系,設(shè)置此屬性使item依次上下排列 attributes.zIndex = Int(1 - abs(delta)) //value<=0表示向左移動(dòng),最前面的item停止一段距離 if value <= 0{ //實(shí)際中心點(diǎn)與開始變化時(shí)的item的中心點(diǎn)小于等于設(shè)定的邊界值 if delta >= 0 && delta <= itemHeight { //item的中心點(diǎn)固定不變 attributes.center.x = centerX //根據(jù)推進(jìn)值,改變item的透明度,此處的delta>10是想讓item有一個(gè)達(dá)到目標(biāo)區(qū)域時(shí)有一個(gè)停頓效果而不是直接進(jìn)入改變透明度的階段 attributes.alpha = (delta > 10) ? (1 - delta/(itemHeight/4)) : 1 //設(shè)置縮放比例,停頓階段不進(jìn)行縮放 attributes.transform = CGAffineTransform.init(scaleX: 1, y: 1) } else { //移動(dòng)大于邊界值,就是從停頓階段到透明度改變,此處是下一個(gè)item上來,當(dāng)前item透明度變?yōu)? attributes.alpha = 0 } } } return array }
解決最后一個(gè)小問題,拖動(dòng)iitem開始滾動(dòng),滾動(dòng)結(jié)束時(shí)讓它自動(dòng)滾動(dòng)到網(wǎng)格區(qū)域,而不是停在當(dāng)前或許不適當(dāng)?shù)牡胤?,重寫UICollectionViewFlowLayout另一個(gè)方法:
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { let targetRect = CGRect(x: proposedContentOffset.x, y: 0.0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height) //目標(biāo)區(qū)域中包含的cell let attrArray = super.layoutAttributesForElements(in: targetRect) as! [UICollectionViewLayoutAttributes] //collectionView落在屏幕重點(diǎn)的x坐標(biāo) let horizontalCenterX = proposedContentOffset.x + (self.collectionView?.frame.height ?? 0)/2 var offsetAdjustment = CGFloat(MAXFLOAT) for layoutAttributes in attrArray { let itemHorizontalCenterX = layoutAttributes.center.x //找出離中心店最近的 if (abs(itemHorizontalCenterX-horizontalCenterX) < abs(offsetAdjustment)) { offsetAdjustment = itemHorizontalCenterX - horizontalCenterX } } //返回collectionView最終停留的位置 return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y) } //當(dāng)collectionView的顯示范圍發(fā)生改變的時(shí)候,是否重新布局 override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true }
最后一個(gè)方法不寫看不到漸變的效果。
源碼地址:點(diǎn)擊打開鏈接
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Swift調(diào)用Objective-C編寫的API實(shí)例
- swift5.3 UIColor使用十六進(jìn)制顏色的方法實(shí)例
- 詳解Swift 結(jié)構(gòu)體
- Swift 進(jìn)階 —— map 和 flatMap的使用
- Swift 5.1 之類型轉(zhuǎn)換與模式匹配的教程詳解
- 如何使用Swift來實(shí)現(xiàn)一個(gè)命令行工具的方法
- Swift4使用GCD實(shí)現(xiàn)計(jì)時(shí)器
- Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能
- Swift 中如何使用 Option Pattern 改善可選項(xiàng)的 API 設(shè)計(jì)
相關(guān)文章
Swift之UITabBarController 導(dǎo)航控制器的自定義
本文給大家介紹swift導(dǎo)航控制器之UITabBarController,本文通過代碼實(shí)例給大家講解swift導(dǎo)航控制器,導(dǎo)航控制器類繼承UITabBarController,代碼簡單易懂,需要的朋友可以參考下2015-10-10Swift、Objective-C、Cocoa混合編程設(shè)置指南
這篇文章主要介紹了Swift、Objective-C、Cocoa混合編程設(shè)置指南,需要的朋友可以參考下2014-07-07