首页 > 解决方案 > UIKit:UICollectionViewCell 内的 UIPickerView 变得不可见

问题描述

我想要一个带有一行的自定义视图UIPickerView来显示一个数字。这是我的游乐场:

import PlaygroundSupport
import UIKit
import CoreGraphics

typealias DigitItemSize = (CGFloat, CGFloat)

class NumberViewItemArea {
    private var digitWidth_ : CGFloat = 0
    private var digitHeight_ : CGFloat = 0
    private var numberOfDigits_ : Int = 0
    private var area_ : CGRect? = nil
    private var spaceBetweenDigits_ : CGFloat = 0
    
    private func recalculateArea()
    {
        if numberOfDigits_ < 1 {
            area_ = nil
        } else {
            area_ = CGRect(x:0,
                           y:0,
                           width : digitWidth_*CGFloat(numberOfDigits_) + spaceBetweenDigits_*CGFloat(numberOfDigits_-1),
                           height: digitHeight_)
        }
    }
    
    init(itemWidth : CGFloat,
         itemHeight : CGFloat,
         numOfDigits : Int,
         spaceBetweenDigits : CGFloat) {
        
        digitWidth_ = itemWidth
        digitHeight_ = itemHeight
        numberOfDigits_ = numOfDigits
        spaceBetweenDigits_ = spaceBetweenDigits
        
        recalculateArea()
    }
    
    init() {}

    public var digitWidth : CGFloat {
        get {
            return digitWidth_
        }
        
        set(newWidth) {
            digitWidth_ = newWidth
            recalculateArea()
        }
    }
    
    public var digitHeight : CGFloat {
        get {
            return digitHeight_
        }
        
        set(newHeight) {
            digitHeight_ = newHeight
            recalculateArea()
        }
    }
    
    public var numberOfDigits : Int {
        get {
            return numberOfDigits_
        }
        
        set(newValue) {
            numberOfDigits_ = newValue
            recalculateArea()
        }
    }
    
    public var spaceBetweenDigits : CGFloat {
        get {
            return spaceBetweenDigits_
        }
        
        set(newValue) {
            spaceBetweenDigits_ = newValue
            recalculateArea()
        }
    }
    
    public var area : CGRect? {
        get {
            return area_
        }
    }
}

public class DigitControlItem: UIView {
    lazy var categoryPickerView: UIPickerView = {
        let pv = UIPickerView()
        pv.dataSource = self
        pv.backgroundColor = .white
        pv.delegate = self
        pv.translatesAutoresizingMaskIntoConstraints = false
        return pv
    }()
    
    let dataArray = ["0", "1", "2", "3", "4","5","6","7","8","9"]
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
        
    private func commonInit() {
        setupSettingPickerView()
    }
    
    private func setupSettingPickerView() {
        addSubview(categoryPickerView)
        
        let constraints = [
            categoryPickerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 0),
            categoryPickerView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: 0),
            categoryPickerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
            categoryPickerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0)
        ]
        
        NSLayoutConstraint.activate(constraints)
    }
}

extension DigitControlItem: UIPickerViewDataSource, UIPickerViewDelegate {
    public func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
        
    public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
       return dataArray.count
    }
    
    public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
       let row = dataArray[row]
       return row
    }
}

class DigitItem: UICollectionViewCell {
    private let digitArea : DigitControlItem = {
        let view = DigitControlItem(frame : .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setupViews() {
        contentView.addSubview(digitArea)
        
        let constraints = [
            digitArea.topAnchor.constraint(equalTo: contentView.topAnchor),
            digitArea.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            digitArea.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            digitArea.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ]
        
        NSLayoutConstraint.activate(constraints)
    }
}

class NumberView : UIView {
    private var digitItemSize : DigitItemSize = (0, 0)
    private var numberOfDigitItems : Int = 0
    private var spaceBetweenItems : CGFloat = 0
    
    private lazy var digitsCollection : UICollectionView = {
      let layout = UICollectionViewFlowLayout()
      layout.scrollDirection = .horizontal

      let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
      view.register(DigitItem.self,
                    forCellWithReuseIdentifier: String(describing: DigitItem.self))
      view.dataSource = self
      view.delegate = self
      view.backgroundColor = .white
      view.translatesAutoresizingMaskIntoConstraints = false
      return view
    }()

    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    convenience init(areaProvider : NumberViewItemArea) {
        guard let rect = areaProvider.area else {
            self.init(frame : .zero)
            return
        }
        
        self.init(frame: rect)
        
        numberOfDigitItems = areaProvider.numberOfDigits
        spaceBetweenItems = areaProvider.spaceBetweenDigits
        digitItemSize = (areaProvider.digitWidth, areaProvider.digitHeight)
        digitsCollection.reloadData()
    }
    
    private func setupView()
    {
        addSubview(digitsCollection)
        
        let constraints = [
            digitsCollection.topAnchor.constraint(equalTo: topAnchor, constant: 0),
            digitsCollection.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0),
            digitsCollection.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
            digitsCollection.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0)
        ]
        
        NSLayoutConstraint.activate(constraints)
    }
}

extension NumberView : UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return numberOfDigitItems
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell =
        digitsCollection.dequeueReusableCell(withReuseIdentifier:
                                                String(describing: DigitItem.self),
                                              for: indexPath) as! DigitItem
        
//        cell.imageName = PhotoGalleryData.images[indexPath.row]
        
        return cell
    }
}

extension NumberView : UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: digitItemSize.0, height: digitItemSize.1)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return spaceBetweenItems
    }
        
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }
}

let itemArea = NumberViewItemArea(itemWidth: 32,
                                  itemHeight:32,
                                  numOfDigits:1,
                                  spaceBetweenDigits:2)



//let item = DigitControlItem(frame: CGRect(x: 0, y: 0, width: 50, height: 50))


let item = NumberView(areaProvider: itemArea)

PlaygroundPage.current.liveView = item

因此,如果我查看 a DigitControlItemUIPickerView实际上是 a )一切正常,但如果它是集合视图(NumberView类)的一部分,它似乎是不可见的。任何想法这里可能有什么问题?

标签: swiftuikitswift-playground

解决方案


问题来自选择器视图的默认委托。我解决了定义自己的标签的问题:

public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
    var label = UILabel()
    if let v = view as? UILabel { label = v }
    label.text =  dataArray[row]
    label.textColor = UIColor.white
    label.textAlignment = .center
    return label
}

推荐阅读