为什么我的 Table Views scrollToRow at 只能部分滚动?
Why does my Table Views scrollToRow at only scroll partially?
我正在实施 UITableView
,我希望 table 视图在用户开始滚动时自动向上滚动到顶部。我使用类似于 的逻辑来检测用户滚动的方向。当用户开始向上滚动时,下面的函数会检测到滚动,但 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()
}
}
以上问题有2种解决方法-
解决方案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 中,强制它在主线程中 运行 (尽管它在主线程中处于 运行ning 状态,但出于滚动目的,您需要强制 运行 它)。但是,我还没有在真实设备上测试过这个解决方案,所以不确定这是否显示出一些抖动效果。
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
}
}
我个人更喜欢第一种解决方案,因为这是您可以正确处理拖动和减速场景的方式。
我正在实施 UITableView
,我希望 table 视图在用户开始滚动时自动向上滚动到顶部。我使用类似于 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()
}
}
以上问题有2种解决方法-
解决方案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 中,强制它在主线程中 运行 (尽管它在主线程中处于 运行ning 状态,但出于滚动目的,您需要强制 运行 它)。但是,我还没有在真实设备上测试过这个解决方案,所以不确定这是否显示出一些抖动效果。
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
}
}
我个人更喜欢第一种解决方案,因为这是您可以正确处理拖动和减速场景的方式。