Update: My Problem was that the timer was not firing during the scroll and the fact that for a reason now unclear to me i was under the impression that scrollViewDidScroll would not fire all the time.
I have a UITableView
with the same height as the containing view. While the UITableView
content is moving i need to know which cell is closest to the vertical center of the containing view.
Things which could make a potential solution: 1. The number of items is fix 2. The cell-heights are all equal and known
I tried a number of solutions including reading the contentOffset, rectForRowAtIndexPath and indexPathForRowAtPoint
.
Also this idea which seems to be the same problem:
Determine coordinates of a UITableViewCell while scrolling
But all this solution suffer from the fact that the values of those (contentOffset, rectForRowAtIndexPath and indexPathForRowAtPoint
) are only updated after the UITableView
stopped moving. But since i want to read data related to the cell in the middle of the screen also while it moves this is of no help.
Sidenote: I use a NSTimer
Interval to check the offset.
Update (Code): This is the code which atleast works after the table came to a rest. The setup is simple. iPad sized ViewController in Landscape, Table with the same height as the ViewController wired to self.tableView. That is all.
import UIKit
class ViewControllerTwoScroll: UIViewController {
let cellIdentifier = "cellIdentifier"
let cellHeight : CGFloat = 768 / 5
var tableData = [String]()
var magicNumber = 0
@IBOutlet var tableView: UITableView?
@IBOutlet var devLabelOffset: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.cellIdentifier)
self.tableData.append("");
self.tableData.append("");
for index in 0...100 {
self.tableData.append("Item \(index)")
}
self.tableData.append("");
self.tableData.append("");
// Choose what you like more
self.tableView?.decelerationRate = UIScrollViewDecelerationRateNormal
//self.tableView?.decelerationRate = UIScrollViewDecelerationRateFast
/*** Timer to check the middel cell in a interval ***/
var timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("checkIndexFokus"), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/*** Table Basic-Stuff ***/
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!) {
cell.backgroundColor = UIColor.clearColor()
cell.backgroundView = UIView()
cell.selectedBackgroundView = UIView()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as UITableViewCell
cell.textLabel?.text = self.tableData[indexPath.row]
return cell
}
func tableView( tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return cellHeight;
}
/*** Observe change of cell closest to the center ***/
func checkIndexFokus() {
/*** no solution yet. But if i would know the position of the first cell that
would be enough to calculate the cell that is actually in the middle ***/
var rectInTableView = self.tableView?.rectForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0))
rectInTableView = self.tableView?.convertRect(rectInTableView!, toView: self.tableView?.superview)
/*** this shows the correct value for the first cell as i can say but only after the table came to a rest ***/
self.devLabelOffset?.text = "\(rectInTableView!.origin.y)"
}
/*** Table snapping ***/
func scrollViewWillEndDragging(scrollView: UIScrollView!, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
targetContentOffset.memory.y = floor(targetContentOffset.memory.y / cellHeight) * cellHeight
}
}