问题
I have a few screens worth of content within my UIScrollView which only scrolls vertically.
I want to programmatically scroll to a view contained somewhere in it's hierarchy.
The UIScrollView move so that the child view is at the top of the UIScrollView (either animated or not)
回答1:
Here's an extension I ended up writing.
Usage:
Called from my viewController, self.scrollView is an outlet to the UIScrollView and self.commentsHeader is a view within it, near the bottom:
self.scrollView.scrollToView(self.commentsHeader, animated: true)
Code:
You only need the scrollToView method, but leaving in scrollToBottom / scrollToTop methods too as you'll probably need those too, but feel free to delete them.
extension UIScrollView {
// Scroll to a specific view so that it's top is at the top our scrollview
func scrollToView(view:UIView, animated: Bool) {
if let origin = view.superview {
// Get the Y position of your child view
let childStartPoint = origin.convertPoint(view.frame.origin, toView: self)
// Scroll to a rectangle starting at the Y of your subview, with a height of the scrollview
self.scrollRectToVisible(CGRect(x:0, y:childStartPoint.y,width: 1,height: self.frame.height), animated: animated)
}
}
// Bonus: Scroll to top
func scrollToTop(animated: Bool) {
let topOffset = CGPoint(x: 0, y: -contentInset.top)
setContentOffset(topOffset, animated: animated)
}
// Bonus: Scroll to bottom
func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
if(bottomOffset.y > 0) {
setContentOffset(bottomOffset, animated: true)
}
}
}
回答2:
scrollView.scrollRectToVisible(CGRect(x: x, y: y, width: 1, height:
1), animated: true)
or
scrollView.setContentOffset(CGPoint(x: x, y: y), animated: true)
Another way is
scrollView.contentOffset = CGPointMake(x,y);
and i do it with animated like this
[UIView animateWithDuration:2.0f delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
scrollView.contentOffset = CGPointMake(x, y); }
completion:NULL];
回答3:
scrollView.setContentOffset(CGPoint, animated: Bool)
Where the point's y coordinate is the y coordinate of the frame of the view you want to show relatively to the scrollView's content view.
回答4:
Here is my answer, this is in swift. This will scroll the pages in scrollview infinitely.
private func startBannerSlideShow()
{
UIView.animate(withDuration: 6, delay: 0.1, options: .allowUserInteraction, animations: {
scrollviewOutlt.contentOffset.x = (scrollviewOutlt.contentOffset.x == scrollviewOutlt.bounds.width*2) ? 0 : scrollviewOutlt.contentOffset.x+scrollviewOutlt.bounds.width
}, completion: { (status) in
self.startBannerSlideShow()
})
}
回答5:
For me, the thing was the navigation bar which overlapped the small portion of the scrollView content. So I've made 2 things:
- Size Inspector - Scroll View - Content Insets --> Change from Automatic to Never.
- Size Inspector - Constraints- "Align Top to" (Top Alignment Constraints)- Second item --> Change from Superview.Top to Safe Area.Top and the value(constant field) set to 0
回答6:
For scroll to top or bottom with completion of the animation
// MARK: - UIScrollView extensions
extension UIScrollView {
/// Animate scroll to bottom with completion
///
/// - Parameters:
/// - duration: TimeInterval
/// - completion: Completion block
func animateScrollToBottom(withDuration duration: TimeInterval,
completion: (()->())? = nil) {
UIView.animate(withDuration: duration, animations: { [weak self] in
self?.setContentOffset(CGPoint.zero, animated: false)
}, completion: { finish in
if finish { completion?() }
})
}
/// Animate scroll to top with completion
///
/// - Parameters:
/// - duration: TimeInterval
/// - completion: Completion block
func animateScrollToBottomTop(withDuration duration: TimeInterval,
completion: (()->())? = nil) {
UIView.animate(withDuration: duration, animations: { [weak self] in
guard let `self` = self else {
return
}
let desiredOffset = CGPoint(x: 0, y: -self.contentInset.top)
self.setContentOffset(desiredOffset, animated: false)
}, completion: { finish in
if finish { completion?() }
})
}
}
回答7:
For me scrollRectToVisible()
didn't work (see here), so I used setContentOffset()
and calculated it myself, based on AMAN77's answer:
extension UIScrollView {
func scrollToView(view:UIView, animated: Bool) {
if let superview = view.superview {
let child = superview.convert(view.frame, to: self)
let visible = CGRect(origin: contentOffset, size: visibleSize)
let newOffsetY = child.minY < visible.minY ? child.minY : child.maxY > visible.maxY ? child.maxY - visible.height : nil
if let y = newOffsetY {
setContentOffset(CGPoint(x:0, y: y), animated: animated)
}
}
}
}
It is for a horizontal scroll view, but the same idea can be applied vertically too.
来源:https://stackoverflow.com/questions/39018017/programmatically-scroll-a-uiscrollview-to-the-top-of-a-child-uiview-subview-in