如何在 Swift、UIKit 中制作滚动

问题描述 投票:0回答:1

我制作了这个应用程序,如上图所示。但滚动不起作用。我想让scrollView完全向下。

我问了一个与此相关的问题,我已经工作了。 但我需要做一些功能,而策略是......

  1. 设置视图(顺序为标题标签、日期标签、图像标签(选项)、文章标签)。
  2. 锚点遵循上面的视图,如下所示:
    NSLayoutConstraint.activate([...topAnchor...(equalTo: aboveView.bottomAnchor, constrant: 20)
  3. scrollView 和 UIView(Container) 的高度将在设置视图高度联合后更新。

代码如下。所有视图都是通过代码设置的。

DetailViewController.Swift

import UIKit

class DetailViewController: UIViewController {
    
    private let titleLabel: UILabel = {
        let view = UILabel()
        view.numberOfLines = 2
        return view
    }()
    
    private let dateLabel: UILabel = {
        let view = UILabel()
        return view
    }()
    
    private let scroll: UIScrollView = {
        let scroll = UIScrollView()
        scroll.backgroundColor = .brown
        return scroll
    }()
    
    private let container: UIView = {
        let container = UIView()
        container.backgroundColor = .lightGray
        return container
    }()
    
    private let image: UIImageView = {
        let image = UIImageView()
        return image
    }()
    
    private let controller: UIPageControl = {
        let controller = UIPageControl()
        return controller
    }()
    
    private let content: UITextView = {
        let content = UITextView()
        return content
    }()
    
    var fileName: String!
    var id: String!
    var entryNumber: Int!
    var dataSize: Int!
    var entry: Entry!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        // Get contents id and parse file name
        parsingFileName(id: id)
                
        addScrollView()
        scroll.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
        
        addTopLabels()
        
        content.text = entry. Article
        
        // isImage is true or false
        addContent(isImage: entry.isImage)
        
        // For debugging
        content.backgroundColor = .yellow
        scroll.updateContentSize()
        content.contentSize = CGSize(width: self.scroll.frame.width, height: self.scroll.frame.height)
        
    }

}

扩展1:Union函数

extension UIScrollView {
    func updateContentSize() {
        let unionTotal = recursiveUnion(view: self)
        
        self.contentSize = CGSize(width: self.frame.width, height: unionTotal.height + 50)
    }
    
    private func recursiveUnion(view: UIView) -> CGRect {
        var totalRect: CGRect = .zero
        
        for v in view.subviews {
            totalRect = totalRect.union(recursiveUnion(view: v))
        }
        print("Updated content Size: \(totalRect.union(view.frame))")
        return totalRect.union(view.frame)
    }
}

扩展2:设置视图和约束

extension DetailViewController {
    
    fileprivate func parsingFileName(id: String) {
        // parse ID and get filename
        // ref.: https://ssooyn.tistory.com/22
        let s = id.index(id.startIndex, offsetBy: 0)
        let e = id.index(id.startIndex, offsetBy: 7)
        let r = s...e
        
        fileName = "entry-" + String(id[r])
        let dataFromFile = DataLoader(fileName: fileName, fileType: ".json").entry
        
        // Find the entry
        for i in 0 ..< dataFromFile.count {
            if dataFromFile[i].id == id {
                entry = dataFromFile[i]
                break
            }
        }
    }
    
    fileprivate func addScrollView() {
        // Setting views - ScrollView and Container
        view.addSubview(scroll)
        scroll.translatesAutoresizingMaskIntoConstraints = false
        
        scroll.addSubview(container)
        container.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            scroll.topAnchor.constraint(equalTo: self.view.topAnchor),
            scroll.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            scroll.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            scroll.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            
            container.topAnchor.constraint(equalTo: self.scroll.topAnchor),
            container.bottomAnchor.constraint(equalTo: self.scroll.bottomAnchor),
            container.leadingAnchor.constraint(equalTo: self.scroll.leadingAnchor),
            container.trailingAnchor.constraint(equalTo: self.scroll.trailingAnchor),
            
            container.widthAnchor.constraint(equalTo: self.scroll.widthAnchor, multiplier: 1),
            container.heightAnchor.constraint(equalTo: self.scroll.heightAnchor, multiplier: 1)
        ])
    }
 
    fileprivate func addTopLabels() {
        // Setting Views - Top Labels

        titleLabel.textAlignment = .left
        titleLabel.text = entry.title
        titleLabel.font = UIFont(name: "Pretendard-SemiBold", size: 17)
        
        dateLabel.textAlignment = .right
        dateLabel.text = String(entry.year) + "." + String(entry.month) + "." + String(entry.day)
        
        container.addSubview(titleLabel)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        
        container.addSubview(dateLabel)
        dateLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: container.topAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            titleLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor),
            titleLabel.heightAnchor.constraint(equalToConstant: 20),
            titleLabel.widthAnchor.constraint(equalTo: container.widthAnchor),
            
            dateLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor),
            dateLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            dateLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor),
            dateLabel.heightAnchor.constraint(equalToConstant: 20),
            dateLabel.widthAnchor.constraint(equalTo: container.widthAnchor),
        ])
    }
    
    fileprivate func addContent(isImage: Bool) {
        if isImage == false {
            print("No Image")
            image.backgroundColor = .darkGray
            image.isHidden = true
            
            container.addSubview(content)
            content.translatesAutoresizingMaskIntoConstraints = false
            content.sizeToFit()
            content.isScrollEnabled = false
            
            NSLayoutConstraint.activate([
                content.topAnchor.constraint(equalTo: dateLabel.bottomAnchor, constant: 20),
                content.leadingAnchor.constraint(equalTo: container.leadingAnchor),
                content.trailingAnchor.constraint(equalTo: container.trailingAnchor),
//                content.bottomAnchor.constraint(equalTo: container.bottomAnchor),
                
                content.heightAnchor.constraint(equalTo: container.heightAnchor),
                content.widthAnchor.constraint(equalTo: container.widthAnchor),
            ])
        } else {
            print("There a image")
            image.backgroundColor = .red
            image.image = UIImage(named: "202310172204-1-1.jpeg")
            
            container.addSubview(image)
            content.translatesAutoresizingMaskIntoConstraints = false
            content.sizeToFit()
            content.isScrollEnabled = false
            
            container.addSubview(content)
            image.translatesAutoresizingMaskIntoConstraints = false
            
            print(content.contentSize.height)
            
            NSLayoutConstraint.activate([
                image.topAnchor.constraint(equalTo: dateLabel.bottomAnchor, constant: +20),
                image.leadingAnchor.constraint(equalTo: container.leadingAnchor),
                image.trailingAnchor.constraint(equalTo: container.trailingAnchor),
                image.heightAnchor.constraint(equalTo: container.widthAnchor),
                image.widthAnchor.constraint(equalTo: container.widthAnchor),
                
                content.topAnchor.constraint(equalTo: image.bottomAnchor, constant: +20),
                content.leadingAnchor.constraint(equalTo: container.leadingAnchor),
                content.trailingAnchor.constraint(equalTo: container.trailingAnchor),
//                content.bottomAnchor.constraint(equalTo: container.bottomAnchor),
                content.heightAnchor.constraint(equalTo: container.heightAnchor),
                content.widthAnchor.constraint(equalTo: container.widthAnchor),
            ])
        }
    }
}

