swift 中的 UICellView 单元格布局

UICellView cell layout in swift

我正在尝试使用 UICollectionView 创建一个网格,用户可以将其设置为 x 个单元格和 y 个单元格(在文本框中输入),同时仍然在屏幕上占据相同的宽度。

我已经能够创建包含正确数量单元格的网格视图,但这些单元格的布局还不正确,即输入 5 x 7 将得到 35 个单元格,但在 5 个单元格中不会得到 7细胞布局。这是我目前的代码。

MyCollectionViewCell.swift 导入 UIKit

class MyCollectionViewCell: UICollectionViewCell {

    @IBOutlet var cellLabel: UILabel!

}

CreateNewProject.swift

class CreateNewProject : UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITextFieldDelegate {

    @IBOutlet var widthTextBox: UITextField!

    @IBOutlet var lengthTextBox: UITextField!

    @IBOutlet var myCollection: UICollectionView!

    let reuseIdentifier = "cell" // also enter this string as the cell identifier in the storyboard

    @IBAction func updateView(sender: AnyObject) {
        let widthValue = Int(widthTextBox.text!)
        let lengthValue = Int(lengthTextBox.text!)
        multiplyValue = Int(widthValue! * lengthValue!)
        createArray()
    }


    func createArray() {
        var i = 0
        while i < multiplyValue {
            items.append("")
            i += 1
        }
        myCollection.reloadData()
    }


    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print(self.items.count)
    }

    // make a cell for each cell index path
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        // get a reference to storyboard cell
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell

        // Use the outlet in custom class to get a reference to the UILabel in the cell
        cell.cellLabel.text = self.items[indexPath.item]
        cell.backgroundColor = UIColor.lightGrayColor()

        return cell
    }    
}

我已将 UICollectionView 限制在左侧、右侧和顶部,并希望以编程方式将集合视图中的单元格大小调整为 UICollectionView.width / x(用户选择的单元格宽度)。

不确定执行此操作的最佳方法,还需要在各个单元格之间保留一些白色 space。任何帮助将不胜感激!

这是添加到您的 collectionView 的代码。属性 cellsAcrosscellsDownhorizGapvertGap 是您可以在应用中设置的值。 horizGapvertGap 在方法 minimumInteritemSpacingForSectionAtIndexminimumLineSpacingForSectionAtIndex 中设置。 sizeForItemAtIndexPath 将计算单元格所需的尺寸以使其正常工作。

var cellsAcross = 5
var cellsDown = 7
var horizGap = 4
var vertGap = 4

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return cellsAcross * cellsDown
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
    return CGFloat(vertGap)
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
    return CGFloat(horizGap)
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    // Compute the dimensions of a cell for a cellsAcross x cellsDown layout.

    let dimH = (collectionView.bounds.width - (CGFloat(cellsAcross) - 1) * CGFloat(horizGap)) / CGFloat(cellsAcross)

    let dimV = (collectionView.bounds.height - (CGFloat(cellsDown) - 1) * CGFloat(vertGap)) / CGFloat(cellsDown)

    return CGSize(width: dimH, height: dimV)
}

对于这个演示,我添加了以下代码:

@IBAction func threeBy5(sender: UIButton) {
    cellsAcross = 3
    cellsDown = 5
    collectionView.reloadData()
}

@IBAction func fourBy6(sender: UIButton) {
    cellsAcross = 4
    cellsDown = 6
    collectionView.reloadData()
}

@IBAction func fiveBy7(sender: UIButton) {
    cellsAcross = 5
    cellsDown = 7
    collectionView.reloadData()
}

// Handle screen rotation
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    collectionView.reloadData()
}

简单,添加实现 UICollectionViewDelegateFlowLayout 协议的视图控制器扩展:

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        let  size = collectionView.frame.size.width / CGFloat(cols) - CGFloat((cols - 1)) * spacingBetweenCells
        return CGSize(width: size, height: size)
    }
}

spacingBetweenCells 表示您要在单元格之间放置的间距。

试试这个代码:

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {


@IBOutlet var collectionView: UICollectionView!

let rows = 7
let columns = 3

let spaceBetweenRows = 2
let spaceBetweenColumns = 4

var cellHeight: CGFloat {
    get {
        return collectionView.frame.height/CGFloat(rows)-CGFloat(spaceBetweenRows)
    }
}

var cellWidth: CGFloat {
    get {
        return collectionView.frame.width/CGFloat(columns)-CGFloat(spaceBetweenColumns)
    }
}


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    collectionView.dataSource = self
    collectionView.delegate = self
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    return 1
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return rows*columns
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    return collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath)
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
    return CGFloat(spaceBetweenRows)
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
    return CGFloat(spaceBetweenRows)
}

   func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: cellWidth, height: cellHeight)
}
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
    <deployment identifier="iOS"/>
    <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
    <!--View Controller-->
    <scene sceneID="tne-QT-ifu">
        <objects>
            <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Whosebug_38993378" customModuleProvider="target" sceneMemberID="viewController">
                <layoutGuides>
                    <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                    <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                </layoutGuides>
                <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                    <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                    <subviews>
                        <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="StH-xe-9BK">
                            <rect key="frame" x="0.0" y="20" width="600" height="580"/>
                            <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="ILL-QA-nex">
                                <size key="itemSize" width="50" height="50"/>
                                <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                            </collectionViewFlowLayout>
                            <cells>
                                <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="NTl-75-34J">
                                    <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                    <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                        <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                    </view>
                                    <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
                                </collectionViewCell>
                            </cells>
                        </collectionView>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    <constraints>
                        <constraint firstItem="StH-xe-9BK" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="RD1-j0-nbz"/>
                        <constraint firstItem="StH-xe-9BK" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="SMe-NI-E7C"/>
                        <constraint firstItem="StH-xe-9BK" firstAttribute="bottom" secondItem="wfy-db-euE" secondAttribute="top" id="hxb-pd-z2C"/>
                        <constraint firstAttribute="trailing" secondItem="StH-xe-9BK" secondAttribute="trailing" id="zgF-i5-4fX"/>
                    </constraints>
                </view>
                <connections>
                    <outlet property="collectionView" destination="StH-xe-9BK" id="eU8-eE-LXc"/>
                </connections>
            </viewController>
            <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
        </objects>
        <point key="canvasLocation" x="706" y="586"/>
    </scene>
</scenes>
</document>

不同 iPhone 上的结果

Swift @vacawama 提供的答案的 4.2 版本:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return CGFloat(vertGap)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return CGFloat(horizGap)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // Compute the dimensions of a cell for a cellsAcross x cellsDown layout.

    let dimH = (collectionView.bounds.width - (CGFloat(cellsAcross) - 1) * CGFloat(horizGap)) / CGFloat(cellsAcross)

    let dimV = (collectionView.bounds.height - (CGFloat(cellsDown) - 1) * CGFloat(vertGap)) / CGFloat(cellsDown)

    return CGSize(width: dimH, height: dimV)
}