滚动时的 iOS TableView 索引值
Posted
技术标签:
【中文标题】滚动时的 iOS TableView 索引值【英文标题】:iOS TableView Index Value on Scroll 【发布时间】:2016-09-30 07:57:17 【问题描述】:我在我的 Swift 项目中使用表格视图。问题在于表格视图单元格索引路径值。最初加载表时,索引值正常。但是,一旦我滚动表格视图,单元格索引路径就会发生变化,并且我从数据数组中获得的 id 是错误的。谷歌搜索结果是因为可重复使用的单元格之类的东西。这是我的视图控制器代码:
//
// ProjectsController.swift
// PMUtilityTool
//
// Created by Muhammad Ali on 9/23/16.
// Copyright © 2016 Genetech Solutions. All rights reserved.
//
import UIKit
class ProjectsController: UIViewController
//MARK: Properties
var ProjectsArray: Array<Project> = []
@IBOutlet weak var ProjectsTableView: UITableView!
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view.
self.navigationController?.navigationBarHidden = true
// Remove indenting of cell
if self.ProjectsTableView.respondsToSelector(Selector("setSeparatorInset:"))
self.ProjectsTableView.separatorInset = UIEdgeInsetsZero
if self.ProjectsTableView.respondsToSelector(Selector("setLayoutMargins:"))
self.ProjectsTableView.layoutMargins = UIEdgeInsetsZero
self.ProjectsTableView.layoutIfNeeded()
// Get projects
getProjects()
override func viewWillAppear(animated: Bool)
self.navigationController?.navigationBarHidden = true
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
*/
// MARK: - TableView Datasource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
return 1
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return self.ProjectsArray.count
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
// print("clicked")
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> ProjectTableViewCell
print(indexPath.row)
let cell = tableView.dequeueReusableCellWithIdentifier("ProjectViewCell", forIndexPath:indexPath) as! ProjectTableViewCell
// Remove indenting of cell
cell.separatorInset = UIEdgeInsetsZero
cell.layoutMargins = UIEdgeInsetsZero
// Set project name
cell.ProjectName.text = "\((indexPath.row)+1). \(self.ProjectsArray[indexPath.row].ProjectName)"
// Set action button
cell.ActionButton.tag = indexPath.row
cell.ActionButton.addTarget(self, action: #selector(ProjectsController.projectActions(_:)), forControlEvents: .TouchUpInside)
return cell
func reloadTableViewAfterDelay()
ProjectsTableView.performSelector(#selector(UITableView.reloadData), withObject: nil, afterDelay: 0.1)
@IBAction func projectActions(sender: UIButton)
let index = sender.tag
let optionMenu = UIAlertController(title: nil, message: self.ProjectsArray[index].ProjectName, preferredStyle: .ActionSheet)
// Report Progress
let reportProgressAction = UIAlertAction(title: "Report Progress", style: .Default, handler:
(alert: UIAlertAction!) -> Void in
self.performSegueWithIdentifier("ShowReportProgress", sender: sender)
)
// Cancel
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler:
(alert: UIAlertAction!) -> Void in
)
optionMenu.addAction(reportProgressAction)
optionMenu.addAction(cancelAction)
self.presentViewController(optionMenu, animated: true, completion: nil)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
if let button = sender where segue.identifier == "ShowReportProgress"
let upcoming: ReportProgressController = segue.destinationViewController as! ReportProgressController
print(self.ProjectsArray[button.tag].ProjectId)
upcoming.ProjectId = self.ProjectsArray[button.tag].ProjectId
upcoming.ProjectName = self.ProjectsArray[button.tag].ProjectName
// MARK: Get Projects Function
func getProjects() -> Void
var params = Dictionary<String,AnyObject>()
params = ["user_id":CFunctions.getSession("id")]
WebServiceController.getAllProjects(params) (type, response, message) -> Void in
if (type == ResponseType.kResponseTypeFail)
// Show Error
let alert = UIAlertController(title: "Error(s)", message:"Unable to load projects.", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default) _ in )
self.presentViewController(alert, animated: true)
else
//debugPrint(response)
if(response.count>0)
self.ProjectsArray = response
else
// Show Error
let alert = UIAlertController(title: "Error(s)", message:"No projects found.", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default) _ in )
self.presentViewController(alert, animated: true)
self.reloadTableViewAfterDelay()
无论我向下滚动还是向上滚动,我都希望每个单元格的索引值保持不变。
【问题讨论】:
“单元格的索引值保持不变”是什么意思?你想让它是静态的吗?如果这就是你的意思,那么你不能那样做。 Cell的indexPath用于确定每个cell的位置。 `例如,我有 20 行,它最初显示 8 行(一次)。我在其中添加了 print(indexPath.row)。现在当我向下滚动时,它仍然会打印前行的 indexPath。 像这样:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 10 9 8 7 6 5 4 3 2 1 0 8 9 10 1 0 7 8 9 10 11 12 13 14 15 16 17 10 9 8 7 6 5 4 3 2 1 0 7 所以,当您在 cellForRowAtIndexPath 中打印 indexPath.row 时,您遇到了问题,提示您。 阿里请去掉不需要的代码,只放cellForRowAtIndexPath的代码。因为不需要任何代码。 【参考方案1】:例如,在您的 iPhone 屏幕上,您一次可以看到 5 个单元格。
所以,第一次,当你加载 tableView cellForRowAtindexPAth 方法将被调用前 5 细胞。
“正如你所说,第一次加载和 tableView 索引 是正确的。”
现在,当您向下滚动时,将调用 cellForRowAtIndexPath 方法 仅适用于 6 和 7。
“到目前为止一切正常,正如您所提到的。您可以看到整个索引路径完好无损 1,2,3,4,5,6,7。”
*您的屏幕上当前可以看到深色单元格。
现在向上滚动 2 个单元格。现在您可以看到屏幕上当前可见的单元格是1,2,3,4,5。
这里,只有编号为 2,1 的单元格会调用 cellForRowAtIndexPath 方法。
因为单元格编号 3、4、5 已加载/在您的屏幕中可见。
因此,您的打印日志将为 1,2,3,4,5,6,7,2,1。
【讨论】:
但是如果我有一个带索引的数组,并且我的表会遍历该数组以打印其内容(在单元格中)。一旦我单击操作按钮(针对任何特定单元格),该单元格的索引应该传递给按钮的操作方法,我已经调用了一个操作表,在该操作表中还有另一个选项“报告进度”,现在应该单击该选项获取单元格的索引并通过使用该索引,提取正确的 projectId(从数组中),其中数组的索引和单元格的索引保持相同。希望你明白我的意思。 嗨,阿里。我明白你的意思了。你的代码是正确的。如果您运行您的项目,它将获得正确的索引。你运行你的项目并尝试。我相信你的代码。 不是你看到的索引,请回复。 嗨,阿里,我已经快速编辑了这个问题。请不要阅读,如果你不喜欢编辑。我会编辑得更好。 嗨阿里,你知道为什么你没有得到 indexPath.row 'intact' 吗?【参考方案2】:您应该将UITableViewDelegate
和UITableViewDataSource
添加到您的班级。并在viewDidLoad
中设置ProjectsTableView.delegate = self
。
【讨论】:
【参考方案3】:您需要使用 tableViewCell 的层次结构获取按钮的 indexPath。
@IBAction func projectActions(sender: UIButton)
let button = sender as! UIButton
let view = button.superview!
let cell = view.superview as! UITableViewCell
let indexPath = self.reloadTableViewAfterDelay.indexPathForCell(cell)
let index = indexPath.row
if let button = sender where segue.identifier == "ShowReportProgress"
let upcoming: ReportProgressController = segue.destinationViewController as! ReportProgressController
let view = button.superview!
let cell = view.superview as! UITableViewCell
let indexPath = self.reloadTableViewAfterDelay.indexPathForCell(cell)
let index = indexPath.row
print(self.ProjectsArray[index].ProjectId)
upcoming.ProjectId = self.ProjectsArray[index].ProjectId
upcoming.ProjectName = self.ProjectsArray[index].ProjectName
【讨论】:
【参考方案4】:需要使用tableViewCell获取按钮的indexPath而不是下面的代码
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 10
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let cellId: NSString = "Cell"
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId as String)! as UITableViewCell
let ActionButton : UIButton = cell.viewWithTag(10) as! UIButton
ActionButton.addTarget(self, action: #selector(ViewController.projectActions(_:)), forControlEvents: UIControlEvents.TouchUpInside)
return cell
@IBAction func projectActions(sender: UIButton)
let buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)
print(indexPath?.row)
【讨论】:
以上是关于滚动时的 iOS TableView 索引值的主要内容,如果未能解决你的问题,请参考以下文章