问题描述
我有一个使用自定义单元格的UITableViewController。在自定义单元格内是一个UITextView和一个UIButton。我需要选定的tableView单元格适合用户输入时用户输入的多行文本。可以完美演示这一点的应用程序将是iPhone的预安装的Reminders应用程序。当前在我的应用中,tableView单元格的高度保持不变,并且textView可以在必要时进行滚动以容纳多行文本。
我尝试实施此帖子(Dynamically change cell's height while typing text,and reload the containing tableview for resize)中的解决方案,该帖子似乎提出了相同的问题,但是,该帖子已有3年历史了,即使答案仍然有效,也没有足够的示例代码让我了解如何执行答案。我没有碰碰运气,并且清除了当前的代码,避免了以前的任何尝试,因此就所需的功能而言,它目前是一个干净的状态。看到包含Swift 5中的示例代码的答案真是太神奇了。
如果有用的话,这里是自定义单元格类:
class newNoteTableViewCell: UITableViewCell {
@IBOutlet weak var lyricsField: UITextView!
@IBOutlet weak var recordButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool,animated: Bool) {
super.setSelected(selected,animated: animated)
}
@IBAction func recordButtonpressed(_ sender: UIButton) {
}
}
还有我的cellForRowAt,这是除numberOfRowsInSection之外目前唯一实现的表视图委托方法:
override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "lyricsCell",for: indexPath) as! newNoteTableViewCell
cell.lyricsField.delegate = self
cell.lyricsField.tag = indexPath.row
if let safeLyrics = lyrics {
if indexPath.row < safeLyrics.count {
cell.lyricsField.text = safeLyrics[indexPath.row].text
} else {
cell.lyricsField.text = ""
}
}
return cell
}
解决方法
我们可以通过向您的单元格添加“回调”闭包来实现这一目的。
在编辑文本视图时,单元格类将“回调”到控制器,在这里我们可以告诉表格视图重新计算行高(以及保存编辑的文本)。
这是带有约束的简单单元格布局。确保禁用在文本视图上的滚动:
请注意,在设计时单元的高度无关紧要……我们的约束将允许自动布局来处理它。
结果:
这是示例代码:
class ExampleCell: UITableViewCell,UITextViewDelegate {
@IBOutlet var recordButton: UIButton!
@IBOutlet var lyricsField: UITextView!
var callback: ((String) -> ())?
override func didMoveToSuperview() {
super.didMoveToSuperview()
// make sure scroll is disabled
lyricsField.isScrollEnabled = false
// make sure delegate is set
lyricsField.delegate = self
// if these are set in Storyboard this func is not needed
}
func textViewDidChange(_ textView: UITextView) {
let str = textView.text ?? ""
// tell the controller
callback?(str)
}
}
class ExampleTableViewController: UITableViewController {
var myData: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// start with 20 sample strings for our data
// fill data array with 30 strings
myData = (1...30).map { "This is row \($0)" }
// give the second row some longer sample text
myData[1] = "Some sample text so we see that the text view height will be automatically handled by auto-layout."
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "exampleCell",for: indexPath) as! ExampleCell
cell.lyricsField.text = myData[indexPath.row]
// set the closure
weak var tv = tableView
cell.callback = { [weak self] str in
guard let self = self,let tv = tv else { return }
print("called back",str)
// update our data with the edited string
self.myData[indexPath.row] = str
// we don't need to do anything else here
// this will force the table to recalculate row heights
tv.performBatchUpdates(nil)
}
return cell
}
}
,这是情节提要的参考源:
<?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="UxY-Y6-LYS">
<device id="retina3_5" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<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="HKA-46-9zH">
<objects>
<tableViewController id="UxY-Y6-LYS" customClass="ExampleTableViewController" customModule="Temp" 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="ZaD-4v-hEm">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<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="exampleCell" rowHeight="141" id="1bW-gv-rnI" customClass="ExampleCell" customModule="Temp" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="320" height="141"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="1bW-gv-rnI" id="H65-Gy-hPe">
<rect key="frame" x="0.0" y="0.0" width="320" height="141"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5rZ-Jh-Wyd">
<rect key="frame" x="96" y="11" width="128" height="30"/>
<color key="backgroundColor" red="0.85215073819999998" green="0.88016217949999997" blue="0.94548028709999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="Record"/>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" keyboardDismissMode="onDrag" text="The Text View" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ddd-0L-1pM">
<rect key="frame" x="24" y="49" width="272" height="81"/>
<color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<constraints>
<constraint firstItem="ddd-0L-1pM" firstAttribute="top" secondItem="5rZ-Jh-Wyd" secondAttribute="bottom" constant="8" id="MHf-Yq-xQq"/>
<constraint firstAttribute="trailingMargin" secondItem="ddd-0L-1pM" secondAttribute="trailing" constant="8" id="QMH-AZ-j7k"/>
<constraint firstItem="5rZ-Jh-Wyd" firstAttribute="leading" secondItem="H65-Gy-hPe" secondAttribute="leadingMargin" constant="80" id="TYR-1f-iit"/>
<constraint firstAttribute="trailingMargin" secondItem="5rZ-Jh-Wyd" secondAttribute="trailing" constant="80" id="Yf1-2g-dlf"/>
<constraint firstItem="5rZ-Jh-Wyd" firstAttribute="top" secondItem="H65-Gy-hPe" secondAttribute="topMargin" id="gaW-td-egM"/>
<constraint firstItem="ddd-0L-1pM" firstAttribute="bottom" secondItem="H65-Gy-hPe" secondAttribute="bottomMargin" id="lKj-ML-H4Q"/>
<constraint firstItem="ddd-0L-1pM" firstAttribute="leading" secondItem="H65-Gy-hPe" secondAttribute="leadingMargin" constant="8" id="uxs-rD-Pdj"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="lyricsField" destination="ddd-0L-1pM" id="9Nz-Ru-psp"/>
<outlet property="recordButton" destination="5rZ-Jh-Wyd" id="qNA-Up-zLK"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="UxY-Y6-LYS" id="cmh-tD-hLg"/>
<outlet property="delegate" destination="UxY-Y6-LYS" id="xk4-oC-WNJ"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="7mc-zX-bKw" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="330" y="127.5"/>
</scene>
</scenes>
<resources>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
编辑 以回复评论...。
您在单元格中的约束都是错误的...
这是您原来的xib的外观:
这是他们应该的外观:
重要:您的堆栈视图设置必须为: