#swift #uikit #swift-playground
Вопрос:
Я хотел бы иметь пользовательское представление со строкой 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 DigitControlItem
(что UIPickerView
на самом деле является a), все работает нормально, но если это часть представления коллекции( NumberView
класса), оно кажется невидимым. Есть какие-нибудь идеи, что здесь может быть не так?
Ответ №1:
Проблема возникает из-за делегата по умолчанию представления выбора. Я решил свою проблему, определив свой собственный ярлык :
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 }