Загрузить представление из XIB как подпредставление прокрутки - PullRequest
0 голосов
/ 11 февраля 2019

Я все еще новичок SO и Swift, поэтому, пожалуйста, наберитесь терпения и не стесняйтесь пропустить этот вопрос: -)

В теле XIB awakeFromNib, я хочудля загрузки некоторых представлений в виде подпредставлений UIScrollView (в основном XIB содержит представление прокрутки, метку и кнопку).

Представление прокрутки отлично работает, если в цикле я загружаю представления, созданные наfly, например.

 let customView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 150))
 customView.frame = CGRect(x: i*300 , y: 0, width: 300, height: 150)
 customView.translatesAutoresizingMaskIntoConstraints = false
 scrollView.addSubview(customView)

Но у меня другая цель.

В другом XIB У меня есть вид изображения и вид в стеке с некоторыми метками.Этот XIB подключен в раскадровке к классу SingleEvent, который расширяет UIView.

Я хочу сделать следующее:

  1. использовать XIB в качествевроде «план» и загружать одно и то же представление несколько раз в моем представлении прокрутки;
  2. передать любому экземпляру некоторые данные;

Возможно ли это?

Я пыталсязагрузить содержимое XIB следующим образом:

 let customView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as? SingleEvent

и таким образом:

let customView = SingleEvent()

Первый вызывает сбой приложения, а второй не вызывает проблем, но я могуНе вижу никакого эффекта (ничего не загружается).

Содержимое моего последнего SingleEvent следующее:

 import UIKit

    class SingleEvent: UIView {

        @IBOutlet weak var label:UILabel!
        @IBOutlet weak var imageView:UIImageView!

        override init(frame: CGRect) {
            super.init(frame: frame)

            loadViewFromNib()
        }

        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)

            loadViewFromNib()
        }

        func loadViewFromNib() -> UIView {
            let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! UIView
            return myView
        }
    }

Заранее благодарен за любую помощь:-)

Ответы [ 2 ]

0 голосов
/ 11 февраля 2019

Существует несколько подходов к загрузке пользовательских представлений (классов) из XIBS.Этот метод может показаться вам немного проще.

Сначала создайте свой xib следующим образом:

enter image description here

Обратите внимание, что класс File's Owner - это значение по умолчанию (NSObject).

Вместо этого назначьте свой пользовательский класс для представления «root» в своей xib:

enter image description here

Теперь весь наш пользовательский класс представления выглядит следующим образом:

class SingleEvent: UIView {

    @IBOutlet var topLabel: UILabel!
    @IBOutlet var middleLabel: UILabel!
    @IBOutlet var bottomLabel: UILabel!

    @IBOutlet var imageView: UIImageView!

}

И вместо того, чтобы помещать loadNibNamed(...) в наш пользовательский класс, мы создаем расширение UIView:

extension UIView {
    class func fromNib<T: UIView>() -> T {
        return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
    }
}

Чтобы загрузить и использовать наш пользовательский класс, мы можем сделать это:

class FromXIBViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // create an instance of SingleEvent from its xib/nib
        let v = UIView.fromNib() as SingleEvent

        // we're going to use auto-layout & constraints
        v.translatesAutoresizingMaskIntoConstraints = false

        // set the text of the labels
        v.topLabel?.text    = "Top Label"
        v.middleLabel?.text = "Middle Label"
        v.bottomLabel?.text = "Bottom Label"

        // set the image
        v.imageView.image = UIImage(named: "myImage")

        // add the SingleEvent view
        view.addSubview(v)

        // constrain it 200 x 200, centered X & Y
        NSLayoutConstraint.activate([
            v.widthAnchor.constraint(equalToConstant: 200.0),
            v.heightAnchor.constraint(equalToConstant: 200.0),
            v.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            v.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            ])

    }

}

В результате:

enter image description here

И ... вот пример загрузки 10 экземпляров вида SingleEvent и добавления их в представление с вертикальной прокруткой:

class FromXIBViewController: UIViewController {

    var theScrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()

    var theStackView: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.alignment = .fill
        v.distribution = .fill
        v.spacing = 20.0
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // add the scroll view to the view
        view.addSubview(theScrollView)

        // constrain it 40-pts on each side
        NSLayoutConstraint.activate([
            theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40.0),
            theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -40.0),
            theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40.0),
            theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40.0),
            ])

        // add a stack view to the scroll view
        theScrollView.addSubview(theStackView)

        // constrain it 20-pts on each side
        NSLayoutConstraint.activate([
            theStackView.topAnchor.constraint(equalTo: theScrollView.topAnchor, constant: 20.0),
            theStackView.bottomAnchor.constraint(equalTo: theScrollView.bottomAnchor, constant: -20.0),
            theStackView.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor, constant: 20.0),
            theStackView.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor, constant: -20.0),

            // stackView width = scrollView width -40 (20-pts padding on left & right
            theStackView.widthAnchor.constraint(equalTo: theScrollView.widthAnchor, constant: -40.0),
            ])


        for i in 0..<10 {

            // create an instance of SingleEvent from its xib/nib
            let v = UIView.fromNib() as SingleEvent

            // we're going to use auto-layout & constraints
            v.translatesAutoresizingMaskIntoConstraints = false

            // set the text of the labels
            v.topLabel?.text    = "Top Label: \(i)"
            v.middleLabel?.text = "Middle Label: \(i)"
            v.bottomLabel?.text = "Bottom Label: \(i)"

            // set the image (assuming we have images named myImage0 thru myImage9
            v.imageView.image = UIImage(named: "myImage\(i)")

            theStackView.addArrangedSubview(v)

        }

    }

}

Результат:

enter image description here

0 голосов
/ 11 февраля 2019

Хорошо, я вижу.Проблема, вероятно, в том, что функция loadViewFromNib возвращает UIView из xib, но вы не используете его в любом случае.
Давайте попробуем так:
1) Сделайте вашу функцию loadViewFromNib статической

    // Return our SingleEvent instance here  
    static func loadViewFromNib() -> SingleEvent {
            let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! SingleEvent
            return myView
        }

2) Удалите все элементы в классе SingleEvent

3) Инициируйте его в нужном месте следующим образом:

let customView = SingleView.loadViewFromNib()

Для передачи данных в представление вы можете создать новую функцию в классе SingleView:

func configureView(with dataModel:DataModel) {
   //Set data to IBOutlets here
}

И используйте его снаружи так:

let customView = SingleView.loadViewFromNib()
let dataModel = DataModel()
customView.configureView(with: dataModel)
...