簡體   English   中英

Swift 中一個垂直 ScrollView 中的多個水平 ScrollView?

[英]Multiple Horizontal ScrollViews In One Vertical ScrollView in Swift?

我正在嘗試在 Swift 的應用程序中實現最標准的布局之一。

這基本上是在一個垂直滾動視圖中包含多個水平滾動視圖。

這些子水平滾動視圖中的每一個都將包含一些帶有圖像的視圖。

是這樣的:

在此處輸入圖像描述

實現這一目標的最佳方式是什么?

PS 我需要使用代碼來執行此操作,因為內容是通過遠程 JSON 文件提取的。

任何指針將不勝感激。

我會做以下事情。

  1. UITableView用於垂直滾動視圖。
class TableViewController: UITableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
        self.tableView.register(TableViewHeader.self, forHeaderFooterViewReuseIdentifier: TableViewHeader.identifier)
        
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }
}


extension TableViewController {
    
   override func numberOfSections(in tableView: UITableView) -> Int {
        return 10
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier,
                                                 for: indexPath) as! TableViewCell
        return cell
    }
}


extension TableViewController {
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 250
    }
    
    override  func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: TableViewHeader.identifier)
        header?.textLabel?.text = "Header \(section)"
        return header
    }
    
    
    override   func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50
    }
}


  1. UICollectionView用於水平滾動視圖。
class CollectionView: UICollectionView {
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        self.backgroundColor = .white
        self.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
        
        self.dataSource = self
        self.delegate = self
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


extension CollectionView: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    
    func collectionView(_ collectionView: UICollectionView,
                        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier,
                                                      for: indexPath) as! CollectionViewCell
        cell.index = indexPath.row
        return cell
    }
}



extension CollectionView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 200, height: 250)
    }
    
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 20
    }
    
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
}


class CollectionViewCell: UICollectionViewCell {
    static let identifier = "CollectionViewCell"
    
    var index: Int? {
        didSet {
            if let index = index {
                label.text = "\(index)"
            }
        }
    }
    
    private let label: UILabel = {
        let label = UILabel()
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentView.backgroundColor = .red
        self.contentView.addSubview(label)

        let constraints = [
            label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor)
        ]

        NSLayoutConstraint.activate(constraints)

        label.translatesAutoresizingMaskIntoConstraints = false
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}


  1. 每個UITableViewCell包含一個UICollectionView (水平滾動視圖)。
class TableViewCell: UITableViewCell {
    static let identifier = "TableViewCell"
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.backgroundColor = .white
        
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        

        let subView = CollectionView(frame: .zero, collectionViewLayout: layout)

        self.contentView.addSubview(subView)

        let constraints = [
            subView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 1),
            subView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 1),
            subView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 1),
            subView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 1)
        ]

        NSLayoutConstraint.activate(constraints)

        subView.translatesAutoresizingMaskIntoConstraints = false
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


  1. 使用UITableViewHeaderFooterView ( tableView(_:viewForHeaderInSection:) ) 作為水平滾動視圖的標題

class TableViewHeader: UITableViewHeaderFooterView {
    static let identifier = "TableViewHeader"
}

我添加的代碼是一個完整的工作示例。 只需使用TableViewController就可以達到 go。


更新

UITableViewCells 應該有動態的單元格高度。

測試后,我發現最好使用固定單元格大小而不是動態單元格大小,因為單元格可能具有不同的高度,應使用UITableView.automaticDimension

使用 SwiftUI 非常簡單。對於垂直視圖,您應該在 ScrollView 中使用 VStack; 和水平的 ScrollView 內的 HStack。

這是一個例子:

struct ContentView: View {
    var body: some View {
        ScrollView{
            ForEach(0..<10) {_ in 
                VStack{
                    ScrollView(.horizontal){
                        HStack(spacing: 20) {
                            ForEach(0..<10) {
                                Text("Item \($0)")
                                    .font(.headline)
                                    .frame(width: 100, height: 100)
                                    .background(Color.gray)
                            }
                        }
                    }
                }
            }
        }
    }
}

我制作了一個ForEach來復制每個堆棧中的示例項目,但您應該將它們替換為您的自定義視圖或內容。 在您上傳的圖片中,每個項目都是一個帶有圖像和文本的 ZStack。

編譯代碼的圖像

  1. 為主 ViewController 創建一個UITableView

  2. 您必須在其中創建的視圖使其成為單獨的 ViewController。

     For ex:- for mental fitness - Create separate mental fitness ViewController for that for sleep stories - Create separate Sleep Stories ViewController
  3. 現在高潮來到這里調用addChild()方法。

在主 ViewController class 中訪問所有 ViewController,並將它們添加到addChild()方法內的viewDidLoad( ) 方法中。

  1. 您要做的最后一件事是您只需將子 ViewControllers 添加到您的特定單元格中作為view

作為參考,您可以查看這些示例:-

https://www.hackingwithswift.com/example-code/uikit/how-to-use-view-controller-containment

https://www.swiftbysundell.com/basics/child-view-controllers/

優勢:-

  • 這樣您就可以輕松管理來自服務器的數據

例如:-

 import UIKit

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

//subViewControllers
let firstVC = FirstViewController()
let secondVC = SecondViewController()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    
    self.addChild(firstVC) //adding childVC here
    self.addChild(secondVC)

}


}

UITableViewDataSource 和委托方法

extension ViewController: UITableViewDelegate, UITableViewDataSource {



func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    return 10
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    
    return 250
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? MainCell else {
        
        return UITableViewCell()
    }
    
    if indexPath.row == 0 {
        

        cell.contentView.addSubview(firstVC.view)
                    
    }
    
    if indexPath.row == 1 {
         
        cell.contentView.addSubview(secondVC.view)

    }
    
    return cell
}





 }

UITableViewCell Class

class MainCell: UITableViewCell {



}

UITableViewCell 類

這樣您就可以輕松管理來自服務器的數據。 因為它會給你一個優勢,可以在單獨的 ViewController 中顯示特定的單元格數據等等。

暫無
暫無

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

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