如何解决Swift在UITableViewCell中使用UISlider是正确的方法吗?
我正在努力在UITableViewCell中正确使用UiSliders。 这是想法:
我希望他提供的是,根据他所需的工作,他可以设置特定工作所需的人员数量。 我正在TableViewCell中使用UiSlider,让他做到这一点。
但是麻烦来了:
(1)用户拖动滑块时,UiSlider下的标签显示的数量不正确
(2)prepareForReuse函数无法正常工作。我希望用户在使用重用的单元格时将Slider重新设置为0,并将Label显示为0。
(3)最后,jobAmountNeeded
数组没有存储正确的值(或根本没有任何值),因此在Firebase中保存的数量不正确。
我认为所有三个问题都连接到同一来源。
因此,如果有人可以帮助我,我将非常高兴。 :)
感谢大家的帮助!
class ProjectTeamViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var headerSeperator: UIView!
@IBOutlet weak var saveButton: UIButton!
var sortedSoloJobs = [String]()
var jobIndex: Int?
var jobAmount: [String] = []
var selectedJob:String?
var sentProjectCreated:String?
var projectCreated:String?
var jobAmountNeeded = [JobNeeded]()
var slider: [SliderClass] = []
let step:Float = 1
var selectedindexPath: IndexPath?
var tempArray = [99: "Baum"]
var tempArray2 = [99: 5]
var currentValue:Float = 0
var key = 0
override func viewDidLoad() {
super.viewDidLoad()
setUpUI ()
getJobs(for: User.current) { (memberJobs) in
self.tableView.reloadData()
}
}
// MARK: - Functions
func setUpUI () {
Utilities.addShadowtoView(headerSeperator)
Utilities.addShadowtoButton(saveButton)
saveButton.layer.cornerRadius = 6
saveButton.layer.borderWidth = 1
saveButton.layer.borderColor = UIColor.darkGray.cgColor
}
func getJobs(for user: User,completion: @escaping ([MemberJobsstruct]) -> Void) {
var jobs = [String]() // All Jobs
var soloJobs = [String]() // Solo jobs from all jobs
let ref = Database.database().reference().child("team").child(user.uid)
ref.observeSingleEvent(of: .value,with: { snapshot in
for case let child as DataSnapshot in snapshot.children {
guard let value = child.value as? [String: Any] else {
return completion ([]) }
let memberJob = value["memberJob"] as! String
jobs.append(memberJob)
soloJobs = Array(Set(jobs))
self.sortedSoloJobs = soloJobs.sorted()
dispatchQueue.main.async { self.tableView.reloadData() }
} })
}
func json(from object:Any) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object,options: []) else {
return nil
}
return String(data: data,encoding: String.Encoding.utf8)
}
@objc func sliderValueChange(sender: UiSlider){
sender.isContinuous = false
currentValue = round(sender.value / step) * step
var sliderValue = Int(currentValue)
sender.value = currentValue // get slider's value
let row = sender.tag // get slider's row in table
key = row
if let row = self.jobAmountNeeded.firstIndex(where: {$0.jobKey == key}) {
jobAmountNeeded[row].jobAmount = sliderValue
}
}
@IBAction func saveAction(_ sender: Any) {
if projectCreated == nil || projectCreated == "no Value" {
let alert = UIAlertController(title: "Error",message: "Internal Error send a bug report: #150420",preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK",style: .default,handler: nil))
alert.addAction(UIAlertAction(title: "Cancel",handler: nil))
self.present(alert,animated: true)
} else {
for value in jobAmountNeeded {
let jobName = value.jobName
let jobAmount = value.jobAmount
let jobKey = value.jobKey
let currentUser = User.current
let jobreqRef = Database.database().reference().child("posts").child(currentUser.uid).child(projectCreated ?? "no Value").child("ProjectJobAmount").child(value.jobName)
let project = JobNeeded(jobName: jobName,jobAmount: jobAmount,jobKey: jobKey)
let projectDict = project.dictValue
jobreqRef.setValue(projectDict) { err,jobreqRef in
// print("done")
}
}
}
}
@IBAction func cancelAction(_ sender: Any) {
self.view.window?.rootViewController?.dismiss(animated: true,completion: nil)
}
}
extension ProjectTeamViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
return sortedSoloJobs.count }
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sortedSoloJob = sortedSoloJobs[indexPath.row]
let key = indexPath.row
let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectCharacterTableViewCell",for: indexPath) as! ProjectCharacterTableViewCell
cell.jobNameLabel.text = sortedSoloJobs[indexPath.row]
jobAmountNeeded.append(JobNeeded(jobName: sortedSoloJob,jobAmount: 0,jobKey: indexPath.section))
if let row = self.jobAmountNeeded.firstIndex(where: {$0.jobName == sortedSoloJob}) {
jobAmountNeeded[row].jobName = sortedSoloJob
}
tempArray.updateValue(sortedSoloJob,forKey: key)
let currentValue = cell.slider.value
cell.slider.isContinuous = false
cell.slider.tag = key
cell.slider.minimumValue = 0
cell.slider.maximumValue = Float(sortedSoloJob.count)
cell.slider.addTarget(self,action: #selector(sliderValueChange),for: .valueChanged)
cell.jobAmountLabel.text = "\(currentValue)"
return cell
}
}
// MARK: - UITableViewDelegate
extension ProjectTeamViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView,heightForRowAt indexPath: IndexPath) -> CGFloat {
return 163
}
}
class SliderClass: NSObject {
var title: String?
var subtitle: String?
var sliderMinimum: Float?
var sliderMaximum: Float?
init(title: String,subtitle: String,sliderMinimum: Float,sliderMaximum: Float) {
self.title = title
self.subtitle = subtitle
self.sliderMinimum = sliderMinimum
self.sliderMaximum = sliderMaximum
}
}
class ProjectCharacterTableViewCell: UITableViewCell {
@IBOutlet weak var jobAmountLabel: UILabel!
@IBOutlet weak var slider: UiSlider!
@IBOutlet weak var jobNameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override public func prepareForReuse() {
// Ensures the reused cosmos view is as good as new
super.prepareForReuse()
self.jobAmountLabel.text = "0"
self.slider.value = 0
}
override func setSelected(_ selected: Bool,animated: Bool) {
super.setSelected(selected,animated: animated)
// Configure the view for the selected state
}
}
解决方法
更简单...
首先,让我们为您的SliderClass
添加一个“当前值”属性(我称它为SoloJob
类,这似乎更合逻辑):
class SoloJob: NSObject {
var title: String = ""
var subtitle: String = ""
var sliderMinimum: Float = 0
var sliderMaximum: Float = 100
var currentValue: Float = 0
init(title: String,subtitle: String,sliderMinimum: Float,sliderMaximum: Float,currentValue: Float) {
self.title = title
self.subtitle = subtitle
self.sliderMinimum = sliderMinimum
self.sliderMaximum = sliderMaximum
self.currentValue = currentValue
}
}
我们将使用currentValue
属性来跟踪滑块值。
因此,创建一个带有“标题”标签,一个滑块和一个“作业数量”(或当前值)标签的单元格。我的布局是这样的:
在您的单元格类中,将滑块连接到@IBAction
,以了解其更改的时间-控制器类中的 否 。
也在您的单元格类中,添加一个“回调”闭包变量:
// closure to tell controller the slider was changed
var callback: ((Float) -> ())?
然后,在您的@IBAction
函数中:
@IBAction func sliderValueChange(_ sender: UISlider) -> Void {
let v = sender.value
// update the label
jobAmountLabel.text = "Current Amount: \(Int(v))"
// tell the controller the slider changed
callback?(v)
}
返回您的控制器类,在cellForRowAt
中,设置“回调”闭包:
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectCharacterTableViewCell",for: indexPath) as! ProjectCharacterTableViewCell
let thisJob: SoloJob = sortedSoloJobs[indexPath.row]
// set values / labels in the cell
// closure to get notified when the slider is changed
cell.callback = { val in
// update our data
self.sortedSoloJobs[indexPath.row].currentValue = val
}
return cell
}
当用户拖动滑块时,将调用单元格类本身中的@IBAction func sliderValueChange()
,这就是我们在单元格中更新标签的地方,控制器的值已更改。
这是一个完整的实现:
import UIKit
class SoloJob: NSObject {
var title: String = ""
var subtitle: String = ""
var sliderMinimum: Float = 0
var sliderMaximum: Float = 100
var currentValue: Float = 0
init(title: String,currentValue: Float) {
self.title = title
self.subtitle = subtitle
self.sliderMinimum = sliderMinimum
self.sliderMaximum = sliderMaximum
self.currentValue = currentValue
}
}
class ProjectCharacterTableViewCell: UITableViewCell {
@IBOutlet weak var jobAmountLabel: UILabel!
@IBOutlet weak var slider: UISlider!
@IBOutlet weak var jobNameLabel: UILabel!
// closure to tell controller the slider was changed
var callback: ((Float) -> ())?
override init(style: UITableViewCell.CellStyle,reuseIdentifier: String?) {
super.init(style: style,reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
contentView.layer.cornerRadius = 12
contentView.layer.borderColor = UIColor.blue.cgColor
contentView.layer.borderWidth = 1
contentView.layer.masksToBounds = true
contentView.backgroundColor = .white
backgroundColor = .clear
}
func configureCell(_ theJob: SoloJob) -> Void {
jobNameLabel.text = theJob.title + " - min: \(Int(theJob.sliderMinimum)) / max: \(Int(theJob.sliderMaximum))"
slider.minimumValue = theJob.sliderMinimum
slider.maximumValue = theJob.sliderMaximum
slider.value = theJob.currentValue
jobAmountLabel.text = "Current Amount: \(Int(theJob.currentValue))"
}
// connect valueChanged action in Storyboard
@IBAction func sliderValueChange(_ sender: UISlider) -> Void {
let v = sender.value
// update the label
jobAmountLabel.text = "Current Amount: \(Int(v))"
// tell the controller the slider changed
callback?(v)
}
}
class ProjectTeamViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var sortedSoloJobs: [SoloJob] = []
override func viewDidLoad() {
super.viewDidLoad()
// create some example data
for i in 1...20 {
// random slider minimum between 0 and 2
let minVal = Int.random(in: 0...2)
// random slider maximum between 5 and 10
let maxVal = Int.random(in: 5...10)
// start with current value at minimum
let curVal = minVal
let job = SoloJob(title: "Job Name \(i)",subtitle: "",sliderMinimum: Float(minVal),sliderMaximum: Float(maxVal),currentValue: Float(curVal))
sortedSoloJobs.append(job)
}
tableView.dataSource = self
tableView.delegate = self
}
}
extension ProjectTeamViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
return sortedSoloJobs.count
}
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectCharacterTableViewCell",for: indexPath) as! ProjectCharacterTableViewCell
let thisJob: SoloJob = sortedSoloJobs[indexPath.row]
cell.configureCell(thisJob)
// closure to get notified when the slider is changed
cell.callback = { val in
// update our data
self.sortedSoloJobs[indexPath.row].currentValue = val
}
return cell
}
}
extension ProjectTeamViewController: UITableViewDelegate {
}
和情节提要源(具有所有@IBOutlet
和@IBAction
连接):
<?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="OoM-UM-qa5">
<device id="retina4_0" 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>
<!--Project Team View Controller-->
<scene sceneID="LA9-sV-8lR">
<objects>
<viewController id="OoM-UM-qa5" customClass="ProjectTeamViewController" customModule="TableAdd" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="GWK-to-6GG">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="I5Z-lW-4b3">
<rect key="frame" x="20" y="20" width="280" height="30"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="SAVE BUTTON"/>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Rkw-MO-6Op" userLabel="Horizontal Line View">
<rect key="frame" x="20" y="58" width="280" height="1"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="BkU-lx-Zp8"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="pgu-lS-tk6">
<rect key="frame" x="20" y="67" width="280" height="481"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ProjectCharacterTableViewCell" rowHeight="109" id="tnK-1p-f4N" customClass="ProjectCharacterTableViewCell" customModule="TableAdd" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="280" height="109"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="tnK-1p-f4N" id="gcG-sV-dlw">
<rect key="frame" x="0.0" y="0.0" width="280" height="109"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Job Name Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l3R-9V-mjm">
<rect key="frame" x="78" y="11" width="124" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="mj1-CV-iWZ">
<rect key="frame" x="13" y="36" width="254" height="31"/>
<connections>
<action selector="sliderValueChange:" destination="tnK-1p-f4N" eventType="valueChanged" id="RkI-oL-0eQ"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Job Amount Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xMH-9r-GO9">
<rect key="frame" x="70.5" y="70" width="139" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="l3R-9V-mjm" firstAttribute="top" secondItem="gcG-sV-dlw" secondAttribute="topMargin" id="DPl-Kl-d1J"/>
<constraint firstItem="mj1-CV-iWZ" firstAttribute="leading" secondItem="gcG-sV-dlw" secondAttribute="leadingMargin" id="Sx7-a7-Yxy"/>
<constraint firstItem="mj1-CV-iWZ" firstAttribute="top" secondItem="l3R-9V-mjm" secondAttribute="bottom" constant="4" id="Z05-fI-eal"/>
<constraint firstItem="xMH-9r-GO9" firstAttribute="top" secondItem="mj1-CV-iWZ" secondAttribute="bottom" constant="4" id="a8n-XL-xxa"/>
<constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="xMH-9r-GO9" secondAttribute="bottom" id="cg5-O7-mnS"/>
<constraint firstItem="l3R-9V-mjm" firstAttribute="centerX" secondItem="gcG-sV-dlw" secondAttribute="centerX" id="hGU-ad-se2"/>
<constraint firstItem="xMH-9r-GO9" firstAttribute="centerX" secondItem="gcG-sV-dlw" secondAttribute="centerX" id="p4W-nU-hxy"/>
<constraint firstAttribute="trailingMargin" secondItem="mj1-CV-iWZ" secondAttribute="trailing" id="umL-5D-BUa"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="jobAmountLabel" destination="xMH-9r-GO9" id="AIQ-ro-Q2C"/>
<outlet property="jobNameLabel" destination="l3R-9V-mjm" id="cA7-Kq-aRd"/>
<outlet property="slider" destination="mj1-CV-iWZ" id="YDo-wV-0rA"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="I5Z-lW-4b3" firstAttribute="leading" secondItem="iax-Rw-gHC" secondAttribute="leading" constant="20" id="8bZ-vh-e2L"/>
<constraint firstItem="pgu-lS-tk6" firstAttribute="leading" secondItem="iax-Rw-gHC" secondAttribute="leading" constant="20" id="KK9-MN-7TR"/>
<constraint firstItem="I5Z-lW-4b3" firstAttribute="top" secondItem="iax-Rw-gHC" secondAttribute="top" constant="20" id="MBM-in-OG7"/>
<constraint firstItem="Rkw-MO-6Op" firstAttribute="leading" secondItem="iax-Rw-gHC" secondAttribute="leading" constant="20" id="NM3-Ah-IIR"/>
<constraint firstItem="pgu-lS-tk6" firstAttribute="top" secondItem="Rkw-MO-6Op" secondAttribute="bottom" constant="8" id="abw-Kr-4qh"/>
<constraint firstItem="iax-Rw-gHC" firstAttribute="bottom" secondItem="pgu-lS-tk6" secondAttribute="bottom" constant="20" id="dBK-83-lBg"/>
<constraint firstItem="iax-Rw-gHC" firstAttribute="trailing" secondItem="I5Z-lW-4b3" secondAttribute="trailing" constant="20" id="erM-u3-zLO"/>
<constraint firstItem="Rkw-MO-6Op" firstAttribute="top" secondItem="I5Z-lW-4b3" secondAttribute="bottom" constant="8" id="ry1-D5-U89"/>
<constraint firstItem="iax-Rw-gHC" firstAttribute="trailing" secondItem="Rkw-MO-6Op" secondAttribute="trailing" constant="20" id="vhe-jw-Dnb"/>
<constraint firstItem="iax-Rw-gHC" firstAttribute="trailing" secondItem="pgu-lS-tk6" secondAttribute="trailing" constant="20" id="zdu-4p-FAt"/>
</constraints>
<viewLayoutGuide key="safeArea" id="iax-Rw-gHC"/>
</view>
<connections>
<outlet property="tableView" destination="pgu-lS-tk6" id="08E-xc-PqA"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ns0-iW-ioz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-534.375" y="839.78873239436621"/>
</scene>
</scenes>
</document>
结果:
并且由于每当滑块更改时我们都会更新数据数组,因此我们可以滚动浏览表,并将正确配置重用单元格。
当所有这些都说得通时,将方法带到您的项目中以匹配您的布局和数据结构。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。