如何为重用准备约束?
Posted
技术标签:
【中文标题】如何为重用准备约束?【英文标题】:How to prepare constraints for reuse? 【发布时间】:2020-10-19 21:33:26 【问题描述】:我有一个包含多个部分的UITableViewController
。每个部分都包含带有自定义UITableViewCells
的行。该单元格有 4 个主要元素:
我正在努力解决的是如何重复使用单元格。在this 的答案中,我读到与内容无关的事情应该在prepareForReuse
中完成,与内容相关的“重置”应该在cellForRowAt
中完成。但是,我无法弄清楚我该怎么做。目前,一件主要的事情似乎出了问题。
约束未正确“转移”
这是我现在cellForRowAt
中的代码:
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell", for: indexPath) as! TaskCell
let currentItem = sections[indexPath.section].items[indexPath.row]
cell.taskNameLabel.text = currentItem.name
cell.uid = currentItem.uid
cell.delegate = self
cell.indexSection = indexPath.section
cell.indexRow = indexPath.row
cell.itemID = currentItem.itemID
cell.items = sections[indexPath.section].items
cell.quantity = ""
cell.quantity = currentItem.quantity
if currentItem.quantity != nil && currentItem.quantity != "" && currentItem.quantity != " "
cell.quantityLabel.isHidden = false
cell.quantityLabel.text = currentItem.quantity?.uppercased()
cell.taskNameLabel.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = false
else
cell.quantityLabel.isHidden = true
cell.taskNameLabel.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
if currentItem.uid == Auth.auth().currentUser?.uid
cell.profilePicture.isHidden = true
else
cell.profilePicture.isHidden = false
if currentItem.checked
cell.checkBoxOutlet.setBackgroundImage(#imageLiteral(resourceName: "checkBoxFILLED "), for: UIControl.State.normal)
else
cell.checkBoxOutlet.setBackgroundImage(#imageLiteral(resourceName: "checkBoxOUTLINE "), for: UIControl.State.normal)
当cell.taskNameLabel.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
和cell.taskNameLabel.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = false
这行被注释掉时,代码呈现的就像左边的模拟器:https://www.loom.com/share/fcc332ff862741a8ae346e43820b0b60?from_recorder=1
发生的情况是,例如,当第 2 行没有数量时,new 第 2 行的数量也被隐藏(而该单元格 应该有数量)。当关于约束的行被注释掉时,一切正常,但是当它被包含时,奇怪的情况发生了。
如何确保约束(将名称标签在 Y 轴居中如果单元格没有数量)准备好重复使用?
很抱歉,如果我不清楚,我真的不知道如何走得更远,坦率地说,迷路了。
致 *** 社区:非常感谢!
【问题讨论】:
【参考方案1】:听起来您希望输出看起来像这样:
如果是这样,这就是我设计单元格的方式:
那是:
一个按钮 带有两个标签的垂直堆栈视图 图像视图个人资料图像视图的尾随锚点与内容视图的尾随锚点相距 16 磅,并且它有一个 CenterY 锚点。
按钮被约束Leading: 0, CenterY ... 和 Top和Bottom都大于6
堆栈视图受约束 Leading-to-ButtonTrailing: 8, Trailing-to-ProfileImageViewLeading: -8, CenterY ... and Top 和 Bottom 都大于等于4
这样,我们告诉自动布局使单元格高度:
至少比堆栈视图高 8 点 至少比按钮高 12 分当我们有一个数量时,两个标签都将被填充并且不隐藏。所以堆栈视图将比按钮高,其顶部/底部约束将优先。
如果我们没有数量,名称标签将可见,但数量标签将隐藏。因此,按钮会更高,其顶部/底部约束将优先。
在这两种情况下,单元格中的所有内容都将保持垂直居中。
这里是单元类的简化版本:
class TaskCell: UITableViewCell
@IBOutlet var checkBoxOutlet: UIButton!
@IBOutlet var taskNameLabel: UILabel!
@IBOutlet var quantityLabel: UILabel!
@IBOutlet var profilePicture: UIImageView!
func fillData(_ task: Task, profileImage: UIImage?) -> Void
let sysName: String = task.checked ? "largecircle.fill.circle" : "circle"
if let img = UIImage(systemName: sysName)
checkBoxOutlet.setBackgroundImage(img, for: .normal)
taskNameLabel.text = task.name.uppercased()
// make sure quantity is not " "
let q = task.quantity.trimmingCharacters(in: .whitespacesAndNewlines)
quantityLabel.text = q.uppercased()
quantityLabel.isHidden = q == ""
profilePicture.image = profileImage
profilePicture.isHidden = profileImage == nil
这是故事板的源代码,您可以检查单元格布局:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="ios.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="0rh-3w-bzr">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Example Table View Controller-->
<scene sceneID="RP6-4O-gi2">
<objects>
<tableViewController id="0rh-3w-bzr" customClass="ExampleTableViewController" customModule="DelMe" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="9oA-oN-4sp">
<rect key="frame" x="0.0" y="0.0" />
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="taskCell" rowHeight="104" id="0OE-gK-JaO" customClass="TaskCell" customModule="DelMe" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" />
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0OE-gK-JaO" id="GeB-v3-7H5">
<rect key="frame" x="0.0" y="0.0" />
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rrf-x2-kgv">
<rect key="frame" x="16" y="36.5" />
<constraints>
<constraint firstAttribute="width" constant="32" id="aBr-zc-Hi1"/>
<constraint firstAttribute="width" secondItem="Rrf-x2-kgv" secondAttribute="height" multiplier="1:1" id="t6J-WJ-4Dq"/>
</constraints>
<state key="normal" backgroundImage="circle" catalog="system"/>
</button>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="ugR-45-YpU">
<rect key="frame" x="56" y="31" />
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d1t-1z-Pyt">
<rect key="frame" x="0.0" y="0.0" />
<color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="efT-dG-UOP">
<rect key="frame" x="0.0" y="24.5" />
<color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Hlp-8o-qHO">
<rect key="frame" x="319" y="40" />
<color key="tintColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="4ax-ud-MaN"/>
<constraint firstAttribute="width" secondItem="Hlp-8o-qHO" secondAttribute="height" multiplier="1:1" id="V9i-E8-rqH"/>
</constraints>
</imageView>
</subviews>
<constraints>
<constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="ugR-45-YpU" secondAttribute="bottom" constant="4" id="5Tm-8S-wzZ"/>
<constraint firstItem="Rrf-x2-kgv" firstAttribute="top" relation="greaterThanOrEqual" secondItem="GeB-v3-7H5" secondAttribute="topMargin" constant="6" id="D7D-hZ-deP"/>
<constraint firstItem="ugR-45-YpU" firstAttribute="leading" secondItem="Rrf-x2-kgv" secondAttribute="trailing" constant="8" id="F7l-d8-Raf"/>
<constraint firstItem="ugR-45-YpU" firstAttribute="centerY" secondItem="GeB-v3-7H5" secondAttribute="centerY" id="Gzg-V9-jnW"/>
<constraint firstItem="Rrf-x2-kgv" firstAttribute="centerY" secondItem="GeB-v3-7H5" secondAttribute="centerY" id="Kmx-OQ-LVg"/>
<constraint firstItem="ugR-45-YpU" firstAttribute="top" relation="greaterThanOrEqual" secondItem="GeB-v3-7H5" secondAttribute="topMargin" constant="4" id="LVP-0M-KbC"/>
<constraint firstAttribute="trailingMargin" secondItem="Hlp-8o-qHO" secondAttribute="trailing" constant="16" id="QpT-89-Kci"/>
<constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="Rrf-x2-kgv" secondAttribute="bottom" constant="6" id="STP-yS-UR0"/>
<constraint firstItem="Rrf-x2-kgv" firstAttribute="leading" secondItem="GeB-v3-7H5" secondAttribute="leadingMargin" id="Sum-If-WiN"/>
<constraint firstItem="Hlp-8o-qHO" firstAttribute="centerY" secondItem="GeB-v3-7H5" secondAttribute="centerY" id="h42-Iy-CAV"/>
<constraint firstItem="Hlp-8o-qHO" firstAttribute="leading" secondItem="ugR-45-YpU" secondAttribute="trailing" constant="8" id="wTj-7Z-ZCr"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="checkBoxOutlet" destination="Rrf-x2-kgv" id="EVr-hk-wdw"/>
<outlet property="profilePicture" destination="Hlp-8o-qHO" id="HjC-EX-P2D"/>
<outlet property="quantityLabel" destination="efT-dG-UOP" id="vzF-FI-zX3"/>
<outlet property="taskNameLabel" destination="d1t-1z-Pyt" id="kSQ-K6-gqc"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="0rh-3w-bzr" id="Iqt-W7-ziA"/>
<outlet property="delegate" destination="0rh-3w-bzr" id="CJ8-AF-j5x"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="jyI-jf-7cF" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="183.19999999999999" y="180.35982008995504"/>
</scene>
</scenes>
<resources>
<image name="circle" catalog="system" />
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
【讨论】:
哇。非常感谢您抽出宝贵时间如此清晰和详细地回答这个问题。我马上去看!非常感谢:) 我希望模组允许这个谢谢你的评论,但我想说以下。你是一个绝对的传奇。你不知道我花了多长时间试图修复这个烦人的错误,以及我无法弄清楚它是多么沮丧。您的解决方案完美运行,我非常感谢您花时间如此清晰和详细地解释这一点。非常感谢,非常感谢。 嘿@DonMag,只是跟进我在这段代码中遇到的问题 - moveRow 动画现在消失了。之前,这个self.tableView.moveRow(at: IndexPath(row: indexRow, section: indexSection), to: IndexPath(row: lastRow, section: indexSection))
动画行更改,但现在它只是有点卡到位。 This is what I mean。你知道为什么会这样吗?非常感谢,- 马特。
@Matt - 很难从那个视频中分辨出来。您必须显示您正在运行的代码。
感谢您的回复; this 是 GitHub 项目,可以吗? “moveRow”在 TableViewController.swift 中的第 393 行。以上是关于如何为重用准备约束?的主要内容,如果未能解决你的问题,请参考以下文章