Ios 在可滚动列表中快速添加项目

Ios 在可滚动列表中快速添加项目,ios,swift,listview,uiscrollview,Ios,Swift,Listview,Uiscrollview,现在,这就是我在项目中的全部内容: 最后,它的外观和功能应该如下所示: 1.如何将项目添加到ScrollView中(在2x视图中) 2.我如何使ScrollView能够真正滚动(并像下面的3张图片一样刷新),或者仅仅通过一个列表就可以解决这个问题 更新 最终视图应如下所示: “MainWishList”单元格和“neue Liste erstellen”(=添加新单元格)应该从一开始就存在。当用户单击“添加单元格”时,他应该能够为列表选择名称和图像 UICollectionView的内置功

现在,这就是我在项目中的全部内容:

最后,它的外观和功能应该如下所示:

1.如何将项目添加到ScrollView中(在2x视图中)

2.我如何使ScrollView能够真正滚动(并像下面的3张图片一样刷新),或者仅仅通过一个列表就可以解决这个问题

更新

最终视图应如下所示:


“MainWishList”单元格和“neue Liste erstellen”(=添加新单元格)应该从一开始就存在。当用户单击“添加单元格”时,他应该能够为列表选择名称和图像

UICollectionView的内置功能的一部分是,当您拥有的项目(单元格)超过了框架所能容纳的数量时,自动滚动。因此,不需要在滚动视图中嵌入集合视图

这是一个基本的例子。一切都是通过代码完成的(没有
@IBOutlet
@IBAction
或原型单元)。创建一个新的
UIViewController
,并将其类分配给
ExampleViewController
,如下所示:

//
//  ExampleViewController.swift
//  CollectionAddItem
//
//  Created by Don Mag on 10/22/19.
//

import UIKit

// simple cell with label
class ContentCell: UICollectionViewCell {

    let theLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.textAlignment = .center
        return v
    }()

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

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

    func commonInit() -> Void {
        contentView.backgroundColor = .yellow
        contentView.addSubview(theLabel)
        // constrain label to all 4 sides
        NSLayoutConstraint.activate([
            theLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
            theLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            theLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            theLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
        ])
    }

}

// simple cell with button
class AddItemCell: UICollectionViewCell {

    let btn: UIButton = {
        let v = UIButton()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.setTitle("+", for: .normal)
        v.setTitleColor(.systemBlue, for: .normal)
        v.titleLabel?.font = UIFont.systemFont(ofSize: 40.0)
        return v
    }()

    // this will be used as a "callback closure" in collection view controller
    var tapCallback: (() -> ())?

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

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

    func commonInit() -> Void {
        contentView.backgroundColor = .green
        contentView.addSubview(btn)
        // constrain button to all 4 sides
        NSLayoutConstraint.activate([
            btn.topAnchor.constraint(equalTo: contentView.topAnchor),
            btn.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            btn.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            btn.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
        ])
        btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
    }

    @objc func didTap(_ sender: Any) {
        // tell the collection view controller we got a button tap
        tapCallback?()
    }

}

class ExampleViewController: UIViewController, UICollectionViewDataSource {

    let theCollectionView: UICollectionView = {
        let v = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .white
        v.contentInsetAdjustmentBehavior = .always
        return v
    }()

    let columnLayout = FlowLayout(
        itemSize: CGSize(width: 100, height: 100),
        minimumInteritemSpacing: 10,
        minimumLineSpacing: 10,
        sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    )

    // track collection view frame change
    var colViewWidth: CGFloat = 0.0

    // example data --- this will be filled with simple number strings
    var theData: [String] = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemYellow

        view.addSubview(theCollectionView)

        // constrain collection view
        //      100-pts from top
        //      60-pts from bottom
        //      40-pts from leading
        //      40-pts from trailing
        NSLayoutConstraint.activate([
            theCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100.0),
            theCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -60.0),
            theCollectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40.0),
            theCollectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40.0),
        ])

        // register the two cell classes for reuse
        theCollectionView.register(ContentCell.self, forCellWithReuseIdentifier: "ContentCell")
        theCollectionView.register(AddItemCell.self, forCellWithReuseIdentifier: "AddItemCell")

        // set collection view dataSource
        theCollectionView.dataSource = self

        // use custom flow layout
        theCollectionView.collectionViewLayout = columnLayout

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // only want to call this when collection view frame changes
        // to set the item size
        if theCollectionView.frame.width != colViewWidth {
            let w = theCollectionView.frame.width / 2 - 15
            columnLayout.itemSize = CGSize(width: w, height: w)
            colViewWidth = theCollectionView.frame.width
        }
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // return 1 more than our data array (the extra one will be the "add item" cell
        return theData.count + 1
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        // if item is less that data count, return a "Content" cell
        if indexPath.item < theData.count {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ContentCell", for: indexPath) as! ContentCell
            cell.theLabel.text = theData[indexPath.item]
            return cell
        }

        // past the end of the data count, so return an "Add Item" cell
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AddItemCell", for: indexPath) as! AddItemCell

        // set the closure
        cell.tapCallback = {
            // add item button was tapped, so append an item to the data array
            self.theData.append("\(self.theData.count + 1)")
            // reload the collection view
            collectionView.reloadData()
            collectionView.performBatchUpdates(nil, completion: {
                (result) in
                // scroll to make newly added row visible (if needed)
                let i = collectionView.numberOfItems(inSection: 0) - 1
                let idx = IndexPath(item: i, section: 0)
                collectionView.scrollToItem(at: idx, at: .bottom, animated: true)
            })
        }

        return cell

    }

}


