我想提供我的解决方案。我不喜欢最流行的类别变体(类别中的覆盖方法可能是一些不确定在运行时应该调用什么方法的原因,因为有两个方法具有相同的选择器)。
我改用调酒。而且我也不需要使用标签。
将此方法添加到具有滚动视图的视图控制器(在我的情况下为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
滚动指示器(在本例中为垂直滚动指示器)将始终显示在屏幕上。
2019 年 11 月更新
从 iOS 13 开始,UIScrollView 子类已更改。现在滚动指示器继承自 UIView 并有自己的 private 类,称为 _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];
}
- 添加新类(适用于早于 13 的 iOS)
@interface AlwaysOpaqueImageView : UIImageView
@end
@implementation AlwaysOpaqueImageView
- (void)setAlpha:(CGFloat)alpha {
[super setAlpha:1.0];
}
@end
- 在代码中的某处添加这些方法(与步骤 1 中相同的视图控制器,或所需的
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 提醒这一点