Когда использовать View поверх ViewControlller - PullRequest
0 голосов
/ 02 января 2019

Я хотел бы знать, каковы лучшие рекомендации при выборе класса UIview или UIviewcontroller.

Я работаю над приложением, в котором одновременно используются несколько классов и представлений в одном Viewcontroller. У меня есть вид, который динамически создает кнопки. Это представление живет вместе со многими другими представлениями в ViewController. Так как это представление реализует довольно много строк кода, я сделал это в отдельный класс. Тогда возникает вопрос: должен ли он расширять UiView или UIViewcontroller?

Это представление будет иметь несколько свойств, таких как отступы, доступные размеры и т. Д. Они зависят от якорей авторазметки своего родительского Viewcontroller, подклассом которого он является. Если я использую UIview, они не будут созданы в Init.

почему, я должен выбрать один над другим?

class TagController: UIView {

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

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


var buttons : [UIButton: String]?

var sidePadding = CGFloat(15);
var topPadding = CGFloat(15);
var spacing = CGFloat(10);

var availableHeight : CGFloat!
var availableWidth :  CGFloat!

func createButton (title: String) -> UIButton {
    let maxWidth : CGFloat = 180;
    let button = UIButton();

    button.setTitle(title, for: .normal)
    button.titleLabel?.font = UIFont(name: "Avenir-Light", size: 15.0)
    button.translatesAutoresizingMaskIntoConstraints = false;
    self.addSubview(button)
    button.frame = CGRect(x:0,y:0,width:button.intrinsicContentSize.width, height: button.intrinsicContentSize.height)
    if button.frame.width > maxWidth { button.widthAnchor.constraint(equalToConstant: maxWidth).isActive = true }
    button.backgroundColor = .blue
   // button.addTarget(self, action: #selector(self.onButtonPresed(_:)), for: .touchUpInside);
    return button;
}


public func addButton(name: String) {
    let button = createButton(title: name)
    setConstriants(button: button)
}

private func setConstriants(button: UIButton) {

        for label in buttons {

        if totalHeight + 50 > availableHeight { createMoreButton(topPadding); break };

        let button = createButton(buttonText: label)
        let buttonWidth = button.intrinsicContentSize.width;
        let buttonHeight = button.intrinsicContentSize.height;

        if buttonWidth > availableWidth {
            button.widthAnchor.constraint(equalToConstant:  availableWidth  - sidePadding).isActive = true;
        }
        if rowLength == 0 && rowCount == 0
        {
            setFirstButtonConstraint(button: button, totalHeight: totalHeight, sidePadding: sidePadding)
            rowLength += buttonWidth + sidePadding // FIX annoying first row image overlap

        }
        else if rowLength + buttonWidth + padding < availableWidth
        {
            setConstraint(button: button, lastButton: lastButton, totalHeight: totalHeight, padding: padding)
            rowLength += buttonWidth + padding;
        }
        else
        {

            totalHeight += buttonHeight + padding
            rowLength = buttonWidth + sidePadding;
            rowCount += 1;
            setNewRowConstraint(button: button, totalHeight:totalHeight , sidePadding: sidePadding)
        }
        indexOfLastButton += 1;
        lastButton = button
        displayedButtons.append(button)
        print("Buttons displayed   \(displayedButtons.count)")
    }

    pulsate_buttons(duration: 0.1)
}

private func removeDisplayedButtons() {
    for _ in 0...displayedButtons.count {
        displayedButtons.popLast()?.removeFromSuperview();
    }
};

private func setFirstButtonConstraint(button: UIButton, totalHeight: CGFloat, sidePadding: CGFloat) {
    button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
    button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: sidePadding + 5).isActive = true;
}
private func setConstraint(button: UIButton, lastButton: UIButton, totalHeight: CGFloat, padding:CGFloat) {
    button.leadingAnchor.constraint(equalTo: lastButton.trailingAnchor, constant: padding).isActive = true;
    button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
}
private func setNewRowConstraint(button: UIButton, totalHeight: CGFloat, sidePadding: CGFloat) {
    button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: sidePadding).isActive = true;
    button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
}

private func createMoreButton(_ topPadding: CGFloat) {
    if moreButton != nil { return }
    let btn = UIButton()
    btn.setImage(UIImage(named: "suggestionCloud_more_button.png"), for: .normal)
    let buttonText = "Moooar.."
    btn.setTitle(buttonText, for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.titleLabel?.font = UIFont(name: "Avenir-Light", size: 15.0)
    self.addSubview(btn)
    moreButton = btn
    btn.frame = CGRect(x: (self.frame.size.width/2 - 20), y: self.frame.size.height * 0.85, width: 40, height: 15)
    btn.addTarget(self, action: #selector(showMoreButtons(_:)), for: .touchUpInside)
}

@objc func showMoreButtons(_: UIButton) {
    pulsate_view(duration: 0.1)
    if indexOfLastButton == labelStore.count { indexOfLastButton = 0; return createLayout(buttons : labelStore)}
    let buttonsToBeDisplayed : [String] = Array(labelStore[indexOfLastButton...])
    createLayout(buttons: buttonsToBeDisplayed)
}

1 Ответ

0 голосов
/ 02 января 2019

Мне нравится думать об этом так: UIView размещает и управляет дискретным контентом, в то время как UIViewController размещает и управляет контентом приложения, состоящим из множества частей дискретного контента.

Вы можете думать об этом с точки зрения настольных приложений, где «окно» - это UIViewController, тогда как элементы этого окна (кнопки, панели инструментов и т. Д.) Имеют значение UIViews (вы также можете разместить другие UIViewControllers внутри UIViewController).

Как правило, UIViews не должен определять логику навигации приложения, но должен отнести его к UIViewController.

Проще говоря, если что-то представлено модально или занимает весь экран, это, вероятно, означает UIViewController.

Традиционно Apple принимает парадигму MVC (Модель / Вид / Контроллер). Если вашим контентом является Модель (дата рождения человека, фотография, которую вы сделали), то именно там отображается представление, а Контроллер выступает посредником между управлением контентом (сохранением, поиском) и отображением контента.

Кстати: посмотрите на UIStackView ряды кнопок.


Бонус : Как создать собственный инициализатор для программно созданного экземпляра UIView.

Если ваше представление создается только программно (а не создается с помощью конструктора интерфейса), вы можете определить для него требуемый инициализатор:

class MyView: UIView {
    var required: Bool
    var anotherRequiredVar: String

    required init(frame: CGRect, something: Bool, somethingElse: String) {
        required = something
        anotherRequiredVar = somethingElse
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init with coder not implemented")
    }
}

В этом примере метод init? (Кодер) выдает исключение. Этот инициализатор запускается создателем интерфейса при разархивировании содержимого Storyboard или Nib. Поскольку он вам не понадобится, вы можете просто сгенерировать fatalError (поскольку этот метод должен быть реализован для успешной компиляции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...