UIScrollView - 显示滚动条

56

也许是一个简单的问题!

有人知道如何使UIScrollView的滚动条始终显示吗?

当用户滚动时,它会显示出来,这样他们可以看到滚动视图中的位置。

但是我想让它始终显示,因为对于用户来说并不立即明显他们可以滚动。

任何建议将不胜感激。


如需手动解决,请参见:https://dev59.com/RWYr5IYBdhLWcg3waJj7#40890158 - Top-Master
11个回答

83

不,你不能让它们总是显示,但你可以让它们暂时闪烁。

[myScrollView flashScrollIndicators];

它们是滚动指示器,而不是滚动条。您无法使用它们进行滚动。


2
没错,如果它们一直存在的话,用户体验就会不一致。这是正确的方法。 - David Dunham
1
如果您可以控制内容,您可以通过让一些内容超出边界来向用户提示内容是可滚动的。例如,只显示部分图像,这将暗示更多内容。然后用户很可能会尝试滑动以查看更多内容。 - Sophtware
现在它们是滚动条了:D - Paweł Zgoda-Ferchmin

6

我的解决方案:始终显示滚动指示器的滚动视图。

#define noDisableVerticalScrollTag 836913
#define noDisableHorizontalScrollTag 836914

@implementation UIImageView (ForScrollView)

- (void) setAlpha:(float)alpha {

if (self.superview.tag == noDisableVerticalScrollTag) {
    if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleLeftMargin) {
        if (self.frame.size.width < 10 && self.frame.size.height > self.frame.size.width) {
            UIScrollView *sc = (UIScrollView*)self.superview;
            if (sc.frame.size.height < sc.contentSize.height) {
                return;
            }
        }
    }
}

if (self.superview.tag == noDisableHorizontalScrollTag) {
    if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleTopMargin) {
        if (self.frame.size.height < 10 && self.frame.size.height < self.frame.size.width) {
            UIScrollView *sc = (UIScrollView*)self.superview;
            if (sc.frame.size.width < sc.contentSize.width) {
                return;
            }
        }
    }
}

[super setAlpha:alpha];
}
@end

更新: 这种解决方案在64位系统上可能会出现一些问题。详细信息请参考此处


我无法让它正常工作,而且我也不太明白它应该做什么。当我们试图显示滚动条时,为什么要在滚动上设置Alpha?你能否在这里解释一下这个概念? - Joshua Frank
2
这并不是一个好的答案,它是一个覆盖每个 UIImageView setAlpha 方法的类别。它依赖于滚动视图指示器具有特定的标记号码,这是一个私有实现细节,可能会发生变化。 - lxt
1
这似乎是https://dev59.com/_HrZa4cB1Zd3GeqP6seV#20944188的根本原因 - 在64位模式下运行时导致UI错误。我建议不要使用这段代码。 - Reed Olsen

4
据我所知,这是不可能的。唯一控制滚动指示器显示的API调用是showsVerticalScrollIndicator,但它只能禁用整个指示器的显示。
当视图出现时,您可以flashScrollIndicators,以便用户知道他们在滚动视图中的位置。

3

这个方法对我有效:

#define noDisableVerticalScrollTag 836913
#define noDisableHorizontalScrollTag 836914

@implementation UIImageView (ForScrollView) 

- (void) setAlpha:(float)alpha {

    if (self.superview.tag == noDisableVerticalScrollTag) {
        if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleLeftMargin) {
            if (self.frame.size.width < 10 && self.frame.size.height > self.frame.size.width) {
                UIScrollView *sc = (UIScrollView*)self.superview;
                if (sc.frame.size.height < sc.contentSize.height) {
                    return;
                }
            }
        }
    }

    if (self.superview.tag == noDisableHorizontalScrollTag) {
        if (alpha == 0 && self.autoresizingMask == UIViewAutoresizingFlexibleTopMargin) {
            if (self.frame.size.height < 10 && self.frame.size.height < self.frame.size.width) {
                UIScrollView *sc = (UIScrollView*)self.superview;
                if (sc.frame.size.width < sc.contentSize.width) {
                    return;
                }
            }
        }
    }

    [super setAlpha:alpha];
}
@end

