iOS

代码思维方式

创建视图的一种思维方式

920 发布: 2025/1/16 10:00 本文总阅读量

控制器

import UIKit

class AutoSizingViewController: UIViewController {
    // 自定义视图
    private var mainView: AutoSizingView {
        return self.view as! AutoSizingView
    }
    // 将自定义视图赋值给控制器的view
    override func loadView() {
        self.view = AutoSizingView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        configureNavigationBar()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        randomizeContent()
    }

    private func configureNavigationBar() {
        navigationItem.title = "AutoSizing"
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Randomize", style: .plain, target: self, action: #selector(randomizeContent))
    }

    @objc
    private func randomizeContent() {
        // 网络请求给视图的属性赋值【mainView】
        ContentService.shared.fetchText(numberOfParagraph: 2) { [weak self] (result) in
            guard let strongSelf = self, case let .success(paragraphs) = result else { return }
            strongSelf.mainView.updateTexts(firstText: paragraphs[0], secondText: paragraphs[1])
        }

        ContentService.shared.fetchImage(width: Int.random(in: 200..<500), height: Int.random(in: 200..<500)) { [weak self] (result) in
            guard let strongSelf = self, case let .success(image) = result else { return }
            strongSelf.mainView.updateImage(image)
        }
    }
}

自定义视图

AutoSizingView

import UIKit
import PinLayout

final class AutoSizingView: UIView {
    private let scrollView = UIScrollView()
    private let containerView = AutoSizingContainerView()

    private let margin: CGFloat = 30

    init() {
        super.init(frame: CGRect.zero)
        configureView()
    }

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

    private func configureView() {
        backgroundColor = .white

        scrollView.alwaysBounceVertical = true
        addSubview(scrollView)
        
        containerView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3)
        scrollView.addSubview(containerView)
    }

    func updateImage(_ image: UIImage?) {
        containerView.image = image
        setNeedsLayout()
    }

    func updateTexts(firstText: String?, secondText: String?) {
        containerView.firstText = firstText
        containerView.secondText = secondText
        setNeedsLayout()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        performLayout()
        didPerformLayout()
    }

    private func performLayout() {
        scrollView.pin.all()
        containerView.pin.top(margin).horizontally(margin).sizeToFit(.width)
    }

    private func didPerformLayout() {
        scrollView.contentSize = CGSize(width: bounds.width, height: containerView.frame.maxY + margin)
    }
}

AutoSizingContainerView

import UIKit

final class AutoSizingContainerView: UIView {
    private let imageView = UIImageView()
    private let firstTextLabel = UILabel()
    private let secondTextLabel = UILabel()

    private let margin: CGFloat = 10

    var image: UIImage? {
        didSet {
             imageView.image = image
        }
    }

    var firstText: String? {
        didSet {
            firstTextLabel.text = firstText
        }
    }

    var secondText: String? {
        didSet {
            secondTextLabel.text = secondText
        }
    }

    init() {
        super.init(frame: CGRect.zero)
        configureView()
    }

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

    private func configureView() {
        imageView.clipsToBounds = true
        imageView.contentMode = .scaleAspectFill
        addSubview(imageView)

        firstTextLabel.numberOfLines = 0
        firstTextLabel.backgroundColor = UIColor.orange.withAlphaComponent(0.3)
        addSubview(firstTextLabel)

        secondTextLabel.numberOfLines = 0
        secondTextLabel.backgroundColor = UIColor.green.withAlphaComponent(0.3)
        addSubview(secondTextLabel)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        performLayout()
    }

    private func performLayout() {
        imageView.pin.top().horizontally().sizeToFit(.width).margin(margin)
        firstTextLabel.pin.below(of: imageView).horizontally().sizeToFit(.width).margin(margin)
        secondTextLabel.pin.below(of: firstTextLabel).horizontally().sizeToFit(.width).margin(margin)
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        autoSizeThatFits(size, layoutClosure: performLayout)
    }
}