swift中的UICellView单元格布局

Posted

技术标签:

【中文标题】swift中的UICellView单元格布局【英文标题】:UICellView cell layout in swift 【发布时间】:2016-08-17 09:55:17 【问题描述】:

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

我已经能够创建一个包含正确数量的单元格的网格视图,但这些单元格的布局还不是正确的,即输入 5 x 7 将给出 35 个单元格,但不是 5 x 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(用户选择的单元格宽度)。

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

【问题讨论】:

【参考方案1】:

这是要添加到您的 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()

【讨论】:

【参考方案2】:

简单,添加实现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 在这里表示您希望在单元格之间放置的间距。

【讨论】:

【参考方案3】:

试试这个代码:

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="***_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"  />
                    <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"  />
                            <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="ILL-QA-nex">
                                <size key="itemSize"  />
                                <size key="headerReferenceSize"  />
                                <size key="footerReferenceSize"  />
                                <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"  />
                                    <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"  />
                                        <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 上的结果

【讨论】:

【参考方案4】:

@vacawama 提供的答案的 Swift 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)

【讨论】:

以上是关于swift中的UICellView单元格布局的主要内容,如果未能解决你的问题,请参考以下文章

使用图像和文本单元拖放单元格,如 Swift 中的 MyAlbum 应用程序

使用 nib 自定义单元格和自动布局滚动跳转(ios 8 swift - UITableview)

Swift 无法让 UICollectionView 正确布局

在 UITableView 中使用自动布局进行动态单元格布局和可变行高

在 UITableView 中使用自动布局进行动态单元格布局和可变行高

如何在swift 3中的表视图单元格中实现集合视图的分页?