感谢您阅读长篇故事和代码。 :) 祝你有美好的一天!

ios swift scroll uikit
1个回答
0
投票

首先,你做了很多不必要的事情......

其次,练习以“可读”的方式命名属性/对象/等,例如

content
不会告诉您(或查看您代码的其他人)它是什么。使用
contentTextView
是显而易见的。

第三,从简单开始 - 尤其是在你学习的时候。

看一下这段代码:

class DetailViewController: UIViewController {
    
    private let titleLabel: UILabel = {
        let view = UILabel()
        view.numberOfLines = 2
        return view
    }()
    
    private let dateLabel: UILabel = {
        let view = UILabel()
        return view
    }()
    
    private let scrollView: UIScrollView = {
        let scroll = UIScrollView()
        scroll.backgroundColor = .brown
        return scroll
    }()
    
    private let topImageView: UIImageView = {
        let image = UIImageView()
        return image
    }()
    
    private let contentTextView: UITextView = {
        let content = UITextView()
        content.isScrollEnabled = false
        return content
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
        
        titleLabel.text = "This is the Title Label"
        
        //image.image = UIImage(named: "202310172204-1-1.jpeg")
        if let img = UIImage(systemName: "swift") {
            topImageView.image = img
        }

        dateLabel.text = "This is the Date Label"

        // let's create a string of 50 lines for the "content" text field
        var sTemp: String = "Line 1"
        for i in 2...50 {
            sTemp += "\nLine \(i)"
        }
        contentTextView.text = sTemp

        // let's put all those elements into a vertical UIStackView
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 8
        
        [titleLabel, topImageView, dateLabel, contentTextView].forEach { v in
            stackView.addArrangedSubview(v)
        }
        
        // top image view needs a height constraint
        topImageView.heightAnchor.constraint(equalToConstant: 160.0).isActive = true
        
        // add the stack view to the scroll view
        stackView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(stackView)
        
        // add the scroll view to self's view
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)
        
        let g = view.safeAreaLayoutGuide
        let cg = scrollView.contentLayoutGuide
        let fg = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain all 4 sides of scroll view
            //  we'll inset by 20-points so we can see the framing
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),

            // constrain all 4 sides of stack view
            //  to the scroll view's Content Layout Guide
            //  we'll inset by 12-points so we can see the framing
            stackView.topAnchor.constraint(equalTo: cg.topAnchor, constant: 12.0),
            stackView.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 12.0),
            stackView.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -12.0),
            stackView.bottomAnchor.constraint(equalTo: cg.bottomAnchor, constant: -12.0),

            // we'll make the stack view width 24-points less than
            //  the scroll view's Frame Layout Guide
            //  (24 because we have 12-points on each side)
            stackView.widthAnchor.constraint(equalTo: fg.widthAnchor, constant: -24.0),

        ])
        
        // let's set some background colors so we can see the framing
        titleLabel.backgroundColor = .cyan
        topImageView.backgroundColor = .red
        dateLabel.backgroundColor = .green
        contentTextView.backgroundColor = .yellow

        // let's use a larger font for the content text view
        //  for demonstration purposes
        contentTextView.font = .systemFont(ofSize: 20.0, weight: .light)
    }
    
}

结果如下:

绝对不需要“计算尺寸”...所需的约束少得多...一切都按预期滚动...等等。

© www.soinside.com 2019 - 2024. All rights reserved.