I am writing program to move an UIView named "myView" while scrolling a UITableView, Look at the pic below:
"myView" will change its 'y-coordinate' along with the change of the contentoffset of tableview, the main code I write is:
func scrollViewDidScroll(scrollView: UIScrollView) {
let off_y = scrollView.contentOffset.y
let new_y = originalMyViewY - off_y
if new_y <= 0 {
print("bad new_y : \(new_y)")
return
}
else {
print("right new_y: \(new_y)")
}
var frame = self.myView.frame
frame.origin.y = new_y
self.myView.frame = frame
}
This works perfectly when I scroll the tableview at a normal speed. However, if I scroll the tableview very fast, 'myview' will stop before reaching the top edge. This is what the log shows:
right new_y: 56.0
bad new_y : -92.5
bad new_y : -153.5
bad new_y : -206.0
It seems that the delegate method scrollViewDidScroll
did not catch every scroll movement which led to a value jump.
I want to know the reason and how to fix it, thanks!
The likely reason for this occurring is because the touches that are being received by your app are occurring faster than the refresh rate of the screen. Thus certain intermediate scroll points will be missed.
Refresh Rate
iOS devices typically run at 60hz or 60 frames per second. This means that every 1/60s or 0.016666 seconds the screen and digitizer will attempt to refresh the current state of touches.
If your finger moves faster than 0.5 display points in that time period than the next scrollViewDidScroll
delegate method will report the newer location and never report the intermediate locations.
Solution
Instead of using the values directly from the delegate method, I would recommend "clamping" the result to your expected range. In this instance it looks like you don't want to receive negative numbers. Meaning if you want the origin y value to be at minimum 0 then you should take the value from the delegate and if it is less than 0 set your View's origin to 0 otherwise use your calculated result.
Example:
func scrollViewDidScroll(scrollView: UIScrollView) {
let off_y = scrollView.contentOffset.y
var new_y = originalMyViewY - off_y // make this mutable so we can change it in the <= 0 block
if new_y <= 0 {
print("y is less than 0, clamp y origin to 0")
new_y = 0
}
else {
print("right new_y: \(new_y)")
}
var frame = self.myView.frame
frame.origin.y = new_y
self.myView.frame = frame
}
Note: This shouldn't result in jumpy resizing of your view as scrollView should already be reporting this scrollViewDidScroll at near the screen refresh rate.