我正在实现一个UITableView
,我希望桌面视图在用户开始滚动后自动向上滚动到顶部。我使用了与此post类似的逻辑来检测用户滚动的方向。当用户开始向上滚动时,下面的功能会检测到滚动,但table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
非常慢,并且会在一定程度上停止到单元格的顶部。我怎样才能解决这个问题。
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("Dragging has ended")
//print("lastContentOffSet: \(self.lastContentOffset)")
if (self.lastContentOffset < scrollView.contentOffset.y) {
// moved to top
print("Scrolled down")
} else if (self.lastContentOffset > scrollView.contentOffset.y) {
// moved to bottom
print("Scrolled up")
table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
} else {
// didn't move
}
}
以下是完整的代码。
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var table:UITableView!
@IBOutlet weak var photosButton: UIButton!
var lastContentOffset: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell = UITableViewCell()
if indexPath.row == 1{
cell = table.dequeueReusableCell(withIdentifier: "cameraCell", for: indexPath) as! cameraCell
cell.backgroundColor = .red
}else{
cell = table.dequeueReusableCell(withIdentifier: "photoAlbumCell", for: indexPath) as! photoAlbumCell
cell.backgroundColor = .blue
}
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UIScreen.main.bounds.height
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
print("Scrolling began")
self.lastContentOffset = scrollView.contentOffset.y
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("Dragging has ended")
if (self.lastContentOffset < scrollView.contentOffset.y) {
// moved to top
print("Scrolled down")
} else if (self.lastContentOffset > scrollView.contentOffset.y) {
// moved to bottom
print("Scrolled up")
table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
} else {
// didn't move
}
}
@IBAction func photoAlbumButton(_ sender: UIButton) {
table.scrollToRow(at: IndexPath(row: 1, section: 0), at: .top, animated: true)
}
}
class cameraCell:UITableViewCell{
override func awakeFromNib() {
super.awakeFromNib()
}
}
class photoAlbumCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
}
答案 0 :(得分:1)
针对上述问题有两种解决方案 -
解决方案1 - 用户结束拖动时必须处理func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
。要处理正常滚动并在减速时离开,请使用func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
。请注意,您需要这两种委托方法来处理滚动。两个代理都将执行相同的代码集。唯一的变化是第一个代理执行代码的方式,即,您需要添加!decelerate
条件,因为我们在减速方案的第二个代理中进行处理。请注意,抬起手指后,它会慢慢滚动,直到调用代表,但它会确保它滚动到顶部。换句话说,您的代码应如下所示 -
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
print("Dragging has ended")
if (self.lastContentOffset < scrollView.contentOffset.y) {
// moved to top
print("Scrolled down")
} else if (self.lastContentOffset > scrollView.contentOffset.y) {
// moved to bottom
print("Scrolled up")
table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
} else {
// didn't move
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate { // decelerate logic will be handled above
print("Dragging has ended")
if (self.lastContentOffset < scrollView.contentOffset.y) {
// moved to top
print("Scrolled down")
} else if (self.lastContentOffset > scrollView.contentOffset.y) {
// moved to bottom
print("Scrolled up")
table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
} else {
// didn't move
}
}
}
解决方案2 - 最简单的解决方法是将table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
封装在Dispatch.main中,强制它在主线程中运行(尽管它在主线程中运行) ,为了滚动目的,你需要它来强行运行它。但是,我还没有在真实设备中测试过这个解决方案,所以不确定这是否会显示出一些混蛋效果。
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("Dragging has ended")
if (self.lastContentOffset < scrollView.contentOffset.y) {
// moved to top
print("Scrolled down")
} else if (self.lastContentOffset > scrollView.contentOffset.y) {
// moved to bottom
print("Scrolled up")
DispatchQueue.main.async {
self.table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
}
} else {
// didn't move
}
}
我个人更喜欢第一种解决方案,因为这是您可以正确处理拖拽和减速方案的方式。