iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 29
0
Software Development

無中生有-從SWIFT語法學習到iOS APP的開發系列 第 29

Day29 - highlight 錯誤

前言

昨天雖然把 collection view 可以 highl light 的效果做出來了。
但是還有幾個 bug 還沒解決

問題一

high light 的位置會隨 collection view 捲動的時候亂跳。

這個原因很簡單,跟之前使用 table view 顯示飲料數量一樣, collection view item 也是有 reusable 的記憶體管理。既然記憶體管理會錯亂,那我們就直接設一個陣列來管理 high light 的效果。

問題二

當我們滑動的 scroll view 逐漸離開 collection view item 的顯示區域時,collection view 不會跟著位移。

最後一個問題

當我們預期水平移動 scroll view 的時候,整個 scroll view 會隨手指曲線移動,畫面的切換看起來會讓人頭暈目眩。

問題一解法

1. 設置 highi light 狀態管理陣列

宣告一個新的陣列按順序來存放 high light 與否

var selectedBooling: [Bool] = []

在func collectionView(cellForItemAt indexPath: IndexPath) -> UICollectionViewCell中,把 high light 判斷改寫在這裡面。

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! TitleCollectionVCCell
        
        cell.titleLabel.text = menuList[indexPath.item]
        
        // 初始先設定第一個 item 為已選取
        if selectedBooling == [] {
            selectedBooling.append(true)
            
            for _ in 1...menuList.count {
                selectedBooling.append(false)
            }
        }
        
        // 判斷collection view 是否 high light
        if selectedBooling[indexPath.item] {
            cell.backgroundColor = UIColor.orange
        } else {
            cell.backgroundColor = UIColor.clear
        }
    
        return cell
    }

2. 改寫func collectionView(didSelectItemAt indexPath: IndexPath)

改寫成:被點選的 item 其 high light 狀態管理陣列中的內容為 true,其餘為 false

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        for i in 0...(selectedBooling.count - 1)  {
            selectedBooling[i] = false
        }
        selectedBooling[indexPath.item] = true
        menuCollectionView.reloadData()

        
//      點選 collection view item 後,跳轉 scroll view 到指定頁面
        itemNum = CGFloat(indexPath.item)
        showScrollView.setContentOffset(CGPoint(x: view.frame.width * itemNum, y: 0) , animated: true)
}

3. 取消func collectionView(didDeselectItemAt indexPath: IndexPath)

因為我們已經有狀態管理陣列,所以不用特別再去判斷 item 是否已經取消選取,所以整個 func 可以取消不用。

問題二解法

使用 UICollectionView 的 .scrollToItem 的屬性

這邊有個小插曲,因為 UICollectionView 是 UIScrollView 的子類別,所以 collection view 在滑動的時候,也會調用 func scrollViewDidEndDecelerating,所以在使用 .scrollToItem 的屬性時,要先判斷 item 位置與 scroll view 位置是否不一致,不同的時候才去滾動 collection view

PS: 如果不加入這個判斷,當你滾動 collection view的時候,畫面會自動跳回來滾動前的位置

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
         pageNum = Int(round(showScrollView.contentOffset.x / showScrollView.frame.size.width))
        
        if pageNum != Int(itemNum) {
            collectionView(menuCollectionView, didSelectItemAt: [0, pageNum])
            menuCollectionView.scrollToItem(at: [0, pageNum], at:.centeredHorizontally, animated:  true)
        }

        collectionView(menuCollectionView, didSelectItemAt: [0, pageNum])

        }

問題三解法

進到 storyboard 中,調整 scroll view 屬性

點選 UIScrollView,在右側 Attributes 屬性頁面中將 Scroll View >> Scrolling >> Direction Lock Enabled 打勾

關於 UIScrollView 的屬性說明可以參考下方連結
UIScrollView的所有屬性和方法詳解


上一篇
Day28 - 滑動螢幕切換 table view
下一篇
Day30 - popover 進階用法
系列文
無中生有-從SWIFT語法學習到iOS APP的開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言