我从这里得到了这段代码:http://www.developers-life.com/scrollview-with-scrolls-indicators-which-are-shown-all-the-time.html

请解释如何使用这个? - Minakshi
@Xyz 如果你仍在寻找如何使用这段代码的解释,请参见此处:Make scrollbar always visible on UIScrollView? - Elliott
非常感谢Elliott Perry。 - Minakshi

3

Swift 3+

1) 定时器

var timerForShowScrollIndicator: Timer?

2) 方法

/// Show always scroll indicator in table view
func showScrollIndicatorsInContacts() {
    UIView.animate(withDuration: 0.001) {
        self.tableView.flashScrollIndicators()
    }
}

/// Start timer for always show scroll indicator in table view
func startTimerForShowScrollIndicator() {
    self.timerForShowScrollIndicator = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(self.showScrollIndicatorsInContacts), userInfo: nil, repeats: true)
}

/// Stop timer for always show scroll indicator in table view
func stopTimerForShowScrollIndicator() {
    self.timerForShowScrollIndicator?.invalidate()
    self.timerForShowScrollIndicator = nil
}

3) 使用

在 viewDidAppear 中使用 startTimerForShowScrollIndicator

在 viewDidDisappear 中使用 stopTimerForShowScrollIndicator


1
我想提供我的解决方案。我不喜欢最流行的分类方法(在分类中覆盖方法可能导致在运行时无法确定应该调用哪个方法,因为有两个具有相同选择器的方法)。我改用交换方法的方式。而且我不需要使用标签。
将此方法添加到您的视图控制器中,在其中包含滚动视图(self.categoriesTableView属性是一个表视图,在其中我想显示滚动条)。
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Do swizzling to turn scroll indicator always on
    // Search correct subview with vertical scroll indicator image across tableView subviews
    for (UIView * view in self.categoriesTableView.subviews) {
        if ([view isKindOfClass:[UIImageView class]]) {
            if (view.alpha == 0 && view.autoresizingMask == UIViewAutoresizingFlexibleLeftMargin) {
                if (view.frame.size.width < 10 && view.frame.size.height > view.frame.size.width) {
                    if (self.categoriesTableView.frame.size.height < self.categoriesTableView.contentSize.height) {
                        // Swizzle class for found imageView, that should be scroll indicator
                        object_setClass(view, [AlwaysOpaqueImageView class]);
                        break;
                    }
                }
            }
        }
    }
    // Search correct subview with horizontal scroll indicator image across tableView subviews
    for (UIView * view in self.categoriesTableView.subviews) {
        if ([view isKindOfClass:[UIImageView class]]) {
            if (view.alpha == 0 && view.autoresizingMask == UIViewAutoresizingFlexibleTopMargin) {
                if (view.frame.size.height < 10 && view.frame.size.height < view.frame.size.width) {
                    if (self.categoriesTableView.frame.size.width < self.categoriesTableView.contentSize.width) {
                        // Swizzle class for found imageView, that should be scroll indicator
                        object_setClass(view, [AlwaysOpaqueImageView class]);
                        break;
                    }
                }
            }
        }
    }
    // Ask to flash indicator to turn it on
   [self.categoriesTableView flashScrollIndicators];
}

添加新类
@interface AlwaysOpaqueImageView : UIImageView
@end

@implementation AlwaysOpaqueImageView

- (void)setAlpha:(CGFloat)alpha {
    [super setAlpha:1.0];
}

@end

滚动指示器(第一个for循环中为垂直滚动指示器,第二个for循环中为水平滚动指示器)将始终显示在屏幕上。如果只需要一个指示器,请保留此代码中的一个for循环并删除另一个。

嗨,我需要对水平指示器进行哪些更改? - Asim

0
对于 WebViews,如果第一个子视图是 ScrollView,在最新的 SDK 中,如果 HTML 页面比框架更长,则不会显示滚动条。如果 HTML 内容恰好与框架对齐,或者框架底部有空白,它看起来就像不需要滚动并且没有线以下的内容。在这种情况下,我认为您应该在委托的方法中明确地闪烁滚动条。
- (void)webViewDidFinishLoad:(UIWebView *)webView; 

