亚洲免费人人妻人人,cao78在线视频,福建一级毛片,91精品视频免费观看,高清另类图片操逼,日本特黄特色大片免费看,超碰欧美人人澡曰曰澡夜夜泛

如何實(shí)現(xiàn)iOS圖書(shū)動(dòng)畫(huà):第1部分(上) -電腦資料

電腦資料 時(shí)間:2019-01-01 我要投稿
【www.msguai.com - 電腦資料】

   

如何實(shí)現(xiàn)iOS圖書(shū)動(dòng)畫(huà):第1部分

原文鏈接 : How to Create an iOS Book Open Animation: Part 1 原文作者 : Vincent Ngo 譯文出自 : 開(kāi)發(fā)技術(shù)前線 www.devtf.cn 譯者 : kmyhy

    本教程分為2個(gè)部分,教你開(kāi)發(fā)一個(gè)漂亮的iOS圖書(shū)打開(kāi)和翻頁(yè)動(dòng)畫(huà),就像你在Paper 53中所見(jiàn)到的一樣:

   

    在第1部分,你將學(xué)習(xí)到如何定制化Collection View Layout,并通過(guò)使用深度和陰影使App看起來(lái)更真實(shí),

如何實(shí)現(xiàn)iOS圖書(shū)動(dòng)畫(huà):第1部分(上)

。

    在第2部分,你將學(xué)習(xí)如何以一種合理的方法在兩個(gè)不同的控制器之間創(chuàng)建自定義的過(guò)渡特效,以及利用手勢(shì)在兩個(gè)視圖間創(chuàng)建自然的、直觀的過(guò)渡效果。

    本教程適用于中級(jí)-高級(jí)的開(kāi)發(fā)者;你將使用自定義過(guò)渡動(dòng)畫(huà)和自定義Collection View Layout。如果你從來(lái)沒(méi)有用過(guò)Colleciton View,請(qǐng)先參考其他iOS教程。

    注意:感謝Attila Hegdüs創(chuàng)建了本教程中的示例項(xiàng)目。

開(kāi)始

    從此處下載本教程的開(kāi)始項(xiàng)目;解開(kāi)zip壓縮包,用Xcode打開(kāi)Paper.xcodeproj。

    編譯項(xiàng)目,在模擬器中運(yùn)行App;你將看到如下畫(huà)面:

   

    這個(gè)App的功能已經(jīng)很完善了,你可以在你的書(shū)庫(kù)中滾動(dòng),查看圖書(shū),選中某本圖書(shū)進(jìn)行瀏覽。但當(dāng)你讀一本書(shū)的時(shí)候,為什么它的書(shū)頁(yè)都是并排放置的?通過(guò)一些UICollectionView的知識(shí),你可以讓這些書(shū)頁(yè)看起來(lái)更好一些!

項(xiàng)目結(jié)構(gòu)

    Here’s a quick rundown of the most important bits of the starter project:

    關(guān)于這個(gè)開(kāi)始項(xiàng)目,有幾個(gè)重要的地方需要解釋:

    Data Models文件夾包含3個(gè)文件:

Books.plist 中包含了幾本用于演示的圖書(shū)信息。每本圖書(shū)包含一張封面圖片,以及一個(gè)表示每一頁(yè)的內(nèi)容的圖片的數(shù)組。 BookStore.swift實(shí)現(xiàn)了單例,在整個(gè)App聲明周期中只能創(chuàng)建一次對(duì)象。BookStore的職責(zé)是從Books.plist中加載數(shù)據(jù)并創(chuàng)建Book類實(shí)例。 Book.swift用于存放圖書(shū)相關(guān)信息的類,比如圖書(shū)的封面,每一頁(yè)的圖片,以及頁(yè)號(hào)。

    Books文件夾包含了兩個(gè)文件:

BooksViewController.swift是一個(gè)UICollectionViewController子類。負(fù)責(zé)以水平方式顯式圖書(shū)列表。 BookCoverCell.swift負(fù)責(zé)顯示圖書(shū)的封面,這個(gè)類被BooksViewController類所引用。

    在Book文件夾中則包括:

BookViewController.swift也是UICollectionViewController的子類。當(dāng)用戶在BooksViewController中選定的一本書(shū)后,它負(fù)責(zé)顯示圖書(shū)中的書(shū)頁(yè)。 BookPageCell.swift被BookViewController用于顯示圖書(shū)中的書(shū)頁(yè)。

    在最后一個(gè)文件夾Helper中包含了:

UIImage+Helpers.swift是UIImage的擴(kuò)展。該擴(kuò)展包含了兩個(gè)實(shí)用方法,一個(gè)用于讓圖片呈圓角顯示,一個(gè)用于將圖片縮放到指定大小。

    這就是整個(gè)開(kāi)始項(xiàng)目的大致介紹——接下來(lái)該是我們寫(xiě)點(diǎn)代碼的時(shí)候了!

