OC-开发案例收集

MJRefresh增加振动反馈

2020-11-12  本文已影响0人  Gxdy

前言: 参考了不少文章,其都是使用KVO监听状态变化实现的。但是这样需要多每个tableView对象进行监听处理,或者新建一个父类去管理这些(适合新项目)。对于老旧项目来说比较麻烦, 所以本文诞生了。

思路

核心思路同样是通过监听属性状态变化,但不是使用KVO,而是通过分类

特点

  1. 只需要引入该分类接口,不需要对原有项目进行任何代码更改
  2. 耦合度低,因为不需要改动原代码,所以随时可以从项目中剥离
  3. 可以通过属性,控制页面振动反馈效果的开启关闭:需要导入头文件
  4. 适合新老项目

代码演示

#import "MJRefreshComponent.h"

NS_ASSUME_NONNULL_BEGIN

@interface MJRefreshComponent (ImpactFeedbackGenerator)

// MARK: - 添加阀门控制属性
/// 下拉刷新 是否需要禁止振动反馈, 默认NO
@property(nonatomic, assign) BOOL disableFeedbackOfMJHeader;
/// 上拉加载更多 是否需要禁止振动反馈, 默认NO
@property(nonatomic, assign) BOOL disableFeedbackOfMJFooter;

// MARK: - 发起振动api
/// 发起振动
- (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: - 方法交换、监听状态改变
+ (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: - 属性关联
- (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: - 发起震动
- (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之前的手机或iOS10之前的版本
    // AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); // 效果差,力度和时间太过
    AudioServicesPlayAlertSound(1520); // 1520与1519私有API
}
@end

上一篇下一篇

猜你喜欢

热点阅读