簡要

這次要來完成上方篩選的細節
上次只有實作簡單版的collectionView
但要仔細觀察他每個字其實都有自適應寬度
自適應在很多地方都用得到
今天就來研究 Swfit 自適應寬度

collectionView

要控制cell大小除了之前有提過的

layout.itemSize = CGSize(width: 100, height: 30)

要做更詳細的控制每個index row
可以使用collectionViewLayout做控制
回傳CGSize改變每一個cell

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
    var cellSize = CGSize()
    return cellSize
}

這裡很重要*3
這不像是OC直接將func打好就可以控制
記得宣告頂部的UICollectionViewDelegateFlowLayout
才可以雙劍合併 你的cell才會改變
如果下沒作動記得看一下有沒有宣告

class HomeViewController: UICollectionViewDelegateFlowLayout 

我這邊將上面分類的文字都先用一個陣列儲存好
畢竟沒api直接寫死就可以了

var filterTitleArr: Array<String> = []

filterTitleArr = ["分類", "價格範圍", "外送費上限", "飲食限制"]

這邊開始就可以注意到
他的篩選有五個文字
並且有長有短
所以我們需要幫他們各自測量大小
這邊有一個func可以讓你帶入 font以及maxSize
自動回傳最大的高度以及長度

// MARK: - Custom Methods
func textSize(text : String , font : UIFont , maxSize : CGSize) -> CGSize{
    return text.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font : font], context: nil).size
}

接下來回去剛剛的collectionViewLayout
func加入到裡面
並且把該填入的質都帶進去

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    var cellSize = CGSize()
    let textFont = UIFont.systemFont(ofSize: 17)
    let textString = filterTitleArr[indexPath.item]
    let textMaxSize = CGSize(width: 240, height: CGFloat(MAXFLOAT))
    let textLabelSize = self.textSize(text:textString , font: textFont, maxSize: textMaxSize)

    //+40 是右方icon寬度 + 其他設定
    //如果你是單純文字的話不用加
    cellSize.width = textLabelSize.width + 40

    //高度固定
    cellSize.height = 30 
    return cellSize
}

cellForItemAtindexPath 裡面記得把剛剛的文字也放進去

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell:HomeCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath)
    as! HomeCell
    //文字
    cell.textLabel.text = filterTitleArr[indexPath.item]
    //圖片
    cell.iconImg?.image = UIImage.init(named: "down")

}

簡單Demo

看起來好像可以了
但是前方好像還有一個設定icon
跟大家特別不一致
沒label 圖片大小也不同

原APP
https://ithelp.ithome.com.tw/upload/images/20190923/201122716YyzRMQEhT.png

我在想說要不要乾脆count直接+1
index item == 0的地方直接addSubView
感覺好像可以 來實做看看

collectionViewLayout

第一個按鈕是正圓形
所以將其設定為正方形即可
剩餘不變

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    var cellSize = CGSize()
    if indexPath.item == 0 {
        cellSize.width = 30
    }else{
        let textFont = UIFont.systemFont(ofSize: 17)
        let textString = filterTitleArr[indexPath.item - 1]
        let textMaxSize = CGSize(width: 240, height: CGFloat(MAXFLOAT))
        let textLabelSize = self.textSize(text:textString , font: textFont, maxSize: textMaxSize)
        cellSize.width = textLabelSize.width + 40
    }
    cellSize.height = 30
    return cellSize
}

numberOfItemsInSection

count 比剛剛還多1
為了放置前方icon

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 5
}

cellForItemAtindexPath

這裡的想法是直接接之前的
文字Labelicom 都隱藏
並且加入單純的設定icon

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell:HomeCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath)
        as! HomeCell

    cell.backgroundColor = UIColor.init(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.1)
    cell.clipsToBounds = true
    cell.layer.cornerRadius = cell.frame.height/2

    if indexPath.item == 0 {
        cell.textLabel.isHidden = true
        cell.iconImg.isHidden = true

        let titleImg = UIImageView()
        titleImg.frame = CGRect.init(x: cell.frame.width*0.3, y: cell.frame.height*0.3, width: cell.frame.width*0.4, height: cell.frame.height*0.4)
        titleImg.image = UIImage.init(named: "settings")
        cell.addSubview(titleImg)

    }else{
        cell.textLabel.isHidden = false
        cell.iconImg.isHidden = false

        cell.textLabel.text = filterTitleArr[indexPath.item - 1]
        cell.iconImg?.image = UIImage.init(named: "down")
    }

    return cell
}

Demo

哇 是不是完成了
看似美好 我就在想
這樣會不會他每次都add一個image出來
越想越不對
立刻把 titleImg.alpha = 0.1
這樣如果重複新增的話會越來越深
結果果然越變越深
這樣會造成我的記憶體爆掉
不太行

決定把原來的客製化HomeCell做修改
使用Stack View把他們三個選成一個群組

原先
https://ithelp.ithome.com.tw/upload/images/20190923/20112271Fg7ocoIZh0.png

新增stackView
https://ithelp.ithome.com.tw/upload/images/20190923/20112271LJ4ZqdUYE6.png

將三個元件新增進來
https://ithelp.ithome.com.tw/upload/images/20190923/20112271OZRDLZp5Gc.png

並且把 title icon 固定 1:1比例尺新增進去
再來使用Hidden 來控制是否要出現
Stack View的好處就是會像
Androidgone一樣
Hidden位置也會消失
不會留空白在原地

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell:HomeCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath)
        as! HomeCell

    cell.backgroundColor = UIColor.init(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.1)
    cell.clipsToBounds = true
    cell.layer.cornerRadius = cell.frame.height/2

    if indexPath.item == 0 {
        cell.textLabel.isHidden = true
        cell.iconImg.isHidden = true
        cell.titleImg.isHidden = false
    }else{
        cell.textLabel.isHidden = false
        cell.iconImg.isHidden = false
        cell.titleImg.isHidden = true
        cell.textLabel.text = filterTitleArr[indexPath.item - 1]
    }

    return cell
}

Demo

大功告成


Categorized in: