何时在ViewControlller上使用View

时间:2019-01-02 15:08:49

标签: swift uiview uiviewcontroller

我想知道在确定一个类必须是UIview或UIviewcontroller时的最佳实践是什么。

我正在开发一个在单个Viewcontroller中一次使用多个类和视图的应用程序。我有一个动态创建按钮的视图。该视图与ViewController中的许多其他视图并存。由于此视图实现了很多行代码,因此我将其置于单独的类中。那么问题是:应该扩展UiView还是UIViewcontroller?

此视图将具有一些属性,例如填充,可用尺寸等。这些属性取决于其子类ViewViewler的自动布局锚点。如果我使用UIview,这些将不会在Init上实例化。

为什么我应该选择一个?

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 :(得分:0)

我喜欢这样想:UIView托管和管理离散内容,而UIViewController托管和管理由许多离散内容组成的应用程序内容。

您可以从桌面应用程序来思考它,其中“窗口”是UIViewController,而此窗口的元素(按钮,工具栏等)是UIViews(您也可以在UIViewControllers内托管其他UIViewController

通常,UIViews不应决定应用程序导航逻辑,而应将其推迟到UIViewController

简单来说,如果某些内容以模态呈现或占据整个屏幕,则可能是UIViewController

传统上,Apple采用MVC范例(模型/视图/控制器)。如果您的内容是模型(一个人的出生日期,您拍摄的照片),则在其中显示视图,而Controller在内容管理(持久性,检索)和内容的显示之间进行调解。

顺便说一句:在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?(coder)方法引发异常。取消存档Storyboard或Nib内容时,此初始值设定程序由界面构建器运行。由于您不需要它,因此可以抛出致命错误(因为必须实现该方法才能使编译成功)。