簡體   English   中英

以編程方式在 UIScrollView 中安裝 UIStackView

[英]Fitting UIStackView in UIScrollView programmatically

我將stackView 添加到scrollView。 我將 scrollView 的寬度、X 和 Y 約束設置為與主視圖相同,固定高度為 50。對於堆棧約束,我做了同樣的事情,但相對於 scrollView 而不是視圖。

我的問題是當我將 UIImageViews 添加到我的堆棧時(所有圖像都是 50 x 50)。 我需要堆棧僅顯示前三個 UIImageView,如果超過 3 個則水平滾動。到目前為止,我的堆棧始終顯示所有 UIImageView。

任何建議表示贊賞。 現在已經為此工作了2天。 謝謝!

你可能想做的事...

  • 將堆棧視圖的所有 4 面約束到滾動視圖的內容布局指南
  • 約束堆棧視圖的高度等於滾動視圖的框架布局指南的高度
  • 不要限制堆棧視圖的寬度
  • 將堆棧視圖的分布設置為填充

創建一個“選項卡視圖”——這是一個帶有50 x 50居中圖像視圖、圓角頂角和 1-pt 輪廓的示例:

在此處輸入圖像描述

我們可以用這個簡單的 class 創建它:

class MyTabView: UIView {
    
    let imgView = UIImageView()
    
    init(with image: UIImage) {
        super.init(frame: .zero)
        imgView.image = image
        commonInit()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        imgView.translatesAutoresizingMaskIntoConstraints = false
        // light gray background
        backgroundColor = UIColor(white: 0.9, alpha: 1.0)
        addSubview(imgView)
        NSLayoutConstraint.activate([
            // centered
            imgView.centerXAnchor.constraint(equalTo: centerXAnchor),
            imgView.centerYAnchor.constraint(equalTo: centerYAnchor),
            // 50x50
            imgView.widthAnchor.constraint(equalToConstant: 50.0),
            imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor),
        ])
        
        // a little "styling" for the "tab"
        clipsToBounds = true
        layer.cornerRadius = 12
        layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        layer.borderWidth = 1
        layer.borderColor = UIColor.darkGray.cgColor
    }

}

對於我們添加到堆棧視圖的每個“選項卡”,我們將設置其寬度約束等於滾動視圖的框架布局指南widthAnchor multiplier: 1.0 / 3.0 這樣每個“標簽視圖”將是滾動視圖寬度的 1/3:

在此處輸入圖像描述

在此處輸入圖像描述

在此處輸入圖像描述

使用 1、2 或 3 個“標簽”將不會有水平滾動,因為它們都適合框架。

一旦我們有超過 3 個“選項卡”,堆棧視圖的寬度將超過框架的寬度,我們將進行水平滾動:

在此處輸入圖像描述

這是我用於此的視圖 controller。 它創建 9 個“標簽圖像”......從一個“標簽”開始......每次點擊都會添加一個“標簽”,直到我們擁有全部 9 個標簽,此時每次點擊都會刪除一個“標簽”:

class StackAsTabsViewController: UIViewController {
    
    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .horizontal
        v.distribution = .fill
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    // a label to show what's going on
    let statusLabel: UILabel = {
        let v = UILabel()
        v.numberOfLines = 0
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    // array to hold our "tab" images
    var images: [UIImage] = []

    // we'll add a "tab" on each tap
    //  until we reach the end of the images array
    //  then we'll remove a "tab" on each tap
    //  until we're back to a single "tab"
    var isAdding: Bool = true

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // add the "status" label
        view.addSubview(statusLabel)
        
        // add stackView to scrollView
        scrollView.addSubview(stackView)
        
        // add scrollView to view
        view.addSubview(scrollView)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        // scrollView Content and Frame Layout Guides
        let contentG = scrollView.contentLayoutGuide
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain scrollView Top / Leading / Trailing
            scrollView.topAnchor.constraint(equalTo: g.topAnchor),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            
            // height = 58 (image will be 50x50, so a little top and bottom padding)
            scrollView.heightAnchor.constraint(equalToConstant: 58.0),
            
            // constrain stackView all 4 sides to scrollView Content Layout Guide
            stackView.topAnchor.constraint(equalTo: contentG.topAnchor),
            stackView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor),
            
            // stackView Height equal to scrollView Frame Height
            stackView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
            
            // statusLabel in the middle of the view
            statusLabel.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 40.0),
            statusLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            statusLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0)
            
        ])
        
        // let's create 9 images using SF Symbols
        for i in 1...9 {
            guard let img = UIImage(systemName: "\(i).circle.fill") else {
                fatalError("Could not create images!!!")
            }
            images.append(img)
        }
        
        // add the first "tab view"
        self.updateTabs()
        
        // tap anywhere in the view
        let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
        view.addGestureRecognizer(t)

    }
    
    @objc func gotTap(_ g: UITapGestureRecognizer) -> Void {
        updateTabs()
    }
    
    func updateTabs() -> Void {
        
        if isAdding {

            // get the next image from the array
            let img = images[stackView.arrangedSubviews.count]
            
            // create a "tab view"
            let tab = MyTabView(with: img)
            // add it to the stackView
            stackView.addArrangedSubview(tab)
            let frameG = scrollView.frameLayoutGuide
            NSLayoutConstraint.activate([
                // each "tab view" is 1/3rd the width of the scroll view frame
                tab.widthAnchor.constraint(equalTo: frameG.widthAnchor, multiplier: 1.0 / 3.0),
                // each "tab view" is the same height as the scroll view frame
                tab.heightAnchor.constraint(equalTo: frameG.heightAnchor),
            ])

        } else {

            stackView.arrangedSubviews.last?.removeFromSuperview()

        }

        if stackView.arrangedSubviews.count == 1 {
            isAdding = true
        } else if stackView.arrangedSubviews.count == images.count {
            isAdding = false
        }
        
        updateStatusLabel()
        
    }
    
    func updateStatusLabel() -> Void {
        
        // we'll do this async, to make sure the views have been updated
        DispatchQueue.main.async {
            let numTabs = self.stackView.arrangedSubviews.count
            var str = ""
            if self.isAdding {
                str += "Tap anywhere to ADD a tab"
            } else {
                str += "Tap anywhere to REMOVE a tab"
            }
            str += "\n\n"
            str += "Number of tabs: \(numTabs)"
            str += "\n\n"
            if numTabs > 3 {
                str += "Tabs WILL scroll"
            } else {
                str += "Tabs will NOT scroll"
            }
            self.statusLabel.text = str
        }
        
    }

}

玩它,看看這是不是你想要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM