我需要在 viewDidLoad 上始终显示滚动条,以便用户可以了解有要滚动的内容。我做了以下事情:
[myscrollView flashScrollIndicators];
但随后滚动条仅在 viewDidLoad 后出现一段时间,然后再次消失,仅在用户触摸屏幕时重新出现。
我需要使滚动条始终可见。我该怎么做?
我需要在 viewDidLoad 上始终显示滚动条,以便用户可以了解有要滚动的内容。我做了以下事情:
[myscrollView flashScrollIndicators];
但随后滚动条仅在 viewDidLoad 后出现一段时间,然后再次消失,仅在用户触摸屏幕时重新出现。
我需要使滚动条始终可见。我该怎么做?
Apple 在他们的iOS 人机界面指南中间接地不鼓励不断显示滚动指示器,但指南只是出于某种原因的指南,它们并不适用于所有情况,有时您可能需要礼貌地忽略它们。
任何内容视图的滚动指示器都是UIImageView
这些内容视图的子视图。这意味着您可以像访问UIScrollView
它的任何其他子视图(即myScrollView.subviews
)一样访问a 的滚动指示器,并像您一样(例如)修改滚动指示器。UIImageView
scrollIndicatorImageView.backgroundColor = [UIColor redColor];
最流行的解决方案似乎是以下代码:
#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
最初归功于此来源。
这定义了一个类别,UIImageView
该类别定义了 alpha 属性的自定义设置器。这是有效的,因为在底层代码的某个时刻UIScrollView
,它将滚动指示器的 alpha 属性设置为 0 以隐藏它。此时它将遍历我们的类别,如果主机UIScrollView
具有正确的标签,它将忽略正在设置的值,将其显示出来。
为了使用此解决方案,请确保您UIScrollView
具有适当的标签,例如
如果您想从它UIScrollView
可见的那一刻起显示滚动指示器,只需在视图出现时闪烁滚动指示器。例如
- (void)viewDidAppear:(BOOL)animate
{
[super viewDidAppear:animate];
[self.scrollView flashScrollIndicators];
}
其他 SO 参考:
我想提供我的解决方案。我不喜欢最流行的类别变体(类别中的覆盖方法可能是一些不确定在运行时应该调用什么方法的原因,因为有两个方法具有相同的选择器)。我改用调酒。而且我不需要使用标签。
将此方法添加到您的视图控制器中,您可以在其中滚动视图(self.categoriesTableView
在我的情况下)
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Do swizzling to turn scroll indicator always on
// Search correct subview with 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;
}
}
}
}
}
// 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
滚动指示器(在这种情况下为垂直滚动指示器)将始终显示在屏幕上。
从 iOS 13 开始,UIScrollView
子类发生了变化。现在滚动指示器继承自UIView
并有自己的私有类,称为_UIScrollViewScrollIndicator
. 这意味着,它们不是UIImageView
现在的子类,因此旧方法将不再起作用。
我们也无法实现子类,_UIScrollViewScrollIndicator
因为它是私有类,我们无权访问它。所以唯一的解决方案是使用运行时。现在要支持 iOS 13 及更早版本,请执行以下步骤:
self.categoriesTableView
在我的情况下)- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Do swizzling to turn scroll indicator always on
// Search correct subview with 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;
}
}
}
} else if ([NSStringFromClass(view.class) isEqualToString:@"_UIScrollViewScrollIndicator"]) {
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 scroll indicator, (be sure to create AlwaysOpaqueScrollIndicator in runtime earlier!)
// Current implementation is in AlwaysOpaqueScrollTableView class
object_setClass(view, NSClassFromString(@"AlwaysOpaqueScrollIndicator"));
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
UIScrollView
子类)。+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Create child class from _UIScrollViewScrollIndicator since it is private
Class alwaysOpaqueScrollIndicatorClass = objc_allocateClassPair(NSClassFromString(@"_UIScrollViewScrollIndicator"), "AlwaysOpaqueScrollIndicator", 0);
objc_registerClassPair(alwaysOpaqueScrollIndicatorClass);
// Swizzle setAlpha: method of this class to custom
Class replacementMethodClass = [self class];
SEL originalSelector = @selector(setAlpha:);
SEL swizzledSelector = @selector(alwaysOpaque_setAlpha:);
Method originalMethod = class_getInstanceMethod(alwaysOpaqueScrollIndicatorClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(replacementMethodClass, swizzledSelector);
BOOL didAddMethod =
class_addMethod(alwaysOpaqueScrollIndicatorClass,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(alwaysOpaqueScrollIndicatorClass,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (void)alwaysOpaque_setAlpha:(CGFloat)alpha {
[self alwaysOpaque_setAlpha:1.0];
}
此步骤创建在运行时_UIScrollViewScrollIndicator
调用的子类并将方法实现AlwaysOpaqueScrollIndicator
调配到.setAlpha:
alwaysOpaque_setAlpha:
不要忘记添加
#import <objc/runtime.h>
到您插入此代码的文件。感谢@Smartcat 对此的提醒
我不知道这是否可行。但只是给你一个提示。
Scrollview里面的Scrollbar是一个Imageview。这是 UIScrollview 的子视图
所以得到UIscrollview的Scrollbar Imageview。然后尝试将隐藏的图像属性设置为 NO 或更改 Alpha 值
static const int UIScrollViewHorizontalBarIndexOffset = 0;
static const int UIScrollViewVerticalBarIndexOffset = 1;
-(UIImageView *)scrollbarImageViewWithIndex:(int)indexOffset
{
int viewsCount = [[yourScrollview subviews] count];
UIImageView *scrollBar = [[yourScrollview subviews] objectAtIndex:viewsCount - indexOffset - 1];
return scrollBar;
}
-(void) viewDidLoad
{
//Some Code
//Get Scrollbar
UIImageView *scrollBar = [self scrollbarImageViewWithIndex: UIScrollViewVerticalBarIndexOffset];
//The try setting hidden property/ alpha value
scrollBar.hidden=NO;
}
从这里得到参考
这是@Accid Bright答案的 Swift 版本:
class AlwaysOpaqueImageView: UIImageView {
override var alpha: CGFloat {
didSet {
alpha = 1
}
}
static func setScrollbarToAlwaysVisible(from scrollView: UIScrollView) {
// Do swizzling to turn scroll indicator always on
// Search correct subview with scroll indicator image across tableView subviews
for view in scrollView.subviews {
if view.isKind(of: UIImageView.self),
view.alpha == 0 && view.autoresizingMask == UIView.AutoresizingMask.flexibleLeftMargin,
view.frame.size.width < 10 && view.frame.size.height > view.frame.size.width,
scrollView.frame.size.height < scrollView.contentSize.height {
// Swizzle class for found imageView, that should be scroll indicator
object_setClass(view, AlwaysOpaqueImageView.self)
break
}
}
// Ask to flash indicator to turn it on
scrollView.flashScrollIndicators()
}
}
一个区别是设置滚动条是作为静态方法提取出来的。