定制化圖書(shū)界面

    首先我們需要在BooksViewController中覆蓋Collection View的默認(rèn)布局方式。但當(dāng)前的布局是在屏幕上顯示3張圖書(shū)封面的大圖。為了美觀,我們將這些圖片縮減到一定大小,如下圖所示:

   

    當(dāng)我們滑動(dòng)圖片,移動(dòng)到屏幕中心的圖片將被放大,以表示該圖書(shū)為選中狀態(tài)。如果繼續(xù)滑動(dòng),該圖書(shū)的封面又會(huì)縮小到一邊,表示我們放棄選擇該圖書(shū)。

    在AppBooks文件夾下新建一個(gè)文件夾組:Layout。在Layout上點(diǎn)擊右鍵,選擇New File…,然后選擇iOSSourceCocoa Touch Class模板,并點(diǎn)擊Next。類名命名為BooksLayout,繼承UICollectionViewFlowLayout類,語(yǔ)言設(shè)置為Swift。

    然后需要告訴BooksViewController中的Collection View,適用我們新建的BooksLayout。

    打開(kāi)Main.storyboard,展開(kāi)BooksViewController對(duì)象,然后選擇Collection View。在屬性面板中,設(shè)置Layout 屬性為 Custom,設(shè)置Class屬性為BooksLayout,如下圖所示:

   

    打開(kāi)BooksLayout.swift,在BooksLayout類聲明之上加入以下代碼:

<code class="hljs" cs="">private let PageWidth: CGFloat = 362private let PageHeight: CGFloat = 568</code>

    這個(gè)兩個(gè)常量將用于設(shè)置單元格的的大小。

    現(xiàn)在,在類定義內(nèi)部定義如下初始化方法:

<code class="hljs" java="">required init(coder aDecoder: NSCoder) {  super.init(coder: aDecoder)  scrollDirection = UICollectionViewScrollDirection.Horizontal //1  itemSize = CGSizeMake(PageWidth, PageHeight) //2  minimumInteritemSpacing = 10 //3}</code>

    上述代碼作用如下:

設(shè)置Collectioin View的滾動(dòng)方向?yàn)樗椒较颉?設(shè)置單元格的大小為PageWidth和PageHeight,即362x568。 設(shè)置兩個(gè)單元格間距10。

    然后,在init(coder:)方法中加入代碼:

<code avrasm="" class="hljs">override func prepareLayout() {  super.prepareLayout()  //The rate at which we scroll the collection view.  //1  collectionView?.decelerationRate = UIScrollViewDecelerationRateFast  //2  collectionView?.contentInset = UIEdgeInsets(    top: 0,    left: collectionView!.bounds.width / 2 - PageWidth / 2,    bottom: 0,    right: collectionView!.bounds.width / 2 - PageWidth / 2  )}</code>

    prepareLayout()方法允許我們?cè)诿總(gè)單元格的布局信息生效之前可以進(jìn)行一些計(jì)算。

    對(duì)應(yīng)注釋中的編號(hào),以上代碼分別說(shuō)明如下:

設(shè)置當(dāng)用戶手指離開(kāi)后,Collection

    View停止?jié)L動(dòng)的速度。默認(rèn)的設(shè)置為UIScrollViewDecelerationRateFast,這是一個(gè)較快的速度。你可以嘗試著設(shè)置為Normal 和 Fast,看看二者之間有什么區(qū)別。 設(shè)置Collection View的contentInset,以使第一本書(shū)的封面位于Collection View的中心。

    現(xiàn)在我們需要處理每一個(gè)單元格的布局信息。

    在prepareLayout()方法下面,加入以下代碼:

<code class="hljs" php="">override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {  //1  var array = super.layoutAttributesForElementsInRect(rect) as! [UICollectionViewLayoutAttributes]  //2  for attributes in array {    //3    var frame. = attributes.frame. //4    var distance = abs(collectionView!.contentOffset.x + collectionView!.contentInset.left - frame.origin.x)    //5    var scale = 0.7 * min(max(1 - distance / (collectionView!.bounds.width), 0.75), 1)    //6    attributes.transform. = CGAffineTransformMakeScale(scale, scale)  }  return array}</code>

    layoutAttributesForElementsInRect(_:) 方法返回一個(gè)UICollectionViewLayoutAttributes對(duì)象數(shù)組,其中包含了每一個(gè)單元格的布局屬性,

電腦資料

如何實(shí)現(xiàn)iOS圖書(shū)動(dòng)畫(huà):第1部分(上)》(http://www.msguai.com)。以上代碼稍作說(shuō)明如下:

調(diào)用父類的layoutAttributesForElementsInRect方法,已獲得默認(rèn)的單元格布局屬性。 遍歷數(shù)組中的每個(gè)單元格布局屬性。 從單元格布局屬性中讀取frame。 計(jì)算兩本書(shū)的封面之間的間距——即兩個(gè)單元格之間的間距——以及屏幕的中心點(diǎn)。 以0.75~1之間的比率縮放封面,具體的比率取決于前面計(jì)算出來(lái)的間距。然后為了美觀,將所有的封面都縮放70%。 最后,應(yīng)用仿射變換。

    接下來(lái),在layoutAttributesForElementsInRect(_:)方法后增加如下代碼:

<code class="hljs" coffeescript="">override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {  return true}</code>

    返回true表示每當(dāng)Collection View的bounds發(fā)生改變時(shí)都強(qiáng)制重新計(jì)算布局屬性。Collection View在滾動(dòng)時(shí)會(huì)改變它的bounds,因此我們需要重新計(jì)算單元格的布局屬性。

    編譯運(yùn)行程序,我們將看到位于中央的封面明顯比其他封面要大上一圈:

   

    拖動(dòng)Colleciton View,查看每本書(shū)放大、縮小。但仍然有一點(diǎn)稍顯不足,為什么不讓書(shū)本能夠卡到固定的位置呢?

    接下來(lái)我們介紹的這個(gè)方法就是干這個(gè)的。

對(duì)齊書(shū)本

    targetContentOffsetForProposedContentOffset(_:withScrollingVelocity:)方法用于計(jì)算每本書(shū)應(yīng)該在對(duì)齊到哪個(gè)位置,它返回一個(gè)偏移位置,可用于設(shè)置Collection View的contentOffset。如果你不覆蓋這個(gè)方法,它會(huì)返回一個(gè)默認(rèn)的值。

    在shouldInvalidateLayoutForBoundsChange(_:)方法后添加如下代碼:

<code class="hljs" livecodeserver="">override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {  // Snap cells to centre  //1  var newOffset = CGPoint()  //2  var layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout  //3  var width = layout.itemSize.width + layout.minimumLineSpacing  //4  var ffset = proposedContentOffset.x + collectionView!.contentInset.left  //5  if velocity.x > 0 {    //ceil returns next biggest number    ffset = width * ceil(offset / width)  } else if velocity.x == 0 { //6    //rounds the argument    ffset = width * round(offset / width)  } else if velocity.x < 0 { //7    //removes decimal part of argument    ffset = width * floor(offset / width)  }  //8  newOffset.x = offset - collectionView!.contentInset.left  newOffset.y = proposedContentOffset.y //y will always be the same...  return newOffset}</code>

    這段代碼計(jì)算當(dāng)用戶手指離開(kāi)屏幕時(shí),封面應(yīng)該位于哪個(gè)偏移位置:

聲明一個(gè)CGPoint。 獲得Collection View的當(dāng)前布局。 獲得單元格的總寬度。 計(jì)算相對(duì)于屏幕中央的currentOffset。 如果velocity.x>0,表明用戶向右滾動(dòng),用offset除以width,得到書(shū)的索引,并滾動(dòng)到相應(yīng)的位置。 如果velocity.x=0,表明用戶是無(wú)意識(shí)的滾動(dòng),原來(lái)的選擇不會(huì)發(fā)生改變。 如果velocity.x<0,表明用戶向左滾動(dòng)。 修改newOffset.x,然后返回newOffset。這樣就保證書(shū)本總是對(duì)齊到屏幕的中央。

    編譯運(yùn)行程序;再次滾動(dòng)封面,你會(huì)注意到滾動(dòng)動(dòng)作將變得更整齊了。

    要完成這個(gè)布局,我們還需要使用一種機(jī)制,以限制用戶只能點(diǎn)擊位于中央的封面。目前,不管哪個(gè)位置的封面都是可點(diǎn)擊的。

    打開(kāi)BooksViewController.swift,在注釋”//MARK:Helpers”下面加入以下代碼:

<code class="hljs" coffeescript="">func selectedCell() -> BookCoverCell? {  if let indexPath = collectionView?.indexPathForItemAtPoint(CGPointMake(collectionView!.contentOffset.x + collectionView!.bounds.width / 2, collectionView!.bounds.height / 2)) {    if let cell = collectionView?.cellForItemAtIndexPath(indexPath) as? BookCoverCell {      return cell    }  }  return nil}</code>

    selectedCell()方法返回位于中央的那個(gè)單元格。

    替換openBook(_:)方法的代碼如下:

<code class="hljs" coffeescript="">func openBook() {  let vc = storyboard?.instantiateViewControllerWithIdentifier(BookViewController) as! BookViewController  vc.book = selectedCell()?.book  // UICollectionView loads it's cells on a background thread, so make sure it's loaded before passing it to the animation handler  dispatch_async(dispatch_get_main_queue(), { () -> Void in    self.navigationController?.pushViewController(vc, animated: true)    return  })}</code>

    這里,直接調(diào)用新的selectedCell方法,并用它的book屬性代替原來(lái)的book參數(shù)。

    然后,將collectionView(_:didSelectItemAtIndexPath:)方法替換為:

<code class="hljs" scss="">override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {  openBook()}</code>

    這里,我們簡(jiǎn)單地刪除了原來(lái)的打開(kāi)某個(gè)索引處的圖書(shū)的代碼,而直接打開(kāi)了當(dāng)前位于屏幕中央的圖書(shū)。

    編譯運(yùn)行程序,我們將看到每次打開(kāi)的圖書(shū)總是位于屏幕中央的那本。

最新文章