// custom FlowLayout class to left-align collection view cells
// found here: https://stackoverflow.com/a/49717759/6257435
class FlowLayout: UICollectionViewFlowLayout {

    required init(itemSize: CGSize, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
        super.init()

        self.itemSize = itemSize
        self.minimumInteritemSpacing = minimumInteritemSpacing
        self.minimumLineSpacing = minimumLineSpacing
        self.sectionInset = sectionInset
        sectionInsetReference = .fromSafeArea
    }

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

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
        guard scrollDirection == .vertical else { return layoutAttributes }

        // Filter attributes to compute only cell attributes
        let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })

        // Group cell attributes by row (cells with same vertical center) and loop on those groups
        for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
            // Set the initial left inset
            var leftInset = sectionInset.left

            // Loop on cells to adjust each cell's origin and prepare leftInset for the next cell
            for attribute in attributes {
                attribute.frame.origin.x = leftInset
                leftInset = attribute.frame.maxX + minimumInteritemSpacing
            }
        }

        return layoutAttributes
    }
}
//
//示例ViewController.swift
//收集附加项
//
//唐·马格于19年10月22日创作。
//
导入UIKit
//带标签的简单单元格
类ContentCell:UICollectionViewCell{
让标签:UILabel={
设v=UILabel()
v、 translatesAutoresizingMaskIntoConstraints=false
v、 textAlignment=.center
返回v
}()
重写初始化(帧:CGRect){
super.init(frame:frame)
commonInit()
}
必需初始化?(编码器:NSCoder){
super.init(编码器:编码器)
commonInit()
}
func commonInit()->Void{
contentView.backgroundColor=.yellow
contentView.addSubview(标签)
//将标签约束到所有4个边
NSLayoutConstraint.activate([
标签.topAnchor.constraint(等式:contentView.topAnchor),
label.bottomAnchor.constraint(等式:contentView.bottomAnchor),
Label.leadingAnchor.constraint(等同于:contentView.leadingAnchor),
标签.trailingAnchor.constraint(等式:contentView.trailingAnchor),
])
}
}
//带按钮的简单单元
类AddItemCell:UICollectionViewCell{
让btn:UIButton={
设v=UIButton()
v、 translatesAutoresizingMaskIntoConstraints=false
v、 setTitle(“+”,用于:。正常)
v、 setTitleColor(.systemBlue,用于:。正常)
v、 titleLabel?.font=UIFont.systemFont(大小:40.0)
返回v
}()
//这将用作集合视图控制器中的“回调闭包”
变量tapCallback:(()->())?
重写初始化(帧:CGRect){
super.init(frame:frame)
commonInit()
}
必需初始化?(编码器:NSCoder){
super.init(编码器:编码器)
commonInit()
}
func commonInit()->Void{
contentView.backgroundColor=.green
contentView.addSubview(btn)
//将按钮约束到所有4个边
NSLayoutConstraint.activate([
btn.topAnchor.constraint(等式:contentView.topAnchor),
btn.bottomAnchor.constraint(等式:contentView.bottomAnchor),
btn.leadingAnchor.constraint(等式:contentView.leadingAnchor),
btn.trailingAnchor.constraint(等式:contentView.trailingAnchor),
])
btn.addTarget(self,action:#选择器(didTap(:)),for:.touchUpInside)
}
@objc func didTap(发送方:任何){
//告诉集合视图控制器我们有一个按钮点击
tapCallback?()
}
}
类示例ViewController:UIViewController,UICollectionViewDataSource{
让集合视图:UICollectionView={
设v=UICollectionView(帧:CGRect.zero,collectionViewLayout:UICollectionViewFlowLayout())
v、 translatesAutoresizingMaskIntoConstraints=false
v、 背景颜色=白色
v、 contentInsetAdjustmentBehavior=.always
返回v
}()
让columnLayout=FlowLayout(
项目尺寸:CGSize(宽:100,高:100),
最小材料间距:10,
最小线间距:10,
截面插图:UIEdgeInsets(顶部:10,左侧:10,底部:10,右侧:10)
)
//轨迹集合视图帧更改
var colViewWidth:CGFloat=0.0
//示例数据---这将由简单的数字字符串填充
变量数据:[String]=[String]()
重写func viewDidLoad(){
super.viewDidLoad()
view.backgroundColor=.systemYellow
view.addSubview(集合视图)
//约束集合视图
//距顶部100分
//底部60分
//领先40分
//距尾随40分
NSLayoutConstraint.activate([
集合视图.topAnchor.constraint(等于:view.safeArea LayoutGuide.topAnchor,常量:100.0),
CollectionView.bottomAnchor.constraint(等于:view.safeArea LayoutGuide.bottomAnchor,常量:-60.0),
Collection view.leadingAnchor.constraint(相等于:view.SafeArea LayoutGuide.leadingAnchor,常量:40.0),
集合视图.trailingAnchor.constraint(等于:view.saferearealayoutguide.trailingAnchor,常量:-40.0),
])
//注册这两个单元类以便重用
CollectionView.register(ContentCell.self,强制使用ReuseIdentifier:“ContentCell”)
CollectionView.register(AddItemCell.self,强制使用ReuseIdentifier:“AddItemCell”)
//设置集合视图数据源
collectionview.dataSource=self
//使用自定义流布局
CollectionView.collectionViewLayout=columnLayout
}
重写func viewdilayoutsubviews(){
super.viewDidLayoutSubviews()
//仅希望在集合图幅更改时调用此
//设置项目大小的步骤
如果集合