ios - UITableView Swift 中的多标题部分
问题描述
以下代码成功填充了一个表格,如UITableView 1图像所示。我想做的是添加一个额外的级别,看起来像UITableView 2图像。
如UITableView 2图像所示,创建多级部分的最佳方法是什么?
仅供参考 - 我尝试按照该线程的说明进行操作,但无法使其正常工作。
代码
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var myTable: UITableView!
let sections = [["Mustang", "Model S"],["F-150", "Cybertruck"]]
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let viewContainer = UIView(frame: CGRect(x:0, y:0, width: myTable.frame.width, height: 40))
viewContainer.backgroundColor = UIColor.lightGray
let labelHeader = UILabel(frame: CGRect(x:0, y:0, width: 200, height: 30))
labelHeader.textColor = UIColor.white
if section == 0{
labelHeader.text = "Cars "
}
if section == 1{
labelHeader.text = "Trucks"
}
viewContainer.addSubview(labelHeader)
return viewContainer
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return sections[section].count
}
return sections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCustomCell", for: indexPath) as! MyCustomCell
if indexPath.section == 0{
cell.textLabel?.text = sections[indexPath.section][indexPath.row]
}
if indexPath.section == 1{
cell.textLabel?.text = sections[indexPath.section][indexPath.row]
}
return cell
}
}
图片
解决方案
您可以使用单个 Cell Prototype 轻松完成此操作:
我添加了一个标签,限制在所有 4 个边上(使用边距)。
您会注意到其中一个约束与其他约束不同Label Leading
- 因为我将其连接为@IBOutlet
. 当我设置单元格数据时,我更改标签背景颜色、.constant
前导约束的颜色以及.selectionStyle
基于它是“品牌”行或“模型”行:
enum VehicleType {
case car, truck
}
struct Vehicle {
var type: VehicleType = .car
var brand: String = ""
var model: String = ""
}
class MyCustomCell: UITableViewCell {
@IBOutlet var theLabel: UILabel!
@IBOutlet var labelLeading: NSLayoutConstraint!
func setData(_ v: Vehicle) -> Void {
if v.model == "" {
theLabel.text = v.brand
theLabel.textColor = .darkGray
theLabel.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
labelLeading.constant = 0
selectionStyle = .none
} else {
theLabel.text = v.model
theLabel.textColor = .black
theLabel.backgroundColor = .clear
labelLeading.constant = 16
selectionStyle = .default
}
}
}
在此示例中,如果“型号”名称为空字符串,我将确定它是否为“品牌”行/单元格。
这是它的外观:
向下滚动到卡车部分后:
如果您想要 Brand 和 Model 行之间的其他外观差异,您可以在同一.setData()
函数中处理这些差异。
这是一个完整的例子:
enum VehicleType {
case car, truck
}
struct Vehicle {
var type: VehicleType = .car
var brand: String = ""
var model: String = ""
}
class MyCustomCell: UITableViewCell {
@IBOutlet var theLabel: UILabel!
@IBOutlet var labelLeading: NSLayoutConstraint!
func setData(_ v: Vehicle) -> Void {
if v.model == "" {
theLabel.text = v.brand
theLabel.textColor = .darkGray
theLabel.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
labelLeading.constant = 0
selectionStyle = .none
} else {
theLabel.text = v.model
theLabel.textColor = .black
theLabel.backgroundColor = .clear
labelLeading.constant = 16
selectionStyle = .default
}
}
}
class MultiSectionViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var tableView: UITableView!
// for simulating getting the data
let activityView = UIActivityIndicatorView(style: .large)
// will contain an array of Cars and an array of Trucks
var dataArray: [[Vehicle]] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// empty view as footer so we don't see blank rows
tableView.tableFooterView = UIView()
}
override func viewDidAppear(_ animated: Bool) {
self.simulateGetData()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let viewContainer = UIView()
viewContainer.backgroundColor = UIColor.lightGray
let labelHeader = UILabel()
labelHeader.textColor = UIColor.white
if section == 0 {
labelHeader.text = "Cars "
}
if section == 1 {
labelHeader.text = "Trucks"
}
viewContainer.addSubview(labelHeader)
labelHeader.autoresizingMask = [.flexibleWidth, .flexibleHeight]
labelHeader.frame = viewContainer.frame
return viewContainer
}
func numberOfSections(in tableView: UITableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCustomCell", for: indexPath) as! MyCustomCell
let vehicle: Vehicle = dataArray[indexPath.section][indexPath.row]
cell.setData(vehicle)
return cell
}
func simulateGetData() -> Void {
// show the "spinner"
view.addSubview(activityView)
activityView.center = CGPoint(x: tableView.center.x, y: tableView.frame.origin.y + 80)
activityView.startAnimating()
// simulate it taking 2 seconds to get the data
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.parseData(self.remoteData)
}
}
func parseData(_ str: String) -> Void {
var fullList: [Vehicle] = []
// split retrieved string into lines
let linesArray: [String] = str.components(separatedBy: "\n")
linesArray.forEach { line in
// split this line
let a: [String] = line.components(separatedBy: ",")
fullList.append(Vehicle(type: a[0] == "car" ? .car : .truck, brand: a[1], model: a[2]))
}
// get the cars
var cars: [Vehicle] = fullList.filter { $0.type == .car }
// get list of car brands
let carBrands = Set((cars).compactMap { $0.brand })
// for each brand, append a Vehicle with Brand but no Model
carBrands.forEach { brand in
cars.append(Vehicle(type: .car, brand: brand, model: ""))
}
// sort cars by brand / model
cars.sort {
($0.brand, $0.model) <
($1.brand, $1.model)
}
// get the trucks and sort by brand / model
var trucks: [Vehicle] = fullList.filter { $0.type == .truck }
// get list of trueck brands
let truckBrands = Set((trucks).compactMap { $0.brand })
// for each brand, append a Vehicle with Brand but no Model
truckBrands.forEach { brand in
trucks.append(Vehicle(type: .truck, brand: brand, model: ""))
}
// sort trucks by brand / model
trucks.sort {
($0.brand, $0.model) <
($1.brand, $1.model)
}
// fill our dataArray
dataArray.append(cars)
dataArray.append(trucks)
// remove the spinner
activityView.stopAnimating()
activityView.removeFromSuperview()
// reload the table
tableView.reloadData()
}
let remoteData: String = """
car,Chevrolet,Camaro
car,Chevrolet,Corvette
car,Chevrolet,Impala
car,Chevrolet,Malibu
car,Chevrolet,Sonic
truck,Chevrolet,Colorado
truck,Chevrolet,Silverado
car,Ford,EcoSport
car,Ford,Edge
car,Ford,Escape
car,Ford,Expedition
car,Ford,Fusion
car,Ford,Mustang
truck,Ford,F-150
truck,Ford,F-250
truck,Ford,F-350
car,Toyota,4Runner
car,Toyota,Avalon
car,Toyota,Camry
car,Toyota,Corolla
car,Toyota,Highlander
car,Toyota,Prius
car,Toyota,Rav4
truck,Toyota,Tacoma
truck,Toyota,Tundra
"""
}
以及我与原型单元一起使用的故事板的来源:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wBJ-BC-ngb">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Multi Section View Controller-->
<scene sceneID="vJm-85-LPr">
<objects>
<viewController id="wBJ-BC-ngb" customClass="MultiSectionViewController" customModule="MiniScratch" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="pxy-Ko-DBo">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UEv-mW-XVy">
<rect key="frame" x="40" y="100" width="295" height="527"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="myCustomCell" id="rtS-G4-74c" customClass="MyCustomCell" customModule="MiniScratch" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="295" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="rtS-G4-74c" id="39C-jc-tSh">
<rect key="frame" x="0.0" y="0.0" width="295" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<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="KlT-QG-nQC">
<rect key="frame" x="15" y="11" width="265" height="21.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="KlT-QG-nQC" secondAttribute="trailing" id="EpN-7X-Ue5"/>
<constraint firstAttribute="bottomMargin" secondItem="KlT-QG-nQC" secondAttribute="bottom" id="WK9-gS-0S3"/>
<constraint firstItem="KlT-QG-nQC" firstAttribute="top" secondItem="39C-jc-tSh" secondAttribute="topMargin" id="hkl-1J-cH5"/>
<constraint firstItem="KlT-QG-nQC" firstAttribute="leading" secondItem="39C-jc-tSh" secondAttribute="leadingMargin" id="zza-OX-VlC"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="labelLeading" destination="zza-OX-VlC" id="FIW-Qy-k9n"/>
<outlet property="theLabel" destination="KlT-QG-nQC" id="CX2-4G-IlT"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="nNy-q0-wea" firstAttribute="bottom" secondItem="UEv-mW-XVy" secondAttribute="bottom" constant="40" id="Je2-cL-xF0"/>
<constraint firstItem="UEv-mW-XVy" firstAttribute="top" secondItem="nNy-q0-wea" secondAttribute="top" constant="100" id="Wne-7o-FQB"/>
<constraint firstItem="nNy-q0-wea" firstAttribute="trailing" secondItem="UEv-mW-XVy" secondAttribute="trailing" constant="40" id="h4R-46-NsF"/>
<constraint firstItem="UEv-mW-XVy" firstAttribute="leading" secondItem="nNy-q0-wea" secondAttribute="leading" constant="40" id="hUZ-2G-yQI"/>
</constraints>
<viewLayoutGuide key="safeArea" id="nNy-q0-wea"/>
</view>
<connections>
<outlet property="tableView" destination="UEv-mW-XVy" id="pMr-41-iIc"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mYD-E0-bHz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52" y="-68"/>
</scene>
</scenes>
</document>
推荐阅读
- r - 定义 lapply 函数
- django - 即使在将 WSGIApplication 组设置为 Global 之后,从守护进程读取响应标头时也会超时
- java - 如何保留用于设置 JsonSubTypes 的属性?
- android - 需要帮助在 android studio 中进行特定设计
- javascript - Crockford 的 Javascript Applicative Order Y Combinator 语法构造解释?
- google-apps-script - 将 Google 表单的编辑响应 URL 添加到其电子表格
- react-native - 在抽屉导航器中刷新“contentComponent”(React-Native)
- json - url 中的查询参数在 laravel json 响应中不起作用?
- java - 如何使用Java获取(检索)mysql数据库数据到数组列表并使用索引打印
- javascript - wordpress 以编程方式添加帖子标签