Hon*_*ney 20 iphone cocoa-touch uiscrollview uikit ios
我需要在viewDidLoad上始终显示滚动条,以便用户可以理解有滚动的内容.我做了以下事情:
[myscrollView flashScrollIndicators];
Run Code Online (Sandbox Code Playgroud)
但是滚动条只会在viewDidLoad之后显示一段时间并再次消失,只是在用户触摸屏幕时重新出现.
我需要让滚动条始终可见.我该怎么做?
Ell*_*rry 19
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
Run Code Online (Sandbox Code Playgroud)
这最初归功于此来源.
这定义了一个类别,用于UIImageView定义alpha属性的自定义setter.这是有效的,因为在底层代码中的某些时候UIScrollView,它会将其滚动指示器的alpha属性设置为0以隐藏它.此时它将运行我们的类别,如果托管UIScrollView具有正确的标记,它将忽略正在设置的值,并将其显示.
为了使用此解决方案,请确保您UIScrollView拥有适当的标签,例如

如果要显示滚动指示器的UIScrollView可见时间,只需在视图出现时闪烁滚动指示器即.eg
- (void)viewDidAppear:(BOOL)animate
{
[super viewDidAppear:animate];
[self.scrollView flashScrollIndicators];
}
Run Code Online (Sandbox Code Playgroud)
其他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];
}
Run Code Online (Sandbox Code Playgroud)
新增班级
@interface AlwaysOpaqueImageView : UIImageView
@end
@implementation AlwaysOpaqueImageView
- (void)setAlpha:(CGFloat)alpha {
[super setAlpha:1.0];
}
@end
Run Code Online (Sandbox Code Playgroud)
滚动指示器(在这种情况下为垂直滚动指示器)将始终在屏幕上。
从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];
}
Run Code Online (Sandbox Code Playgroud)
@interface AlwaysOpaqueImageView : UIImageView
@end
@implementation AlwaysOpaqueImageView
- (void)setAlpha:(CGFloat)alpha {
[super setAlpha:1.0];
}
@end
Run Code Online (Sandbox Code Playgroud)
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];
}
Run Code Online (Sandbox Code Playgroud)
此步骤将在运行时创建被_UIScrollViewScrollIndicator调用的子类,AlwaysOpaqueScrollIndicator并将swizzle setAlpha:方法的实现实现为alwaysOpaque_setAlpha:。
不要忘记添加
#import <objc/runtime.h>
您插入此代码的文件。感谢@Smartcat提醒您