有没有相当于 SwiftUI 的 zstack 的 UIKit?

发布于 2025-01-13 09:47:17 字数 539 浏览 1 评论 0原文

我正在尝试创建类似 this 的内容。我最近一直在使用 SwiftUI,所以我知道我可以通过向 zstack 添加图像、文本和按钮(我是灵活的文本是按钮/NavigationLink 的标签)来创建它。但我正在四处寻找,看看是否有办法在 UIKit 中做到这一点。最好不使用故事板。我对 cocoapods 库或其他库持开放态度,如果需要的话。我环顾四周并探索了使用 SwiftUI 创建所需的 ZStack,然后在我的 UIKit 中使用 UIHostingController,但因为它涉及按钮/导航链接。鉴于 NavigationLink 如何要求目的地符合视图,我想在将我的项目的更多内容转换为 swiftui 之前询问一下。我更希望这个项目能给我更多在 UIKit 中构建视图而无需故事板的经验,所以我更愿意这样做而不是使用 SwiftUI。如果可能的话我想。

我尝试过四处搜索,但所有涉及 UIButtons 和图像的 Google 搜索都只是链接到有关在 UIButton 中设置图像的帖子。

I'm trying to create something like this. I've been working with SwiftUI recently so I know I could create that by adding an image, text and button (the I'm flexible text is the label for a button/NavigationLink) to a zstack. but I'm looking around trying to see if there's anyway to do that in UIKit. preferably without using storyboards. I'm open to a cocoapods library or whatever if that's what it takes. I've looked around and explored using SwiftUI to create the desired ZStack and then use it in my UIKit with a UIHostingController but because it involves a button/navigationlink. seeing as how the NavigationLink would require the destination to conform to a View, I wanted to ask around before converting even more of my project to swiftui. I was more hoping this project would be for giving me more experience building views in UIKit without storyboards so I'd prefer to do that instead of using SwiftUI. if that's possible I guess.

I've tried searching around but all my google searches involving UIButtons and images just link to posts about setting the image in a UIButton.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

那些过往 2025-01-20 09:47:17

由于您希望获得更多使用 UIKit 创建视图的经验,因此我创建了一个继承自 UIView 的视图,您可以重用该视图。在 UIKit 中有相当多的代码可以得到相同的结果。下面提供了代码和输出。

注意:阅读提供的注释

代码

class ImageCardWithButton: UIView {

    lazy var cardImage: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false // To flag that we are using Constraints to set the layout
        image.image = UIImage(named: "dog")
        image.contentMode = .scaleAspectFill
        return image
    }()

    lazy var gradientView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false // IMPORTANT IF YOU ARE USING CONSTRAINTS INSTEAD OF FRAMES
        return view
    }()

    // VStack equivalent in UIKit
    lazy var contentStack: UIStackView = {
        let stack = UIStackView()
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .vertical
        stack.distribution = .fillProportionally // Setting the distribution to fill based on the content
        return stack
    }()

    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        label.numberOfLines = 0 // Setting line number to 0 to allow sentence breaks
        label.text = "Let your curiosity do the booking"
        label.font = UIFont(name: "Raleway-Semibold", size: 20) // Custom font defined for the project
        label.textColor = .white
        return label
    }()

    lazy var cardButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .white
        button.setTitle("I'm flexible", for: .normal)
        button.setTitleColor(.blue, for: .normal)
//        button.addTarget(self, action: #selector(someObjcMethod), for: .touchUpInside) <- Adding a touch event and function to invoke
        return button
    }()

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

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        self.addSubview(cardImage) // Adding the subview to the current view. i.e., self

        // Setting the corner radius of the view
        self.layer.cornerRadius = 10
        self.layer.masksToBounds = true

        NSLayoutConstraint.activate([
            cardImage.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            cardImage.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            cardImage.topAnchor.constraint(equalTo: self.topAnchor),
            cardImage.bottomAnchor.constraint(equalTo: self.bottomAnchor),
        ])

        setupGradientView()
        addTextAndButton()
    }

    private func setupGradientView() {
        let height = self.frame.height * 0.9 // Height of the translucent gradient view

        self.addSubview(gradientView)
        NSLayoutConstraint.activate([
            gradientView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            gradientView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            gradientView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            gradientView.heightAnchor.constraint(equalToConstant: height)
        ])

        // Adding the gradient
        let colorTop =  UIColor.clear
        let colorBottom = UIColor.black

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.locations = [0.0, 1.0]
        gradientLayer.frame = CGRect(
            x: 0,
            y: self.frame.height - height,
            width: self.frame.width,
            height: height)
        gradientView.layer.insertSublayer(gradientLayer, at:0)
        print(self.frame)
    }

    private func addTextAndButton() {

        // Adding the views to the stackview
        contentStack.addArrangedSubview(titleLabel)
        contentStack.addArrangedSubview(cardButton)

        gradientView.addSubview(contentStack)
        NSLayoutConstraint.activate([
            contentStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20),
            contentStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20),    // Negative for leading and bottom constraints
            contentStack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -20),        // Negative for leading and bottom constraints

            cardButton.heightAnchor.constraint(equalToConstant: 60)
        ])

        cardButton.layer.cornerRadius = 30 // Half of the height of the button
    }

}