提示用户有更多的内容“超出了框架”的方法。

NSArray *subViews = [[NSArray alloc] initWithArray:[webView subviews]] ;
UIScrollView *webScroller = (UIScrollView *)[subViews objectAtIndex:0] ;    

使用 HTML,水平内容会自动换行,因此请检查网页滚动条的高度。
        if (webScroller.contentSize.height > webView.frame.size.height) {
            [webScroller flashScrollIndicators];
        }

闪光灯非常短暂,而且发生在视图加载时,很容易被忽略。为了解决这个问题,您还可以通过通用的UIView commitAnimations来微调、弹跳、滚动或缩放内容。


0

这是一个类似于iOS内置ScrollBar的控件,但你可以自定义颜色和宽度。

-(void)persistantScrollBar
{
    [persistantScrollBar removeFromSuperview];
    [self.collectionView setNeedsLayout];
    [self.collectionView layoutIfNeeded];

    if (self.collectionView.contentSize.height > self.collectionView.frame.size.height + 10)
    {
        persistantScrollBar = [[UIView alloc] initWithFrame:(CGRectMake(self.view.frame.size.width - 10, self.collectionView.frame.origin.y, 5, (self.collectionView.frame.size.height /self.collectionView.contentSize.height) * self.collectionView.frame.size.height))];
        persistantScrollBar.backgroundColor = [UIColor colorWithRed:207/255.f green:207/255.f blue:207/255.f alpha:0.5f];
        persistantScrollBar.layer.cornerRadius = persistantScrollBar.frame.size.width/2;
        persistantScrollBar.layer.zPosition = 0;
        [self.view addSubview:persistantScrollBar];
    }
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect rect = persistantScrollBar.frame;
    rect.origin.y =  scrollView.frame.origin.y + (scrollView.contentOffset.y *(self.collectionView.frame.size.height/self.collectionView.contentSize.height));
    rect.size.height = (self.collectionView.frame.size.height /self.collectionView.contentSize.height) * self.collectionView.frame.size.height;
    if ( scrollView.contentOffset.y <= 0 )
    {
        rect.origin.y = scrollView.frame.origin.y;
        rect.size.height = rect.size.height + (scrollView.contentOffset.y);
    }
    else if (scrollView.contentOffset.y + scrollView.frame.size.height >= scrollView.contentSize.height)
    {
        rect.size.height = rect.size.height - ((scrollView.contentOffset.y + scrollView.frame.size.height) - scrollView.contentSize.height);
        rect.origin.y =  (self.collectionView.frame.origin.y + self.collectionView.frame.size.height - 5) - rect.size.height;
    }

    persistantScrollBar.frame = rect;
}

0

浏览了这些答案,它们大部分都很可怕。使用以下代码可以在Swift 5中实现该功能。仍然依赖于滚动视图使用具有类"_UIScrollViewScrollIndicator"的子视图-但至少没有交换或应用程序范围的类别。

class IndicatorScrollView: UIScrollView {
    
    weak var indicatorTimer: Timer?
    
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        setupIndicatorTimer()
    }
    
    override func removeFromSuperview() {
        super.removeFromSuperview()
        indicatorTimer?.invalidate()
    }
    
    deinit {
        indicatorTimer?.invalidate()
    }
    
    func setupIndicatorTimer() {
        indicatorTimer?.invalidate()
        indicatorTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(showIndicators), userInfo: nil, repeats: true)
    }
    
    @objc func showIndicators() {
        subviews.forEach {
            if String(describing: type(of: $0)).contains("ScrollIndicator") {
                $0.alpha = 1
            }
        }
    }
}

0

iOS没有提供API。但是如果您真的想要这个功能,您可以将自定义指示器添加到滚动视图并自行布局,就像演示中所做的那样:

- (void)layoutSubviews
{
    [super layoutSubviews];
if (self.showsVerticalScrollIndicatorAlways) { scroll_indicator_position(self, k_scroll_indicator_vertical); }
if (self.showsHorizontalScrollIndicatorAlways) { scroll_indicator_position(self, k_scroll_indicator_horizontal); } }

链接为 https://github.com/flexih/MazeScrollView


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接