前言: 參考了不少文章泰涂,其都是使用KVO監(jiān)聽狀態(tài)變化實(shí)現(xiàn)的既绕。但是這樣需要多每個(gè)tableView對(duì)象進(jìn)行監(jiān)聽處理,或者新建一個(gè)父類去管理這些(適合新項(xiàng)目)霉猛。對(duì)于老舊項(xiàng)目來說比較麻煩谐鼎, 所以本文誕生了席楚。
思路
核心思路同樣是通過監(jiān)聽屬性狀態(tài)變化,但不是使用KVO畏浆,而是通過分類
特點(diǎn)
- 只需要引入該分類接口胆胰,不需要對(duì)原有項(xiàng)目進(jìn)行任何代碼更改
- 耦合度低,因?yàn)椴恍枰膭?dòng)原代碼刻获,所以隨時(shí)可以從項(xiàng)目中剝離
- 可以通過屬性蜀涨,控制頁面振動(dòng)反饋效果的開啟關(guān)閉:需要導(dǎo)入頭文件
- 適合新老項(xiàng)目
代碼演示
#import "MJRefreshComponent.h"
NS_ASSUME_NONNULL_BEGIN
@interface MJRefreshComponent (ImpactFeedbackGenerator)
// MARK: - 添加閥門控制屬性
/// 下拉刷新 是否需要禁止振動(dòng)反饋, 默認(rèn)NO
@property(nonatomic, assign) BOOL disableFeedbackOfMJHeader;
/// 上拉加載更多 是否需要禁止振動(dòng)反饋蝎毡, 默認(rèn)NO
@property(nonatomic, assign) BOOL disableFeedbackOfMJFooter;
// MARK: - 發(fā)起振動(dòng)api
/// 發(fā)起振動(dòng)
- (void)tl_impactOccurred;
+ (void)tl_impactOccurred;
@end
NS_ASSUME_NONNULL_END
#import "MJRefreshComponent+ImpactFeedbackGenerator.h"
#import <AudioToolbox/AudioToolbox.h>
#import <sys/utsname.h>
@implementation MJRefreshComponent (ImpactFeedbackGenerator)
// MARK: - 方法交換厚柳、監(jiān)聽狀態(tài)改變
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = NSClassFromString(@"MJRefreshComponent");
Method method1 = class_getInstanceMethod(cls, @selector(setState:));
Method method2 = class_getInstanceMethod(cls, @selector(tl_setState:));
method_exchangeImplementations(method1, method2);
});
}
- (void)tl_setState:(MJRefreshState)state {
if (self.state == MJRefreshStateIdle && state == MJRefreshStatePulling) {
BOOL flag = YES;
if ([self isKindOfClass:NSClassFromString(@"MJRefreshHeader")] && self.disableFeedbackOfMJHeader) {
flag = NO;
}
if ([self isKindOfClass:NSClassFromString(@"MJRefreshBackFooter")] && self.disableFeedbackOfMJFooter) {
flag = NO;
}
if (flag) {
[self tl_impactOccurred];
}
}
[self tl_setState:state];
}
// MARK: - 屬性關(guān)聯(lián)
- (void)setDisableFeedbackOfMJHeader:(BOOL)disableFeedbackOfMJHeader {
objc_setAssociatedObject(self, @selector(disableFeedbackOfMJHeader), @(disableFeedbackOfMJHeader), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)disableFeedbackOfMJHeader {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setDisableFeedbackOfMJFooter:(BOOL)disableFeedbackOfMJFooter {
objc_setAssociatedObject(self, @selector(disableFeedbackOfMJFooter), @(disableFeedbackOfMJFooter), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)disableFeedbackOfMJFooter {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
// MARK: - 發(fā)起震動(dòng)
- (void)tl_impactOccurred {
[MJRefreshComponent tl_impactOccurred];
}
+ (void)tl_impactOccurred {
if (@available(iOS 10.0, *)) {
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
if ([platform containsString:@"iPhone"]) {
NSString *p = [platform componentsSeparatedByString:@","].firstObject;
p = [p stringByReplacingOccurrencesOfString:@"iPhone" withString:@""];
if (p.intValue > 8) { // iPhone 7 +
UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
[generator prepare];
[generator impactOccurred];
return;
}
}
}
// iPhone 7之前的手機(jī)或iOS10之前的版本
// AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); // 效果差,力度和時(shí)間太過
AudioServicesPlayAlertSound(1520); // 1520與1519私有API
}
@end