输出

在此处输入图像描述

重要提示

  1. 您可以使用约束或框架创建布局。如果您使用约束,请将视图 .translatesAutoresizingMaskIntoConstraints 设置为 false 重要(您可以阅读其文档)。

  2. NSLayoutConstraint.activate([...]) 用于一次应用一组约束。或者,您可以使用:

cardImage.leadingAnchor.constraint(...)isActivated = true

对于单独的约束

  1. 视图的手动布局有时需要填充。因此,为此,您必须根据您所在视图的边缘(侧面)使用负或正的填充值。很容易记住在视图中心的方向设置填充值。

例如,从前缘/左边缘,您需要向视图中心添加 10 的填充,或从右/尾侧向中心添加 -10 的填充。

since you wanted to get more experience in creating views using UIKit, I've created a view that inherits from UIView that you can reuse. There's quite a lot of code to get the same result in UIKit. The code and output are provided below.

NOTE: Read the comments provided

Code

class ImageCardWithButton: UIView {

    lazy var cardImage: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false // To flag that we are using Constraints to set the layout
        image.image = UIImage(named: "dog")
        image.contentMode = .scaleAspectFill
        return image
    }()

    lazy var gradientView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false // IMPORTANT IF YOU ARE USING CONSTRAINTS INSTEAD OF FRAMES
        return view
    }()

    // VStack equivalent in UIKit
    lazy var contentStack: UIStackView = {
        let stack = UIStackView()
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .vertical
        stack.distribution = .fillProportionally // Setting the distribution to fill based on the content
        return stack
    }()

    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        label.numberOfLines = 0 // Setting line number to 0 to allow sentence breaks
        label.text = "Let your curiosity do the booking"
        label.font = UIFont(name: "Raleway-Semibold", size: 20) // Custom font defined for the project
        label.textColor = .white
        return label
    }()

    lazy var cardButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .white
        button.setTitle("I'm flexible", for: .normal)
        button.setTitleColor(.blue, for: .normal)
//        button.addTarget(self, action: #selector(someObjcMethod), for: .touchUpInside) <- Adding a touch event and function to invoke
        return button
    }()

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

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        self.addSubview(cardImage) // Adding the subview to the current view. i.e., self

        // Setting the corner radius of the view
        self.layer.cornerRadius = 10
        self.layer.masksToBounds = true

        NSLayoutConstraint.activate([
            cardImage.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            cardImage.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            cardImage.topAnchor.constraint(equalTo: self.topAnchor),
            cardImage.bottomAnchor.constraint(equalTo: self.bottomAnchor),
        ])

        setupGradientView()
        addTextAndButton()
    }

    private func setupGradientView() {
        let height = self.frame.height * 0.9 // Height of the translucent gradient view

        self.addSubview(gradientView)
        NSLayoutConstraint.activate([
            gradientView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            gradientView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            gradientView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            gradientView.heightAnchor.constraint(equalToConstant: height)
        ])

        // Adding the gradient
        let colorTop =  UIColor.clear
        let colorBottom = UIColor.black

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.locations = [0.0, 1.0]
        gradientLayer.frame = CGRect(
            x: 0,
            y: self.frame.height - height,
            width: self.frame.width,
            height: height)
        gradientView.layer.insertSublayer(gradientLayer, at:0)
        print(self.frame)
    }

    private func addTextAndButton() {

        // Adding the views to the stackview
        contentStack.addArrangedSubview(titleLabel)
        contentStack.addArrangedSubview(cardButton)

        gradientView.addSubview(contentStack)
        NSLayoutConstraint.activate([
            contentStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20),
            contentStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20),    // Negative for leading and bottom constraints
            contentStack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -20),        // Negative for leading and bottom constraints

            cardButton.heightAnchor.constraint(equalToConstant: 60)
        ])

        cardButton.layer.cornerRadius = 30 // Half of the height of the button
    }

}

Output

enter image description here

Important pointers

  1. You can create the layout using constraints or frames. In case you are using constraints, it is important to set a views .translatesAutoresizingMaskIntoConstraints to false (You can read the documentation for it).

  2. NSLayoutConstraint.activate([...]) Is used to apply an array of constraints at once. Alternatively, you can use:

cardImage.leadingAnchor.constraint(...)isActivated = true

for individual constraints

  1. Manual layout of the views will sometimes require padding. So for this you will have to use negative or positive values for the padding based on the edge (side) of the view you are in. It's easy to remember to set the value of the padding in the direction of the centre of the view.

E.x., From the leading/left edge, you will need to add a padding of 10 towards the centre of the view or -10 from the right/trailing side towards the centre.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文