Reputation: 70476
The case: https://github.com/ArtworkAD/ios_jumping_y.git
The Container
class ContainerController: UIViewController {
@IBOutlet weak var container: UIView!
@IBOutlet weak var foregroundTopSpace: NSLayoutConstraint!
@IBOutlet weak var foregroundBottomSpace: NSLayoutConstraint!
}
The container is connected to the UITableViewController to its right.
What I want to do
The user scrolls the table and when he reaches the top I want to move the table down with the same movement. So I simply change the top/bottom space of the container view. However this causes the table to jump.
class MainController: UITableViewController, UIGestureRecognizerDelegate {
var panRecognizer: UIPanGestureRecognizer!
var gotStart: Bool = true
var startTouch: CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.bounces = false
self.panRecognizer = self.tableView.panGestureRecognizer
self.panRecognizer.addTarget(self, action: "pan:")
self.tableView.addGestureRecognizer(self.panRecognizer)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func pan(rec:UIPanGestureRecognizer){
if let parent = self.parentViewController as? ContainerController {
var y = self.tableView.contentOffset.y
var touch = rec.locationInView(self.view)
// JUMPING y
println(touch.y)
if y == -64 {
if self.gotStart || y < -64 || y > -64 {
self.startTouch = touch
self.gotStart = false
} else {
if rec.state == .Changed {
var changedVerticalHeight = (self.startTouch.y - touch.y)*(-1)
if changedVerticalHeight <= parent.view.frame.size.height && touch.y >= changedVerticalHeight {
parent.foregroundTopSpace.constant = changedVerticalHeight
parent.foregroundBottomSpace.constant = -changedVerticalHeight
}
} else if rec.state == .Ended {
parent.foregroundTopSpace.constant = 0
parent.foregroundBottomSpace.constant = 0
self.gotStart = true
}
}
}
}
}
}
Result:
Any ideas whats wrong? There has to be some problem with the container view because when I move the table view directly there is no jumping.
Upvotes: 0
Views: 2284
Reputation: 23459
I going to clarify some things in my answer before I put the complete code
You can use the function scrollViewWillEndDragging
to know where exactly the contentOffset
is going to, see the below code :
override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
println(targetContentOffset.memory.y)
}
You can use the function scrollViewDidEndDecelerating
to know when the scroll has finished it.
Then you can merge the two above tips to accomplish your goal in the following way:
class MainController: UITableViewController {
var position : CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
}
override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Save where the contentOffset go
position = targetContentOffset.memory.y
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// If reach the top or more than the top when the user move the scroll
if (position < 0) {
var to = scrollView.contentOffset.y + 213
scrollView.setContentOffset(CGPoint(x: 0, y: to), animated: true)
}
}
// Default table stuff, not related to problem
/* Here comes the rest of your code of TableView */
}
I remove some code for your project relative to the panGestureRecognizer
and bounces to test.
In the line var to = scrollView.contentOffset.y + 213
you can add the position
variable or the value you want, I put 213
only to test the down movement.
I hope this help you.
Upvotes: 4
Reputation: 2829
I believe that exactly what you want:
import UIKit
class MainController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let beginingContentOffset: CGFloat = -64
if scrollView.contentOffset.y < beginingContentOffset {
scrollView.bounces = false
UIView.animateWithDuration(0.05, animations: { () -> Void in
scrollView.contentOffset = CGPointMake(0, 0)
}, completion: { (finished: Bool) -> Void in
scrollView.bounces = true
})
}
}
// Default table stuff, not related to problem
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell_ : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL_ID") as? UITableViewCell
if(cell_ == nil){
cell_ = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CELL_ID")
}
cell_!.textLabel!.text = "Row " + String(indexPath.row)
return cell_!
}
}
P.S. That "-64" value. It's margin from storyboard. You can uncheck margins for constraint and it will be "0". It will be much clearest
Upvotes: 0
Reputation: 516
You're printing the location from self.view
system coordinates. The UITableViewController
use a table view like self.view. So the origin (x:0 y:0) start to move when the user scrolling.
You have to user a static system coordinates. Use the UIViewController
and UITableView
panGestureRecognizer
property for print position correctly and get the scrolling:
UIViewController
.UITableview
and setup AutoLayout
.IBOutlet
with the UITableView
Add the code to the UIViewController
class:
var panRecognizer: UIPanGestureRecognizer!
@IBOutlet weak var tableView: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
self.panRecognizer = tableView?.panGestureRecognizer;
self.panRecognizer .addTarget(self, action: "pan:")
tableView?.addGestureRecognizer(self.panRecognizer)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func pan(rec:UIPanGestureRecognizer){
println(rec.locationInView(self.view).y)
}
You can download the project example here.
If you just need control the scrolling, remember that UIScrollView delegate method:
optional func scrollViewDidScroll(_ scrollView: UIScrollView)
can help you. It's a cleaner a simpler solution:
Good luck.
Upvotes: 1