小说绘上架版本
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// CAGradientLayer+Crash.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/6/25.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CAGradientLayer (Crash)
|
||||
|
||||
- (void)_clearContents;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// CAGradientLayer+Crash.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/6/25.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CAGradientLayer+Crash.h"
|
||||
|
||||
@implementation CAGradientLayer (Crash)
|
||||
|
||||
- (void)_clearContents
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,206 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifndef Release
|
||||
|
||||
@implementation NSSet(Log)
|
||||
|
||||
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
|
||||
{
|
||||
|
||||
NSMutableString *desc = [NSMutableString string];
|
||||
NSMutableString *tabString = [[NSMutableString alloc] initWithCapacity:level];
|
||||
for (NSUInteger i = 0; i < level; ++i) {
|
||||
[tabString appendString:@"\t"];
|
||||
}
|
||||
|
||||
NSString *tab = @"\t";
|
||||
if (level > 0) {
|
||||
tab = tabString;
|
||||
}
|
||||
[desc appendString:@"\t{(\n"];
|
||||
|
||||
for (id obj in self) {
|
||||
if ([obj isKindOfClass:[NSDictionary class]]
|
||||
|| [obj isKindOfClass:[NSArray class]]
|
||||
|| [obj isKindOfClass:[NSSet class]]) {
|
||||
NSString *str = [((NSDictionary *)obj) descriptionWithLocale:locale indent:level + 1];
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, str];
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, obj];
|
||||
} else if ([obj isKindOfClass:[NSData class]]) {
|
||||
// if is NSData,try parse
|
||||
NSError *error = nil;
|
||||
NSObject *result = [NSJSONSerialization JSONObjectWithData:obj
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
|
||||
if (error == nil && result != nil) {
|
||||
if ([result isKindOfClass:[NSDictionary class]]
|
||||
|| [result isKindOfClass:[NSArray class]]
|
||||
|| [result isKindOfClass:[NSSet class]]) {
|
||||
NSString *str = [((NSDictionary *)result) descriptionWithLocale:locale indent:level + 1];
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, str];
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, result];
|
||||
}
|
||||
} else {
|
||||
@try {
|
||||
NSString *str = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding];
|
||||
if (str != nil) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, str];
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
|
||||
[desc appendFormat:@"%@)}", tab];
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSArray (Log)
|
||||
|
||||
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
|
||||
{
|
||||
|
||||
NSMutableString *desc = [NSMutableString string];
|
||||
NSMutableString *tabString = [[NSMutableString alloc] initWithCapacity:level];
|
||||
for (NSUInteger i = 0; i < level; ++i) {
|
||||
[tabString appendString:@"\t"];
|
||||
}
|
||||
|
||||
NSString *tab = @"";
|
||||
if (level > 0) {
|
||||
tab = tabString;
|
||||
}
|
||||
[desc appendString:@"\t(\n"];
|
||||
|
||||
for (id obj in self) {
|
||||
if ([obj isKindOfClass:[NSDictionary class]]
|
||||
|| [obj isKindOfClass:[NSArray class]]
|
||||
|| [obj isKindOfClass:[NSSet class]]) {
|
||||
NSString *str = [((NSDictionary *)obj) descriptionWithLocale:locale indent:level + 1];
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, str];
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, obj];
|
||||
} else if ([obj isKindOfClass:[NSData class]]) {
|
||||
|
||||
NSError *error = nil;
|
||||
NSObject *result = [NSJSONSerialization JSONObjectWithData:obj
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
|
||||
if (error == nil && result != nil) {
|
||||
if ([result isKindOfClass:[NSDictionary class]]
|
||||
|| [result isKindOfClass:[NSArray class]]
|
||||
|| [result isKindOfClass:[NSSet class]]) {
|
||||
NSString *str = [((NSDictionary *)result) descriptionWithLocale:locale indent:level + 1];
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, str];
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, result];
|
||||
}
|
||||
} else {
|
||||
@try {
|
||||
NSString *str = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding];
|
||||
if (str != nil) {
|
||||
[desc appendFormat:@"%@\t\"%@\",\n", tab, str];
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@,\n", tab, obj];
|
||||
}
|
||||
}
|
||||
|
||||
[desc appendFormat:@"%@)", tab];
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSDictionary (Log)
|
||||
|
||||
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
|
||||
{
|
||||
|
||||
NSMutableString *desc = [NSMutableString string];
|
||||
NSMutableString *tabString = [[NSMutableString alloc] initWithCapacity:level];
|
||||
for (NSUInteger i = 0; i < level; ++i) {
|
||||
[tabString appendString:@"\t"];
|
||||
}
|
||||
|
||||
NSString *tab = @"";
|
||||
if (level > 0) {
|
||||
tab = tabString;
|
||||
}
|
||||
|
||||
[desc appendString:@"\t{\n"];
|
||||
|
||||
// Through array, self is array
|
||||
for (id key in self.allKeys) {
|
||||
id obj = [self objectForKey:key];
|
||||
|
||||
if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t%@ = \"%@\",\n", tab, key, obj];
|
||||
} else if ([obj isKindOfClass:[NSArray class]]
|
||||
|| [obj isKindOfClass:[NSDictionary class]]
|
||||
|| [obj isKindOfClass:[NSSet class]]) {
|
||||
[desc appendFormat:@"%@\t%@ = %@,\n", tab, key, [obj descriptionWithLocale:locale indent:level + 1]];
|
||||
} else if ([obj isKindOfClass:[NSData class]]) {
|
||||
|
||||
NSError *error = nil;
|
||||
NSObject *result = [NSJSONSerialization JSONObjectWithData:obj
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
|
||||
if (error == nil && result != nil) {
|
||||
if ([result isKindOfClass:[NSDictionary class]]
|
||||
|| [result isKindOfClass:[NSArray class]]
|
||||
|| [result isKindOfClass:[NSSet class]]) {
|
||||
NSString *str = [((NSDictionary *)result) descriptionWithLocale:locale indent:level + 1];
|
||||
[desc appendFormat:@"%@\t%@ = %@,\n", tab, key, str];
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
[desc appendFormat:@"%@\t%@ = \"%@\",\n", tab, key, result];
|
||||
}
|
||||
} else {
|
||||
@try {
|
||||
NSString *str = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding];
|
||||
if (str != nil) {
|
||||
[desc appendFormat:@"%@\t%@ = \"%@\",\n", tab, key, str];
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@ = %@,\n", tab, key, obj];
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[desc appendFormat:@"%@\t%@ = %@,\n", tab, key, obj];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[desc appendFormat:@"%@\t%@ = %@,\n", tab, key, obj];
|
||||
}
|
||||
}
|
||||
|
||||
[desc appendFormat:@"%@}", tab];
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSAttributedString+TReaderPage.h
|
||||
// Examda
|
||||
//
|
||||
// Created by tanyang on 16/1/26.
|
||||
// Copyright © 2016年 tanyang. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NSAttributedString (TReaderPage)
|
||||
|
||||
// 根据渲染图文大小分页,返回range数组
|
||||
- (NSArray *)pageRangeArrayWithConstrainedToSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// NSAttributedString+TReaderPage.m
|
||||
// Examda
|
||||
//
|
||||
// Created by tanyang on 16/1/26.
|
||||
// Copyright © 2016年 tanyang. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSAttributedString+TReaderPage.h"
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
@implementation NSAttributedString (TReaderPage)
|
||||
|
||||
//根据指定的大小,对字符串进行分页,计算出每页显示的字符串区间(NSRange)
|
||||
- (NSArray *)pageRangeArrayWithConstrainedToSize:(CGSize)size
|
||||
{
|
||||
NSAttributedString *attributedString = self;
|
||||
NSMutableArray * resultRange = [NSMutableArray array];
|
||||
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
||||
|
||||
NSInteger rangeIndex = 0;
|
||||
do {
|
||||
NSUInteger length = MIN(1500, attributedString.length - rangeIndex);
|
||||
NSAttributedString * childString = [attributedString attributedSubstringFromRange:NSMakeRange(rangeIndex, length)];
|
||||
CTFramesetterRef childFramesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) childString);
|
||||
UIBezierPath * bezierPath = [UIBezierPath bezierPathWithRect:rect];
|
||||
CTFrameRef frame = CTFramesetterCreateFrame(childFramesetter, CFRangeMake(0, 0), bezierPath.CGPath, NULL);
|
||||
|
||||
CFRange range = CTFrameGetVisibleStringRange(frame);
|
||||
NSRange r = {rangeIndex, range.length};
|
||||
if (r.length > 0) {
|
||||
[resultRange addObject:[NSValue valueWithRange:r]];
|
||||
}
|
||||
|
||||
if (r.length == 0) {
|
||||
rangeIndex ++;
|
||||
} else {
|
||||
rangeIndex += r.length;
|
||||
}
|
||||
CFRelease(frame);
|
||||
CFRelease(childFramesetter);
|
||||
} while (rangeIndex < attributedString.length && attributedString.length > 0);
|
||||
return resultRange;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// NSMutableArray+KVO.h
|
||||
// iOSHelper
|
||||
//
|
||||
// Created by Chair on 2020/3/5.
|
||||
// Copyright © 2020 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 当数组的元素发生改变时回调
|
||||
@interface NSMutableArray (KVO)
|
||||
|
||||
@property (nonatomic, copy) void(^changeBlock)(NSMutableArray *newVal);
|
||||
|
||||
- (void)KVO_addObject:(id)object;
|
||||
- (void)KVO_insertObject:(id)anObject atIndex:(NSUInteger)index;
|
||||
- (void)KVO_removeLastObject;
|
||||
- (void)KVO_removeObjectAtIndex:(NSUInteger)index;
|
||||
- (void)KVO_replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
|
||||
|
||||
- (void)KVO_addObjectsFromArray:(NSArray<id> *)otherArray;
|
||||
- (void)KVO_exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2;
|
||||
- (void)KVO_removeAllObjects;
|
||||
- (void)KVO_removeObject:(id)anObject inRange:(NSRange)range;
|
||||
- (void)KVO_removeObject:(id)anObject;
|
||||
- (void)KVO_removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range;
|
||||
- (void)KVO_removeObjectIdenticalTo:(id)anObject;
|
||||
- (void)KVO_removeObjectsFromIndices:(NSUInteger *)indices numIndices:(NSUInteger)cnt API_DEPRECATED("Not supported", macos(10.0,10.6), ios(2.0,4.0), watchos(2.0,2.0), tvos(9.0,9.0));
|
||||
- (void)KVO_removeObjectsInArray:(NSArray<id> *)otherArray;
|
||||
- (void)KVO_removeObjectsInRange:(NSRange)range;
|
||||
- (void)KVO_replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<id> *)otherArray range:(NSRange)otherRange;
|
||||
- (void)KVO_replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<id> *)otherArray;
|
||||
- (void)KVO_setArray:(NSArray<id> *)otherArray;
|
||||
|
||||
- (void)KVO_insertObjects:(NSArray<id> *)objects atIndexes:(NSIndexSet *)indexes;
|
||||
- (void)KVO_removeObjectsAtIndexes:(NSIndexSet *)indexes;
|
||||
- (void)KVO_replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray<id> *)objects;
|
||||
|
||||
- (void)KVO_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// NSMutableArray+KVO.m
|
||||
// iOSHelper
|
||||
//
|
||||
// Created by Chair on 2020/3/5.
|
||||
// Copyright © 2020 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSMutableArray+KVO.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char * identifier = "identifier";
|
||||
|
||||
@implementation NSMutableArray (KVO)
|
||||
|
||||
- (void)setChangeBlock:(void (^)(NSMutableArray * _Nonnull))changeBlock {
|
||||
if (!changeBlock) return ;
|
||||
|
||||
objc_setAssociatedObject(self, identifier, changeBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void (^)(NSMutableArray * _Nonnull))changeBlock {
|
||||
return objc_getAssociatedObject(self, identifier);
|
||||
}
|
||||
|
||||
- (void)KVO_addObject:(id)object {
|
||||
if (object == nil || [object isKindOfClass:NSNull.class]) return ;
|
||||
[self addObject:object];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_insertObject:(id)anObject atIndex:(NSUInteger)index {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self insertObject:anObject atIndex:index];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeLastObject {
|
||||
[self removeLastObject];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectAtIndex:(NSUInteger)index {
|
||||
[self removeObjectAtIndex:index];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self replaceObjectAtIndex:index withObject:anObject];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_addObjectsFromArray:(NSArray<id> *)otherArray {
|
||||
if (![otherArray isKindOfClass:NSArray.class]) return ;
|
||||
[self addObjectsFromArray:otherArray];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2 {
|
||||
[self exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeAllObjects {
|
||||
[self removeAllObjects];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObject:(id)anObject inRange:(NSRange)range {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self removeObject:anObject inRange:range];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObject:(id)anObject {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self removeObject:anObject];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self removeObjectIdenticalTo:anObject inRange:range];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectIdenticalTo:(id)anObject {
|
||||
if (anObject == nil || [anObject isKindOfClass:NSNull.class]) return ;
|
||||
[self removeObjectIdenticalTo:anObject];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectsFromIndices:(NSUInteger *)indices numIndices:(NSUInteger)cnt {
|
||||
[self removeObjectsFromIndices:indices numIndices:cnt];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectsInArray:(NSArray<id> *)otherArray {
|
||||
if (![otherArray isKindOfClass:NSArray.class]) return ;
|
||||
[self removeObjectsInArray:otherArray];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectsInRange:(NSRange)range {
|
||||
[self removeObjectsInRange:range];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<id> *)otherArray range:(NSRange)otherRange {
|
||||
if (![otherArray isKindOfClass:NSArray.class]) return ;
|
||||
[self replaceObjectsInRange:range withObjectsFromArray:otherArray range:otherRange];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<id> *)otherArray {
|
||||
if (![otherArray isKindOfClass:NSArray.class]) return ;
|
||||
[self replaceObjectsInRange:range withObjectsFromArray:otherArray];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_setArray:(NSArray<id> *)otherArray {
|
||||
if (![otherArray isKindOfClass:NSArray.class]) return ;
|
||||
[self setArray:otherArray];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_insertObjects:(NSArray<id> *)objects atIndexes:(NSIndexSet *)indexes {
|
||||
if (![objects isKindOfClass:NSArray.class]) return ;
|
||||
[self insertObjects:objects atIndexes:indexes];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_removeObjectsAtIndexes:(NSIndexSet *)indexes {
|
||||
[self removeObjectsAtIndexes:indexes];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray<id> *)objects {
|
||||
if (![objects isKindOfClass:NSArray.class]) return ;
|
||||
[self replaceObjectsAtIndexes:indexes withObjects:objects];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
- (void)KVO_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
|
||||
if (obj == nil || [obj isKindOfClass:NSNull.class]) return ;
|
||||
[self setObject:obj atIndexedSubscript:idx];
|
||||
self.changeBlock(self);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSObject+DZM.h
|
||||
// DZMAnimatedTransitioning
|
||||
//
|
||||
// Created by 邓泽淼 on 2017/12/22.
|
||||
// Copyright © 2017年 邓泽淼. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NSObject (DZM)
|
||||
|
||||
@property (nonatomic, weak, nullable) UIView *ATTarget;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// NSObject+DZM.m
|
||||
// DZMAnimatedTransitioning
|
||||
//
|
||||
// Created by 邓泽淼 on 2017/12/22.
|
||||
// Copyright © 2017年 邓泽淼. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+DZM.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const NSString *isATTarget = @"isATTarget";
|
||||
|
||||
@implementation NSObject (DZM)
|
||||
|
||||
- (void)setATTarget:(UIView *)ATTarget {
|
||||
|
||||
objc_setAssociatedObject(self, &isATTarget, ATTarget, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
- (UIView *)ATTarget {
|
||||
|
||||
return objc_getAssociatedObject(self, &isATTarget);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// NSObject+LSDefaults.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/10/9.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (LSDefaults)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// NSObject+LSDefaults.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/10/9.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+LSDefaults.h"
|
||||
|
||||
@implementation NSObject (LSDefaults)
|
||||
|
||||
+ (void)load{
|
||||
|
||||
SEL originalSelector = @selector(doesNotRecognizeSelector:);
|
||||
SEL swizzledSelector = @selector(sw_doesNotRecognizeSelector:);
|
||||
|
||||
Method originalMethod = class_getClassMethod(self, originalSelector);
|
||||
Method swizzledMethod = class_getClassMethod(self, swizzledSelector);
|
||||
|
||||
if(class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))){
|
||||
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
|
||||
}else{
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)sw_doesNotRecognizeSelector:(SEL)aSelector{
|
||||
//处理 _LSDefaults 崩溃问题
|
||||
if([[self description] isEqualToString:@"_LSDefaults"] && (aSelector == NSSelectorFromString(@"sharedInstance"))){
|
||||
return;
|
||||
}
|
||||
[self sw_doesNotRecognizeSelector:aSelector];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// NSObject+WXYZ_Observer.h
|
||||
// BW_Video
|
||||
//
|
||||
// Created by Chair on 2019/11/29.
|
||||
// Copyright © 2019 WXYZ. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** 启用KVO自动清除功能 */
|
||||
#define ENABLE_SWIZZ_IN_SIMPLEKVO 1
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (Observer)
|
||||
|
||||
/** 添加一个会自动释放的KVO */
|
||||
- (void)addObserver:(NSString *)keyPath complete:(void(^)(id obj, id _Nullable oldVal, id _Nullable newVal))complte;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// NSObject+WXYZ_Observer.m
|
||||
// BW_Video
|
||||
//
|
||||
// Created by Chair on 2019/11/29.
|
||||
// Copyright © 2019 WXYZ. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+Observer.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static NSString *helper;
|
||||
|
||||
@implementation NSObject (Observer)
|
||||
|
||||
- (void)addObserver:(NSString *)keyPath complete:(void (^)(id _Nonnull, id _Nullable, id _Nullable))complte {
|
||||
if (keyPath.length == 0 || complte == nil) return ;
|
||||
|
||||
[self addObserverBlockForKeyPath:keyPath block:complte];
|
||||
|
||||
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 11.0 && ENABLE_SWIZZ_IN_SIMPLEKVO) {
|
||||
NSString *objHash = [NSString stringWithFormat:@"%zd", [self modelHash]];
|
||||
NSString *pathHash = [NSString stringWithFormat:@"%zd", [keyPath modelHash]];
|
||||
helper = [objHash stringByAppendingString:pathHash];
|
||||
if (!objc_getAssociatedObject(self, &helper)) {
|
||||
objc_setAssociatedObject(self, &helper, helper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)load {
|
||||
// 判断版本是否小于11.0并且开关打开,然后替换系统的dealloc方法
|
||||
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 11.0 && ENABLE_SWIZZ_IN_SIMPLEKVO) {
|
||||
NSString *dealloc = @"dealloc";
|
||||
Method originalDealloc = class_getInstanceMethod(self, NSSelectorFromString(dealloc));
|
||||
Method kvoDealloc = class_getInstanceMethod(self, @selector(customDealloc));
|
||||
method_exchangeImplementations(originalDealloc, kvoDealloc);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)customDealloc {
|
||||
// 判断是否需要移除KVO
|
||||
if (objc_getAssociatedObject(self, &helper) != nil) {
|
||||
[self removeObserverBlocks];
|
||||
objc_setAssociatedObject(self, &helper, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
[self customDealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// NSObject+Utils.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/6/5.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (Utils)
|
||||
|
||||
- (BOOL)modelisEmpty;
|
||||
|
||||
+ (NSDictionary<NSString *, NSString *> *)propertyDict;
|
||||
|
||||
+ (NSArray<NSString *> *)propertyArr;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// NSObject+Utils.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/6/5.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+Utils.h"
|
||||
|
||||
#import "NSString+TFExtension.h"
|
||||
|
||||
@implementation NSObject (Utils)
|
||||
|
||||
/// 获取指定类中所有的属性信息(属性名-属性类型)
|
||||
+ (NSDictionary<NSString *, NSString *> *)propertyDict {
|
||||
// 属性数量
|
||||
unsigned int count;
|
||||
objc_property_t *properties = class_copyPropertyList(self, &count);
|
||||
NSMutableDictionary<NSString *, NSString *> *dic = [NSMutableDictionary dictionary];
|
||||
for (int i = 0; i < count; i++) {
|
||||
// 获取属性名称
|
||||
objc_property_t property = properties[i];
|
||||
const char *cName = property_getName(property);
|
||||
const char *cType = property_getAttributes(property);
|
||||
// 属性名称
|
||||
NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
|
||||
|
||||
// 属性类型
|
||||
NSString *type = [NSString stringWithCString:cType encoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
// 利用正则表达式获取正确类型
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=@\").*?(?=\")" options:NSRegularExpressionCaseInsensitive error:&error];
|
||||
if (error) {
|
||||
NSAssert(NO, error.localizedDescription ?: TFLocalizedString(@"动态获取属性类型错误"));
|
||||
return @{};
|
||||
}
|
||||
|
||||
NSTextCheckingResult *match = [regex firstMatchInString:type options:kNilOptions range:NSMakeRange(0, type.length)];
|
||||
if (match) {
|
||||
type = [type substringWithRange:match.range];
|
||||
} else {
|
||||
type = [self switchType:type];
|
||||
}
|
||||
|
||||
[dic setObject:type forKey:name];
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
/// 获取指定类中属性名数组
|
||||
+ (NSArray<NSString *> *)propertyArr {
|
||||
return [[self propertyDict] allKeys];
|
||||
}
|
||||
|
||||
+ (NSString *)switchType:(NSString *)type {
|
||||
NSString *sub = [type substringWithRange:NSMakeRange(1, 1)];
|
||||
if ([sub isEqualToString:@"i"] ||
|
||||
[sub isEqualToString:@"s"] ||
|
||||
[sub isEqualToString:@"I"] ||
|
||||
[sub isEqualToString:@"S"]) {
|
||||
return @"int";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"l"]) {
|
||||
return @"long";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"q"]) {
|
||||
return @"NSInteger";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"Q"]) {
|
||||
return @"NSUInteger";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"L"]) {
|
||||
return @"long";// unsigned long
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"f"]) {
|
||||
return @"float";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"d"]) {
|
||||
return @"CGFloat";
|
||||
}
|
||||
|
||||
if ([sub isEqualToString:@"B"]) {
|
||||
return @"BOOL";
|
||||
}
|
||||
|
||||
return @"int";
|
||||
}
|
||||
|
||||
/// 检查Model是否为空
|
||||
- (BOOL)modelisEmpty {
|
||||
for (NSString *name in [self.class propertyArr]) {
|
||||
SEL sel = NSSelectorFromString(name);
|
||||
if ([self respondsToSelector:sel]) {
|
||||
id obj = [self performSelectorWithArgs:sel];
|
||||
if (!kObjectIsEmpty(obj)) {
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"is", [name firstCapitalized]]);
|
||||
if ([self respondsToSelector:sel]) {
|
||||
id obj = [self performSelectorWithArgs:sel];
|
||||
if (!kObjectIsEmpty(obj)) {
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// NSString+TFExtension.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by 谢腾飞 on 2020/12/3.
|
||||
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (TFExtension)
|
||||
|
||||
- (NSString *)fileSize;
|
||||
|
||||
- (NSString *)safeSubstringWithRange:(NSRange)range;
|
||||
|
||||
- (BOOL)containChinese;
|
||||
|
||||
/// 获取正确的网络URL地址
|
||||
- (NSString *)networkUrl;
|
||||
|
||||
- (NSString *)firstCapitalized;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// NSString+TFExtension.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by 谢腾飞 on 2020/12/3.
|
||||
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+TFExtension.h"
|
||||
|
||||
@implementation NSString (TFExtension)
|
||||
|
||||
- (NSString *)fileSize
|
||||
{
|
||||
// 总大小
|
||||
unsigned long long size = 0;
|
||||
NSString *sizeText = @"";
|
||||
// 文件管理者
|
||||
NSFileManager *mgr = [NSFileManager defaultManager];
|
||||
|
||||
// 文件属性
|
||||
NSDictionary *attrs = [mgr attributesOfItemAtPath:self error:nil];
|
||||
// 如果这个文件或者文件夹不存在,或者路径不正确直接返回0;
|
||||
if (attrs == nil) return @"";
|
||||
if ([attrs.fileType isEqualToString:NSFileTypeDirectory]) { // 如果是文件夹
|
||||
// 获得文件夹的大小 == 获得文件夹中所有文件的总大小
|
||||
NSDirectoryEnumerator *enumerator = [mgr enumeratorAtPath:self];
|
||||
for (NSString *subpath in enumerator) {
|
||||
// 全路径
|
||||
NSString *fullSubpath = [self stringByAppendingPathComponent:subpath];
|
||||
// 累加文件大小
|
||||
size += [mgr attributesOfItemAtPath:fullSubpath error:nil].fileSize;
|
||||
|
||||
if (size >= pow(10, 9)) { // size >= 1GB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fGB", size / pow(10, 9)];
|
||||
} else if (size >= pow(10, 6)) { // 1GB > size >= 1MB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fMB", size / pow(10, 6)];
|
||||
} else if (size >= pow(10, 3)) { // 1MB > size >= 1KB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fKB", size / pow(10, 3)];
|
||||
} else { // 1KB > size
|
||||
sizeText = [NSString stringWithFormat:@"%zdB", (long)size];
|
||||
}
|
||||
}
|
||||
return sizeText;
|
||||
} else { // 如果是文件
|
||||
size = attrs.fileSize;
|
||||
if (size >= pow(10, 9)) { // size >= 1GB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fGB", size / pow(10, 9)];
|
||||
} else if (size >= pow(10, 6)) { // 1GB > size >= 1MB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fMB", size / pow(10, 6)];
|
||||
} else if (size >= pow(10, 3)) { // 1MB > size >= 1KB
|
||||
sizeText = [NSString stringWithFormat:@"%.2fKB", size / pow(10, 3)];
|
||||
} else { // 1KB > size
|
||||
sizeText = [NSString stringWithFormat:@"%zdB", (long)size];
|
||||
}
|
||||
}
|
||||
return sizeText;
|
||||
}
|
||||
|
||||
- (NSString *)safeSubstringWithRange:(NSRange)range
|
||||
{
|
||||
if (range.location > self.length) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
if (range.length > self.length) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
if ((range.location + range.length) > self.length) {
|
||||
return @"";
|
||||
}
|
||||
return [self substringWithRange:range];
|
||||
}
|
||||
|
||||
- (BOOL)containChinese
|
||||
{
|
||||
for (int i = 0; i < [self length]; i++) {
|
||||
unichar t_char = [self characterAtIndex:i];
|
||||
if (t_char >= 0x4E00 && t_char <= 0x9FA5) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
YYCache *_cache = nil;
|
||||
- (NSString *)networkUrl
|
||||
{
|
||||
if (!_cache) {
|
||||
_cache = [YYCache cacheWithName:@"networkingURL"];
|
||||
}
|
||||
if ([_cache containsObjectForKey:self]) {
|
||||
return self;
|
||||
} else {
|
||||
BOOL status = [self containChinese];
|
||||
if (status) {
|
||||
NSString *t_url = [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||
[_cache setObject:t_url forKey:self];
|
||||
return t_url;
|
||||
} else {
|
||||
[_cache setObject:self forKey:self];
|
||||
return self;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)firstCapitalized
|
||||
{
|
||||
NSString *firstStirng = [self substringToIndex:1];
|
||||
NSString *lastString = [self substringFromIndex:1];
|
||||
return [firstStirng.capitalizedString stringByAppendingString:lastString];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// NSURL+ImageURL.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/7/2.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSURL (ImageURL)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// NSURL+ImageURL.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/7/2.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSURL+ImageURL.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation NSURL (ImageURL)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
Method URLWithStringMethod = class_getClassMethod(self, @selector(URLWithString:));
|
||||
Method sc_URLWithStringMethod = class_getClassMethod(self, @selector(wxyz_URLWithString:));
|
||||
method_exchangeImplementations(URLWithStringMethod, sc_URLWithStringMethod);
|
||||
}
|
||||
|
||||
// 处理网络图片地址带中文的问题
|
||||
+ (NSURL *)wxyz_URLWithString:(NSString *)URLString
|
||||
{
|
||||
for (int i = 0; i < [URLString length]; i++) {
|
||||
int character = [URLString characterAtIndex:i];
|
||||
if (character > 0x4e00 && character < 0x9fff) { // 如果包含中文
|
||||
|
||||
// 转义中文内容
|
||||
NSString *t_string = [[URLString substringWithRange:NSMakeRange(i, 1)] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||
URLString = [URLString stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:t_string];
|
||||
}
|
||||
}
|
||||
|
||||
return [NSURL wxyz_URLWithString:URLString];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// UIButton+LayoutCallback.h
|
||||
// iOS_TEST
|
||||
//
|
||||
// Created by Chair on 2020/1/22.
|
||||
// Copyright © 2020 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/** 是否启用该功能 */
|
||||
#define ENABLE_SWIZZ_IN_SIMPLEFrame 1
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIButton (LayoutCallback)
|
||||
|
||||
#if ENABLE_SWIZZ_IN_SIMPLEFrame
|
||||
|
||||
/** 子视图布局完成后返回自身 */
|
||||
@property (nonatomic, copy) void(^frameBlock)(UIButton *button);
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// UIButton+LayoutCallback.m
|
||||
// iOS_TEST
|
||||
//
|
||||
// Created by Chair on 2020/1/22.
|
||||
// Copyright © 2020 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIButton+LayoutCallback.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char * identifier = "identifier";
|
||||
|
||||
@implementation UIButton (LayoutCallback)
|
||||
|
||||
#if ENABLE_SWIZZ_IN_SIMPLEFrame
|
||||
|
||||
+ (void)load {
|
||||
Method method1 = class_getInstanceMethod(self, @selector(layoutSubviews));
|
||||
Method method2 = class_getInstanceMethod(self, @selector(xl_Btn_layoutSubviews));
|
||||
method_exchangeImplementations(method1, method2);
|
||||
}
|
||||
|
||||
- (void)xl_Btn_layoutSubviews {
|
||||
[self xl_Btn_layoutSubviews];
|
||||
|
||||
!self.frameBlock ?: self.frameBlock(self);
|
||||
}
|
||||
|
||||
- (void)setFrameBlock:(void (^)(UIButton * _Nonnull))frameBlock {
|
||||
if (frameBlock == nil) return ;
|
||||
objc_setAssociatedObject(self, identifier, frameBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void (^)(UIButton * _Nonnull))frameBlock {
|
||||
return objc_getAssociatedObject(self, identifier);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// UIControl+EventInterval.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/7/23.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIControl (EventInterval)
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval touchEventInterval;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// UIControl+EventInterval.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/7/23.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIControl+EventInterval.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static char * const touchEventIntervalKey = "touchEventIntervalKey";
|
||||
static char * const eventUnavailableKey = "eventUnavailableKey";
|
||||
|
||||
@interface UIControl ()
|
||||
|
||||
@property (nonatomic, assign) BOOL eventUnavailable;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIControl (EventInterval)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
Method method = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
|
||||
Method qi_method = class_getInstanceMethod(self, @selector(qi_sendAction:to:forEvent:));
|
||||
method_exchangeImplementations(method, qi_method);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action functions
|
||||
|
||||
- (void)qi_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
|
||||
{
|
||||
if ([self isMemberOfClass:[UIButton class]]) {
|
||||
if (self.eventUnavailable == NO) {
|
||||
self.eventUnavailable = YES;
|
||||
[self qi_sendAction:action to:target forEvent:event];
|
||||
[self performSelector:@selector(setEventUnavailable:) withObject:0 afterDelay:self.touchEventInterval];
|
||||
}
|
||||
} else {
|
||||
[self qi_sendAction:action to:target forEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setter & Getter functions
|
||||
|
||||
- (NSTimeInterval)touchEventInterval
|
||||
{
|
||||
return [objc_getAssociatedObject(self, touchEventIntervalKey) doubleValue];
|
||||
}
|
||||
|
||||
- (void)setTouchEventInterval:(NSTimeInterval)touchEventInterval
|
||||
{
|
||||
objc_setAssociatedObject(self, touchEventIntervalKey, @(touchEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)eventUnavailable
|
||||
{
|
||||
return [objc_getAssociatedObject(self, eventUnavailableKey) boolValue];
|
||||
}
|
||||
|
||||
- (void)setEventUnavailable:(BOOL)eventUnavailable
|
||||
{
|
||||
objc_setAssociatedObject(self, eventUnavailableKey, @(eventUnavailable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// UIImage+Blur.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/5/20.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIImage (Blur)
|
||||
|
||||
/*
|
||||
1.白色,参数:
|
||||
透明度 0~1, 0为白, 1为深灰色
|
||||
半径:默认30,推荐值 3 半径值越大越模糊 ,值越小越清楚
|
||||
色彩饱和度(浓度)因子: 0是黑白灰, 9是浓彩色, 1是原色 默认1.8
|
||||
“彩度”,英文是称Saturation,即饱和度。将无彩色的黑白灰定为0,最鲜艳定为9s,这样大致分成十阶段,让数值和人的感官直觉一致。
|
||||
*/
|
||||
- (UIImage *)imgWithLightAlpha:(CGFloat)alpha radius:(CGFloat)radius colorSaturationFactor:(CGFloat)colorSaturationFactor;
|
||||
|
||||
- (UIImage *)imgWithBlur;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// UIImage+LightMode.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/5/20.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIImage+Blur.h"
|
||||
|
||||
#import <Accelerate/Accelerate.h>
|
||||
|
||||
@implementation UIImage (Blur)
|
||||
|
||||
- (UIImage *)imgWithLightAlpha:(CGFloat)alpha radius:(CGFloat)radius colorSaturationFactor:(CGFloat)colorSaturationFactor {
|
||||
UIColor *tintColor = [UIColor colorWithRed:180 / 255.0 green:180 / 255.0 blue:180 / 255.0 alpha:alpha];
|
||||
return [self imgBluredWithRadius:radius tintColor:tintColor saturationDeltaFactor:colorSaturationFactor maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imgWithBlur {
|
||||
return [self imgWithLightAlpha:0.1 radius:3 colorSaturationFactor:1];
|
||||
}
|
||||
|
||||
// 内部方法,核心代码,封装了毛玻璃效果 参数:半径,颜色,色彩饱和度
|
||||
- (UIImage *)imgBluredWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
|
||||
{
|
||||
CGRect imageRect = { CGPointZero, self.size };
|
||||
UIImage *effectImage = self;
|
||||
|
||||
BOOL hasBlur = blurRadius > __FLT_EPSILON__;
|
||||
BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
|
||||
if (hasBlur || hasSaturationChange) {
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef effectInContext = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(effectInContext, 1.0, -1.0);
|
||||
CGContextTranslateCTM(effectInContext, 0, -self.size.height);
|
||||
CGContextDrawImage(effectInContext, imageRect, self.CGImage);
|
||||
|
||||
vImage_Buffer effectInBuffer;
|
||||
effectInBuffer.data = CGBitmapContextGetData(effectInContext);
|
||||
effectInBuffer.width = CGBitmapContextGetWidth(effectInContext);
|
||||
effectInBuffer.height = CGBitmapContextGetHeight(effectInContext);
|
||||
effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
|
||||
vImage_Buffer effectOutBuffer;
|
||||
effectOutBuffer.data = CGBitmapContextGetData(effectOutContext);
|
||||
effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext);
|
||||
effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext);
|
||||
effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
|
||||
|
||||
if (hasBlur) {
|
||||
CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
|
||||
NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
|
||||
if (radius % 2 != 1) {
|
||||
radius += 1; // force radius to be odd so that the three box-blur methodology works.
|
||||
}
|
||||
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (int)radius, (int)radius, 0, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (int)radius, (int)radius, 0, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (int)radius, (int)radius, 0, kvImageEdgeExtend);
|
||||
}
|
||||
BOOL effectImageBuffersAreSwapped = NO;
|
||||
if (hasSaturationChange) {
|
||||
CGFloat s = saturationDeltaFactor;
|
||||
CGFloat floatingPointSaturationMatrix[] = {
|
||||
0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
|
||||
0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
|
||||
0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const int32_t divisor = 256;
|
||||
NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
|
||||
int16_t saturationMatrix[matrixSize];
|
||||
for (NSUInteger i = 0; i < matrixSize; ++i) {
|
||||
saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
|
||||
}
|
||||
if (hasBlur) {
|
||||
vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
|
||||
effectImageBuffersAreSwapped = YES;
|
||||
}
|
||||
else {
|
||||
vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
|
||||
}
|
||||
}
|
||||
if (!effectImageBuffersAreSwapped)
|
||||
effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
if (effectImageBuffersAreSwapped)
|
||||
effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
// 开启上下文 用于输出图像
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef outputContext = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(outputContext, 1.0, -1.0);
|
||||
CGContextTranslateCTM(outputContext, 0, -self.size.height);
|
||||
|
||||
// 开始画底图
|
||||
CGContextDrawImage(outputContext, imageRect, self.CGImage);
|
||||
|
||||
// 开始画模糊效果
|
||||
if (hasBlur) {
|
||||
CGContextSaveGState(outputContext);
|
||||
if (maskImage) {
|
||||
CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
|
||||
}
|
||||
CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
|
||||
CGContextRestoreGState(outputContext);
|
||||
}
|
||||
|
||||
// 添加颜色渲染
|
||||
if (tintColor) {
|
||||
CGContextSaveGState(outputContext);
|
||||
CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
|
||||
CGContextFillRect(outputContext, imageRect);
|
||||
CGContextRestoreGState(outputContext);
|
||||
}
|
||||
|
||||
// 输出成品,并关闭上下文
|
||||
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// UIImage+Color.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/6/4.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIImage (Color)
|
||||
|
||||
- (instancetype)imageWithColor:(UIColor *)color;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// UIImage+Color.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/6/4.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIImage+Color.h"
|
||||
|
||||
@implementation UIImage (Color)
|
||||
|
||||
- (instancetype)imageWithColor:(UIColor *)color {
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextTranslateCTM(context, 0, self.size.height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
CGContextSetBlendMode(context, kCGBlendModeNormal);
|
||||
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
|
||||
CGContextClipToMask(context, rect, self.CGImage);
|
||||
[color setFill];
|
||||
CGContextFillRect(context, rect);
|
||||
UIImage *t_image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return t_image;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// UIImageView+CornerRadius.h
|
||||
// MyPractise
|
||||
//
|
||||
// Created by lzy on 16/3/1.
|
||||
// Copyright © 2016年 lzy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIImageView (CornerRadius)
|
||||
|
||||
- (instancetype)initWithCornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType;
|
||||
|
||||
- (void)zy_cornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType;
|
||||
|
||||
- (instancetype)initWithRoundingRectImageView;
|
||||
|
||||
- (void)zy_cornerRadiusRoundingRect;
|
||||
|
||||
- (void)zy_attachBorderWidth:(CGFloat)width color:(UIColor *)color;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,300 @@
|
||||
//
|
||||
// UIImageView+CornerRadius.m
|
||||
// MyPractise
|
||||
//
|
||||
// Created by lzy on 16/3/1.
|
||||
// Copyright © 2016年 lzy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIImageView+CornerRadius.h"
|
||||
|
||||
#import "NSObject+Observer.h"
|
||||
|
||||
const char kProcessedImage;
|
||||
|
||||
@interface UIImageView ()
|
||||
|
||||
@property (assign, nonatomic) CGFloat zyRadius;
|
||||
@property (assign, nonatomic) UIRectCorner roundingCorners;
|
||||
@property (assign, nonatomic) CGFloat zyBorderWidth;
|
||||
@property (strong, nonatomic) UIColor *zyBorderColor;
|
||||
@property (assign, nonatomic) BOOL zyHadAddObserver;
|
||||
@property (assign, nonatomic) BOOL zyIsRounding;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation UIImageView (CornerRadius)
|
||||
/**
|
||||
* @brief init the Rounding UIImageView, no off-screen-rendered
|
||||
*/
|
||||
- (instancetype)initWithRoundingRectImageView {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self zy_cornerRadiusRoundingRect];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief init the UIImageView with cornerRadius, no off-screen-rendered
|
||||
*/
|
||||
- (instancetype)initWithCornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self zy_cornerRadiusAdvance:cornerRadius rectCornerType:rectCornerType];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief attach border for UIImageView with width & color
|
||||
*/
|
||||
- (void)zy_attachBorderWidth:(CGFloat)width color:(UIColor *)color {
|
||||
self.zyBorderWidth = width;
|
||||
self.zyBorderColor = color;
|
||||
}
|
||||
|
||||
#pragma mark - Kernel
|
||||
/**
|
||||
* @brief clip the cornerRadius with image, UIImageView must be setFrame before, no off-screen-rendered
|
||||
*/
|
||||
- (void)zy_cornerRadiusWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
||||
CGSize size = self.bounds.size;
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
|
||||
CGContextRef currentContext = UIGraphicsGetCurrentContext();
|
||||
if (nil == currentContext) {
|
||||
return;
|
||||
}
|
||||
UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadii:cornerRadii];
|
||||
[cornerPath addClip];
|
||||
[self.layer renderInContext:currentContext];
|
||||
[self drawBorder:cornerPath];
|
||||
UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
if (processedImage) {
|
||||
objc_setAssociatedObject(processedImage, &kProcessedImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
self.image = processedImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief clip the cornerRadius with image, draw the backgroundColor you want, UIImageView must be setFrame before, no off-screen-rendered, no Color Blended layers
|
||||
*/
|
||||
- (void)zy_cornerRadiusWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType backgroundColor:(UIColor *)backgroundColor {
|
||||
CGSize size = self.bounds.size;
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, YES, scale);
|
||||
CGContextRef currentContext = UIGraphicsGetCurrentContext();
|
||||
if (nil == currentContext) {
|
||||
return;
|
||||
}
|
||||
UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadii:cornerRadii];
|
||||
UIBezierPath *backgroundRect = [UIBezierPath bezierPathWithRect:self.bounds];
|
||||
[backgroundColor setFill];
|
||||
[backgroundRect fill];
|
||||
[cornerPath addClip];
|
||||
[self.layer renderInContext:currentContext];
|
||||
[self drawBorder:cornerPath];
|
||||
UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
if (processedImage) {
|
||||
objc_setAssociatedObject(processedImage, &kProcessedImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
self.image = processedImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set cornerRadius for UIImageView, no off-screen-rendered
|
||||
*/
|
||||
- (void)zy_cornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
||||
self.zyRadius = cornerRadius;
|
||||
self.roundingCorners = rectCornerType;
|
||||
self.zyIsRounding = NO;
|
||||
if (!self.zyHadAddObserver) {
|
||||
// [[self class] swizzleDealloc];
|
||||
// [self addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
|
||||
[self addObserver:KEY_PATH(self, image) complete:^(UIImageView * _Nonnull obj, id _Nullable oldVal, UIImage * _Nullable newImage) {
|
||||
if ([newImage isMemberOfClass:[NSNull class]]) {
|
||||
return;
|
||||
} else if ([objc_getAssociatedObject(newImage, &kProcessedImage) intValue] == 1) {
|
||||
return;
|
||||
}
|
||||
[obj validateFrame];
|
||||
if (obj.zyIsRounding) {
|
||||
[obj zy_cornerRadiusWithImage:newImage cornerRadius:obj.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
||||
} else if (0 != self.zyRadius && 0 != self.roundingCorners && nil != self.image) {
|
||||
[obj zy_cornerRadiusWithImage:newImage cornerRadius:obj.zyRadius rectCornerType:obj.roundingCorners];
|
||||
}
|
||||
}];
|
||||
self.zyHadAddObserver = YES;
|
||||
}
|
||||
//Xcode 8 xib 删除了控件的Frame信息,需要主动创造
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief become Rounding UIImageView, no off-screen-rendered
|
||||
*/
|
||||
- (void)zy_cornerRadiusRoundingRect {
|
||||
self.zyIsRounding = YES;
|
||||
if (!self.zyHadAddObserver) {
|
||||
// [[self class] swizzleDealloc];
|
||||
// [self addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
|
||||
[self addObserver:KEY_PATH(self, image) complete:^(UIImageView * _Nonnull obj, id _Nullable oldVal, UIImage * _Nullable newImage) {
|
||||
if ([newImage isMemberOfClass:[NSNull class]]) {
|
||||
return;
|
||||
} else if ([objc_getAssociatedObject(newImage, &kProcessedImage) intValue] == 1) {
|
||||
return;
|
||||
}
|
||||
[obj validateFrame];
|
||||
if (obj.zyIsRounding) {
|
||||
[obj zy_cornerRadiusWithImage:newImage cornerRadius:obj.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
||||
} else if (0 != self.zyRadius && 0 != self.roundingCorners && nil != self.image) {
|
||||
[obj zy_cornerRadiusWithImage:newImage cornerRadius:obj.zyRadius rectCornerType:obj.roundingCorners];
|
||||
}
|
||||
}];
|
||||
self.zyHadAddObserver = YES;
|
||||
}
|
||||
//Xcode 8 xib 删除了控件的Frame信息,需要主动创造
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
- (void)drawBorder:(UIBezierPath *)path {
|
||||
if (0 != self.zyBorderWidth && nil != self.zyBorderColor) {
|
||||
[path setLineWidth:2 * self.zyBorderWidth];
|
||||
[self.zyBorderColor setStroke];
|
||||
[path stroke];
|
||||
}
|
||||
}
|
||||
|
||||
//- (void)zy_dealloc {
|
||||
// if (self.zyHadAddObserver) {
|
||||
//// [self removeObserver:self forKeyPath:@"image"];
|
||||
// }
|
||||
// [self zy_dealloc];
|
||||
//}
|
||||
|
||||
- (void)validateFrame {
|
||||
if (self.frame.size.width == 0) {
|
||||
[self.class swizzleLayoutSubviews];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)swizzleMethod:(SEL)oneSel anotherMethod:(SEL)anotherSel {
|
||||
Method oneMethod = class_getInstanceMethod(self, oneSel);
|
||||
Method anotherMethod = class_getInstanceMethod(self, anotherSel);
|
||||
method_exchangeImplementations(oneMethod, anotherMethod);
|
||||
}
|
||||
//
|
||||
//+ (void)swizzleDealloc {
|
||||
// static dispatch_once_t onceToken;
|
||||
// dispatch_once(&onceToken, ^{
|
||||
// [self swizzleMethod:NSSelectorFromString(@"dealloc") anotherMethod:@selector(zy_dealloc)];
|
||||
// });
|
||||
//}
|
||||
|
||||
+ (void)swizzleLayoutSubviews {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[self swizzleMethod:@selector(layoutSubviews) anotherMethod:@selector(zy_LayoutSubviews)];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)zy_LayoutSubviews {
|
||||
[self zy_LayoutSubviews];
|
||||
if (self.zyIsRounding) {
|
||||
[self zy_cornerRadiusWithImage:self.image cornerRadius:self.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
||||
} else if (0 != self.zyRadius && 0 != self.roundingCorners && nil != self.image) {
|
||||
[self zy_cornerRadiusWithImage:self.image cornerRadius:self.zyRadius rectCornerType:self.roundingCorners];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KVO for .image
|
||||
//- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
// if ([keyPath isEqualToString:@"image"]) {
|
||||
// UIImage *newImage = change[NSKeyValueChangeNewKey];
|
||||
// if ([newImage isMemberOfClass:[NSNull class]]) {
|
||||
// return;
|
||||
// } else if ([objc_getAssociatedObject(newImage, &kProcessedImage) intValue] == 1) {
|
||||
// return;
|
||||
// }
|
||||
// [self validateFrame];
|
||||
// if (self.zyIsRounding) {
|
||||
// [self zy_cornerRadiusWithImage:newImage cornerRadius:self.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
||||
// } else if (0 != self.zyRadius && 0 != self.roundingCorners && nil != self.image) {
|
||||
// [self zy_cornerRadiusWithImage:newImage cornerRadius:self.zyRadius rectCornerType:self.roundingCorners];
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#pragma mark property
|
||||
- (CGFloat)zyBorderWidth {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
- (void)setZyBorderWidth:(CGFloat)zyBorderWidth {
|
||||
objc_setAssociatedObject(self, @selector(zyBorderWidth), @(zyBorderWidth), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (UIColor *)zyBorderColor {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setZyBorderColor:(UIColor *)zyBorderColor {
|
||||
objc_setAssociatedObject(self, @selector(zyBorderColor), zyBorderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)zyHadAddObserver {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
- (void)setZyHadAddObserver:(BOOL)zyHadAddObserver {
|
||||
objc_setAssociatedObject(self, @selector(zyHadAddObserver), @(zyHadAddObserver), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)zyIsRounding {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
- (void)setZyIsRounding:(BOOL)zyIsRounding {
|
||||
objc_setAssociatedObject(self, @selector(zyIsRounding), @(zyIsRounding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (UIRectCorner)roundingCorners {
|
||||
return [objc_getAssociatedObject(self, _cmd) unsignedLongValue];
|
||||
}
|
||||
|
||||
- (void)setRoundingCorners:(UIRectCorner)roundingCorners {
|
||||
objc_setAssociatedObject(self, @selector(roundingCorners), @(roundingCorners), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (CGFloat)zyRadius {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
- (void)setZyRadius:(CGFloat)zyRadius {
|
||||
objc_setAssociatedObject(self, @selector(zyRadius), @(zyRadius), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//ZYCornerRadius is available under the MIT license.
|
||||
//Please visit https://github.com/liuzhiyi1992/ZYCornerRadius for details.
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// YYLabel+LineBreak.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/4/2.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UILabel (LineBreak)
|
||||
|
||||
- (void)setLineBreakByTruncatingLastLineMiddle;
|
||||
|
||||
- (NSArray *)getSeparatedLinesArray;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// YYLabel+LineBreak.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2020/4/2.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UILabel+LineBreak.h"
|
||||
|
||||
@implementation UILabel (LineBreak)
|
||||
|
||||
- (void)setLineBreakByTruncatingLastLineMiddle {
|
||||
|
||||
if ( self.numberOfLines <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableString *limitedText = [NSMutableString string];
|
||||
NSArray *separatedLines = [self getSeparatedLinesArray];
|
||||
|
||||
if (separatedLines > 0) {
|
||||
|
||||
for (int i = 0; i < separatedLines.count; i ++) {
|
||||
if (i == separatedLines.count - 1) {
|
||||
UILabel *lastLineLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width / 2, MAXFLOAT)];
|
||||
lastLineLabel.font = self.font;
|
||||
lastLineLabel.text = [separatedLines lastObject];
|
||||
|
||||
NSArray *subSeparatedLines = [lastLineLabel getSeparatedLinesArray];
|
||||
NSString *lastLineText = [subSeparatedLines firstObject];
|
||||
NSInteger lastLineTextCount = lastLineText.length;
|
||||
[limitedText appendString:[NSString stringWithFormat:@"%@...",[lastLineText substringToIndex:lastLineTextCount]]];
|
||||
} else {
|
||||
[limitedText appendString:[separatedLines objectOrNilAtIndex:i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self setText:limitedText lineSpacing:5];
|
||||
|
||||
}
|
||||
|
||||
-(void)setText:(NSString*)text lineSpacing:(CGFloat)lineSpacing {
|
||||
if (!text || lineSpacing < 0.01) {
|
||||
self.text = text;
|
||||
return;
|
||||
}
|
||||
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
|
||||
[paragraphStyle setLineSpacing:lineSpacing]; //设置行间距
|
||||
[paragraphStyle setLineBreakMode:self.lineBreakMode];
|
||||
[paragraphStyle setAlignment:self.textAlignment];
|
||||
|
||||
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];
|
||||
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [text length])];
|
||||
self.attributedText = attributedString;
|
||||
}
|
||||
|
||||
- (NSArray *)getSeparatedLinesArray {
|
||||
NSString *text = [self text];
|
||||
if (!text || text.length <= 0) {
|
||||
return @[@""];
|
||||
}
|
||||
|
||||
UIFont *font = [self font];
|
||||
CGRect rect = [self frame];
|
||||
|
||||
CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL);
|
||||
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
|
||||
[attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
|
||||
|
||||
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
|
||||
|
||||
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
|
||||
|
||||
NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
|
||||
NSMutableArray *linesArray = [[NSMutableArray alloc] init];
|
||||
|
||||
for (id line in lines) {
|
||||
CTLineRef lineRef = (__bridge CTLineRef )line;
|
||||
CFRange lineRange = CTLineGetStringRange(lineRef);
|
||||
NSRange range = NSMakeRange(lineRange.location, lineRange.length);
|
||||
|
||||
NSString *lineString = [text substringWithRange:range];
|
||||
[linesArray addObject:lineString];
|
||||
}
|
||||
return (NSArray *)linesArray;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// UINavigationController+TFExtension.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by 谢腾飞 on 2020/12/1.
|
||||
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UINavigationController (TFExtension)
|
||||
|
||||
@property (nonatomic ,assign) BOOL isTransition;
|
||||
|
||||
// 执行转场动画
|
||||
- (void)jumpNextViewController:(UIViewController *)viewController animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// UINavigationController+TFExtension.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by 谢腾飞 on 2020/12/1.
|
||||
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UINavigationController+TFExtension.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char *transitionKey = "transitionKey";
|
||||
@implementation UINavigationController (TFExtension)
|
||||
|
||||
- (void)setIsTransition:(BOOL)isTransition
|
||||
{
|
||||
objc_setAssociatedObject(self, transitionKey, @(isTransition), OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
- (BOOL)isTransition
|
||||
{
|
||||
NSNumber *number = objc_getAssociatedObject(self, transitionKey);
|
||||
return [number boolValue];
|
||||
}
|
||||
|
||||
- (void)jumpNextViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
[viewController setValue:[NSNumber numberWithBool:YES] forKey:@"isAT"];
|
||||
|
||||
self.delegate = (id<UINavigationControllerDelegate>)viewController;
|
||||
self.isTransition = YES;
|
||||
|
||||
[self pushViewController:viewController animated:animated];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// UIPageViewController+DPGestureDeal.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/5/30.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIPageViewController (DPGestureDeal)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// UIPageViewController+DPGestureDeal.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/5/30.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIPageViewController+DPGestureDeal.h"
|
||||
#import "NSObject+YYAdd.h"
|
||||
|
||||
@implementation UIPageViewController (DPGestureDeal)
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
||||
{
|
||||
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
|
||||
[otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
|
||||
{
|
||||
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// UIScrollView+UITouch.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/7/7.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIScrollView (UITouch)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// UIScrollView+UITouch.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/7/7.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIScrollView+UITouch.h"
|
||||
|
||||
@implementation UIScrollView (UITouch)
|
||||
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
// 选其一即可
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
// [[self nextResponder] touchesBegan:touches withEvent:event];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2014 Suyeol Jeon (http:xoul.kr)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
@import UIKit;
|
||||
|
||||
FOUNDATION_EXPORT double UITextView_PlaceholderVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char UITextView_PlaceholderVersionString[];
|
||||
|
||||
@interface UITextView (Placeholder)
|
||||
|
||||
/* 占位文字 */
|
||||
@property (nonatomic, copy) NSString *placeholder;
|
||||
/* 占位文字颜色 */
|
||||
@property (nonatomic, strong) UIColor *placeholderColor;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,163 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2014 Suyeol Jeon (http:xoul.kr)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import "UITextView+Placeholder.h"
|
||||
|
||||
// 占位文字
|
||||
static const void *PlaceholderViewKey = &PlaceholderViewKey;
|
||||
// 占位文字颜色
|
||||
static const void *PlaceholderColorKey = &PlaceholderColorKey;
|
||||
|
||||
|
||||
@implementation UITextView (Placeholder)
|
||||
|
||||
#pragma mark - Swizzle Dealloc
|
||||
|
||||
#pragma mark - Swizzle Dealloc
|
||||
+ (void)load {
|
||||
// 交换dealoc
|
||||
Method dealoc = class_getInstanceMethod(self.class, NSSelectorFromString(@"dealloc"));
|
||||
Method myDealoc = class_getInstanceMethod(self.class, @selector(myDealoc));
|
||||
method_exchangeImplementations(dealoc, myDealoc);
|
||||
}
|
||||
|
||||
- (void)myDealoc {
|
||||
// 移除监听
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
UITextView *placeholderView = objc_getAssociatedObject(self, PlaceholderViewKey);
|
||||
|
||||
// 如果有值才去调用,这步很重要
|
||||
if (placeholderView) {
|
||||
NSArray *propertys = @[@"frame", @"bounds", @"font", @"text", @"textAlignment", @"textContainerInset"];
|
||||
for (NSString *property in propertys) {
|
||||
@try {
|
||||
[self removeObserver:self forKeyPath:property];
|
||||
} @catch (NSException *exception) {}
|
||||
}
|
||||
}
|
||||
[self myDealoc];
|
||||
}
|
||||
|
||||
#pragma mark - set && get
|
||||
- (UITextView *)placeholderView {
|
||||
|
||||
// 为了让占位文字和textView的实际文字位置能够完全一致,这里用UITextView
|
||||
UITextView *placeholderView = objc_getAssociatedObject(self, PlaceholderViewKey);
|
||||
|
||||
if (!placeholderView) {
|
||||
|
||||
placeholderView = [[UITextView alloc] init];
|
||||
placeholderView.hidden = (self.text.length > 0 && self.text);
|
||||
// 动态添加属性的本质是: 让对象的某个属性与值产生关联
|
||||
objc_setAssociatedObject(self, PlaceholderViewKey, placeholderView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
placeholderView = placeholderView;
|
||||
|
||||
// 设置基本属性
|
||||
self.scrollEnabled = placeholderView.scrollEnabled = placeholderView.showsHorizontalScrollIndicator = placeholderView.showsVerticalScrollIndicator = placeholderView.userInteractionEnabled = NO;
|
||||
placeholderView.textColor = [UIColor lightGrayColor];
|
||||
placeholderView.backgroundColor = [UIColor clearColor];
|
||||
[self refreshPlaceholderView];
|
||||
[self addSubview:placeholderView];
|
||||
|
||||
// 监听文字改变
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewTextChange) name:UITextViewTextDidChangeNotification object:self];
|
||||
|
||||
// 这些属性改变时,都要作出一定的改变,尽管已经监听了TextDidChange的通知,也要监听text属性,因为通知监听不到setText:
|
||||
NSArray *propertys = @[@"frame", @"bounds", @"font", @"text", @"textAlignment", @"textContainerInset"];
|
||||
|
||||
// 监听属性
|
||||
for (NSString *property in propertys) {
|
||||
[self addObserver:self forKeyPath:property options:NSKeyValueObservingOptionNew context:nil];
|
||||
}
|
||||
|
||||
}
|
||||
return placeholderView;
|
||||
}
|
||||
- (void)setPlaceholder:(NSString *)placeholder
|
||||
{
|
||||
// 为placeholder赋值
|
||||
[self placeholderView].text = placeholder;
|
||||
}
|
||||
|
||||
- (NSString *)placeholder
|
||||
{
|
||||
// 如果有placeholder值才去调用,这步很重要
|
||||
if (self.placeholderExist) {
|
||||
return [self placeholderView].text;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor
|
||||
{
|
||||
self.placeholderView.textColor = placeholderColor;
|
||||
|
||||
}
|
||||
|
||||
- (UIColor *)placeholderColor {
|
||||
|
||||
return self.placeholderView.textColor;
|
||||
}
|
||||
#pragma mark - KVO监听属性改变
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
[self refreshPlaceholderView];
|
||||
if ([keyPath isEqualToString:@"text"]) [self textViewTextChange];
|
||||
}
|
||||
|
||||
- (void)refreshPlaceholderView {
|
||||
|
||||
UITextView *placeholderView = objc_getAssociatedObject(self, PlaceholderViewKey);
|
||||
|
||||
// 如果有值才去调用,这步很重要
|
||||
if (placeholderView) {
|
||||
self.placeholderView.frame = self.bounds;
|
||||
self.placeholderView.font = self.font;
|
||||
self.placeholderView.textAlignment = self.textAlignment;
|
||||
self.placeholderView.textContainerInset = self.textContainerInset;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textViewTextChange {
|
||||
UITextView *placeholderView = objc_getAssociatedObject(self, PlaceholderViewKey);
|
||||
|
||||
// 如果有值才去调用,这步很重要
|
||||
if (placeholderView) {
|
||||
self.placeholderView.hidden = (self.text.length > 0 && self.text);
|
||||
}
|
||||
if (!self.isFirstResponder) [self becomeFirstResponder];
|
||||
}
|
||||
|
||||
// 判断是否有placeholder值,这步很重要
|
||||
- (BOOL)placeholderExist {
|
||||
|
||||
// 获取对应属性的值
|
||||
UITextView *placeholderView = objc_getAssociatedObject(self, PlaceholderViewKey);
|
||||
|
||||
// 如果有placeholder值
|
||||
if (placeholderView) return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// UIView+AZGradient.h
|
||||
// AZCategory
|
||||
//
|
||||
// Created by Alfred Zhang on 2017/6/29.
|
||||
// Copyright © 2017年 Alfred Zhang. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIView (AZGradient)
|
||||
|
||||
/* The array of CGColorRef objects defining the color of each gradient
|
||||
* stop. Defaults to nil. Animatable. */
|
||||
|
||||
@property(nullable, copy) NSArray *az_colors;
|
||||
|
||||
/* An optional array of NSNumber objects defining the location of each
|
||||
* gradient stop as a value in the range [0,1]. The values must be
|
||||
* monotonically increasing. If a nil array is given, the stops are
|
||||
* assumed to spread uniformly across the [0,1] range. When rendered,
|
||||
* the colors are mapped to the output colorspace before being
|
||||
* interpolated. Defaults to nil. Animatable. */
|
||||
|
||||
@property(nullable, copy) NSArray<NSNumber *> *az_locations;
|
||||
|
||||
/* The start and end points of the gradient when drawn into the layer's
|
||||
* coordinate space. The start point corresponds to the first gradient
|
||||
* stop, the end point to the last gradient stop. Both points are
|
||||
* defined in a unit coordinate space that is then mapped to the
|
||||
* layer's bounds rectangle when drawn. (I.e. [0,0] is the bottom-left
|
||||
* corner of the layer, [1,1] is the top-right corner.) The default values
|
||||
* are [.5,0] and [.5,1] respectively. Both are animatable. */
|
||||
|
||||
@property CGPoint az_startPoint;
|
||||
@property CGPoint az_endPoint;
|
||||
|
||||
+ (UIView *_Nullable)az_gradientViewWithColors:(NSArray<UIColor *> *_Nullable)colors locations:(NSArray<NSNumber *> *_Nullable)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;
|
||||
|
||||
- (void)az_setGradientBackgroundWithColors:(NSArray<UIColor *> *_Nullable)colors locations:(NSArray<NSNumber *> *_Nullable)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// UIView+AZGradient.m
|
||||
// AZCategory
|
||||
//
|
||||
// Created by Alfred Zhang on 2017/6/29.
|
||||
// Copyright © 2017年 Alfred Zhang. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+AZGradient.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation UIView (AZGradient)
|
||||
|
||||
|
||||
+ (Class)layerClass {
|
||||
return [CAGradientLayer class];
|
||||
}
|
||||
|
||||
+ (UIView *)az_gradientViewWithColors:(NSArray<UIColor *> *)colors locations:(NSArray<NSNumber *> *)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
|
||||
UIView *view = [[self alloc] init];
|
||||
[view az_setGradientBackgroundWithColors:colors locations:locations startPoint:startPoint endPoint:endPoint];
|
||||
return view;
|
||||
}
|
||||
|
||||
- (void)az_setGradientBackgroundWithColors:(NSArray<UIColor *> *)colors locations:(NSArray<NSNumber *> *)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
|
||||
NSMutableArray *colorsM = [NSMutableArray array];
|
||||
for (UIColor *color in colors) {
|
||||
[colorsM addObject:(__bridge id)color.CGColor];
|
||||
}
|
||||
self.az_colors = [colorsM copy];
|
||||
self.az_locations = locations;
|
||||
self.az_startPoint = startPoint;
|
||||
self.az_endPoint = endPoint;
|
||||
}
|
||||
|
||||
#pragma mark- Getter&Setter
|
||||
|
||||
- (NSArray *)az_colors {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setAz_colors:(NSArray *)colors {
|
||||
objc_setAssociatedObject(self, @selector(az_colors), colors, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
if ([self.layer isKindOfClass:[CAGradientLayer class]]) {
|
||||
[((CAGradientLayer *)self.layer) setColors:self.az_colors];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)az_locations {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setAz_locations:(NSArray<NSNumber *> *)locations {
|
||||
objc_setAssociatedObject(self, @selector(az_locations), locations, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
if ([self.layer isKindOfClass:[CAGradientLayer class]]) {
|
||||
[((CAGradientLayer *)self.layer) setLocations:self.az_locations];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)az_startPoint {
|
||||
return [objc_getAssociatedObject(self, _cmd) CGPointValue];
|
||||
}
|
||||
|
||||
- (void)setAz_startPoint:(CGPoint)startPoint {
|
||||
objc_setAssociatedObject(self, @selector(az_startPoint), [NSValue valueWithCGPoint:startPoint], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
if ([self.layer isKindOfClass:[CAGradientLayer class]]) {
|
||||
[((CAGradientLayer *)self.layer) setStartPoint:self.az_startPoint];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)az_endPoint {
|
||||
return [objc_getAssociatedObject(self, _cmd) CGPointValue];
|
||||
}
|
||||
|
||||
- (void)setAz_endPoint:(CGPoint)endPoint {
|
||||
objc_setAssociatedObject(self, @selector(az_endPoint), [NSValue valueWithCGPoint:endPoint], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
if ([self.layer isKindOfClass:[CAGradientLayer class]]) {
|
||||
[((CAGradientLayer *)self.layer) setEndPoint:self.az_endPoint];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation UILabel (AZGradient)
|
||||
|
||||
+ (Class)layerClass {
|
||||
return [CAGradientLayer class];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// UIView+BorderLine.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/5/24.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, UIBorderSideType) {
|
||||
UIBorderSideTypeAll = 0, // 全边框
|
||||
UIBorderSideTypeTop = 1 << 0, // 上侧边框
|
||||
UIBorderSideTypeBottom = 1 << 1, // 下侧边框
|
||||
UIBorderSideTypeLeft = 1 << 2, // 左侧边框
|
||||
UIBorderSideTypeRight = 1 << 3, // 右侧边框
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, UIBorderConnerType) {
|
||||
UIBorderConnerTypeLeftTop = 0, // 左上
|
||||
UIBorderConnerTypeLeftBottom = 1 << 0, // 左下
|
||||
UIBorderConnerTypeRightTop = 1 << 1, // 右上
|
||||
UIBorderConnerTypeRightBottom = 1 << 2, // 右下
|
||||
UIBorderConnerTypeTopLeft = 1 << 3, // 上左
|
||||
UIBorderConnerTypeTopRight = 1 << 4, // 上右
|
||||
UIBorderConnerTypeBottomLeft = 1 << 5, // 下左
|
||||
UIBorderConnerTypeBottomRight = 1 << 6, // 下右
|
||||
};
|
||||
|
||||
@interface UIView (BorderLine)
|
||||
|
||||
/**
|
||||
增加边框
|
||||
|
||||
@param borderWidth 边框宽度
|
||||
@param borderColor 边框颜色
|
||||
@param cornerRadius 边框圆角
|
||||
*/
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius;
|
||||
|
||||
/**
|
||||
增加边框
|
||||
|
||||
@param borderWidth 边框宽度
|
||||
@param borderColor 边框颜色
|
||||
@param cornerRadius 边框圆角
|
||||
@param borderType 边框类型
|
||||
*/
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius borderType:(UIBorderSideType)borderType;
|
||||
|
||||
/**
|
||||
增加边框
|
||||
|
||||
@param borderWidth 边框宽度
|
||||
@param borderColor 边框颜色
|
||||
@param cornerRadius 边框圆角
|
||||
@param borderType 边框类型
|
||||
@param connerSpaceWidth 角边距离
|
||||
@param connerType 角边类型
|
||||
*/
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius borderType:(UIBorderSideType)borderType connerSpaceWidth:(CGFloat)connerSpaceWidth connerType:(UIBorderConnerType)connerType;
|
||||
|
||||
// 设置正常背景色
|
||||
- (void)normalBackgroundColor;
|
||||
|
||||
// 设置选中背景色
|
||||
- (void)selectBackgroundColor;
|
||||
|
||||
// 添加圆角
|
||||
- (void)addRoundingCornersWithRoundingCorners:(UIRectCorner)corners;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// UIView+BorderLine.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/5/24.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+BorderLine.h"
|
||||
|
||||
@implementation UIView (BorderLine)
|
||||
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius borderType:(UIBorderSideType)borderType connerSpaceWidth:(CGFloat)connerSpaceWidth connerType:(UIBorderConnerType)connerType
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius borderType:(UIBorderSideType)borderType
|
||||
{
|
||||
CGFloat space = borderWidth / 2;
|
||||
|
||||
switch (borderType) {
|
||||
case UIBorderSideTypeAll: {
|
||||
CAShapeLayer *lineBorder = [[CAShapeLayer alloc] init];
|
||||
lineBorder.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
|
||||
[lineBorder setLineWidth:borderWidth];
|
||||
[lineBorder setStrokeColor:borderColor.CGColor];
|
||||
[lineBorder setFillColor:[UIColor clearColor].CGColor];
|
||||
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:lineBorder.frame byRoundingCorners:UIRectCornerAllCorners cornerRadii:(CGSizeMake(cornerRadius, cornerRadius))];
|
||||
lineBorder.path = path.CGPath;
|
||||
[self.layer addSublayer:lineBorder];
|
||||
}
|
||||
break;
|
||||
case UIBorderSideTypeLeft: {
|
||||
[self.layer addSublayer:[self addLineOriginPoint:CGPointMake(0.f, 0.f + space) toPoint:CGPointMake(0.0f, self.frame.size.height - space) color:borderColor borderWidth:borderWidth]];
|
||||
}
|
||||
break;
|
||||
case UIBorderSideTypeRight: {
|
||||
[self.layer addSublayer:[self addLineOriginPoint:CGPointMake(self.frame.size.width, 0.0f + space) toPoint:CGPointMake(self.frame.size.width, self.frame.size.height - space) color:borderColor borderWidth:borderWidth]];
|
||||
}
|
||||
break;
|
||||
case UIBorderSideTypeTop: {
|
||||
[self.layer addSublayer:[self addLineOriginPoint:CGPointMake(0.0f + space, 0.0f) toPoint:CGPointMake(self.frame.size.width - space, 0.0f) color:borderColor borderWidth:borderWidth]];
|
||||
}
|
||||
break;
|
||||
case UIBorderSideTypeBottom: {
|
||||
[self.layer addSublayer:[self addLineOriginPoint:CGPointMake(0.0f + space, self.frame.size.height) toPoint:CGPointMake(self.frame.size.width - space, self.frame.size.height) color:borderColor borderWidth:borderWidth]];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addBorderLineWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor cornerRadius:(CGFloat)cornerRadius
|
||||
{
|
||||
[self addBorderLineWithBorderWidth:borderWidth borderColor:borderColor cornerRadius:cornerRadius borderType:UIBorderSideTypeAll];
|
||||
}
|
||||
|
||||
- (CAShapeLayer *)addLineOriginPoint:(CGPoint)p0 toPoint:(CGPoint)p1 color:(UIColor *)color borderWidth:(CGFloat)borderWidth {
|
||||
|
||||
/// 线的路径
|
||||
UIBezierPath * bezierPath = [UIBezierPath bezierPath];
|
||||
[bezierPath moveToPoint:p0];
|
||||
[bezierPath addLineToPoint:p1];
|
||||
|
||||
CAShapeLayer * shapeLayer = [CAShapeLayer layer];
|
||||
shapeLayer.strokeColor = color.CGColor;
|
||||
shapeLayer.fillColor = [UIColor clearColor].CGColor;
|
||||
/// 添加路径
|
||||
shapeLayer.path = bezierPath.CGPath;
|
||||
/// 线宽度
|
||||
shapeLayer.lineWidth = borderWidth;
|
||||
return shapeLayer;
|
||||
}
|
||||
|
||||
- (void)normalBackgroundColor
|
||||
{
|
||||
//创建一个渐变的图层
|
||||
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
|
||||
gradientLayer.colors = @[(__bridge id)[UIColor colorWithHexString:@"#ffb084"].CGColor, (__bridge id)[UIColor colorWithHexString:@"#fd9a63"].CGColor];
|
||||
gradientLayer.locations = @[@0, @1.0];
|
||||
gradientLayer.startPoint = CGPointMake(0, 0);
|
||||
gradientLayer.endPoint = CGPointMake(0, 1.0);
|
||||
gradientLayer.frame = self.bounds;
|
||||
gradientLayer.name = @"gradientLayer";
|
||||
|
||||
//生成一个image
|
||||
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0);
|
||||
[gradientLayer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
//设置背景颜色
|
||||
self.backgroundColor = [UIColor colorWithPatternImage:img];
|
||||
}
|
||||
|
||||
- (void)selectBackgroundColor
|
||||
{
|
||||
self.backgroundColor = kColorRGBA(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
// 添加圆角
|
||||
- (void)addRoundingCornersWithRoundingCorners:(UIRectCorner)corners
|
||||
{
|
||||
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(12, 12)];
|
||||
CAShapeLayer *maskLayer = [CAShapeLayer layer];
|
||||
maskLayer.frame = self.bounds;
|
||||
maskLayer.path = maskPath.CGPath;
|
||||
self.layer.mask = maskLayer;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// UIView+LayoutSubviewsCallback.h
|
||||
// iOS_TEST
|
||||
//
|
||||
// Created by Chair on 2019/11/24.
|
||||
// Copyright © 2019 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
//#import <AppKit/AppKit.h>
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "UIButton+LayoutCallback.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIView (LayoutCallback)
|
||||
|
||||
#if ENABLE_SWIZZ_IN_SIMPLEFrame
|
||||
|
||||
/** 子视图布局完成后返回自身 */
|
||||
@property (nonatomic, copy) void(^frameBlock)(UIView *view);
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// UIView+LayoutSubviewsCallback.m
|
||||
// iOS_TEST
|
||||
//
|
||||
// Created by Chair on 2019/11/24.
|
||||
// Copyright © 2019 Chair. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+LayoutCallback.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char * identifier = "identifier";
|
||||
|
||||
@implementation UIView (LayoutCallback)
|
||||
|
||||
#if ENABLE_SWIZZ_IN_SIMPLEFrame
|
||||
|
||||
+ (void)load {
|
||||
Method method1 = class_getInstanceMethod(self, @selector(layoutSubviews));
|
||||
Method method2 = class_getInstanceMethod(self, @selector(xl_layoutSubviews));
|
||||
method_exchangeImplementations(method1, method2);
|
||||
}
|
||||
|
||||
- (void)xl_layoutSubviews {
|
||||
[self xl_layoutSubviews];
|
||||
|
||||
!self.frameBlock ?: self.frameBlock(self);
|
||||
}
|
||||
|
||||
- (void)setFrameBlock:(void (^)(UIView * _Nonnull))frameBlock {
|
||||
if (frameBlock == nil) return ;
|
||||
objc_setAssociatedObject(self, identifier, frameBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void (^)(UIView * _Nonnull))frameBlock {
|
||||
return objc_getAssociatedObject(self, identifier);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// UIView+TFExtension.h
|
||||
// EmotionFM
|
||||
//
|
||||
// Created by 谢腾飞 on 2018/10/27.
|
||||
// Copyright © 2018 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIView (TFExtension)
|
||||
|
||||
@property (nonatomic ,assign) CGPoint xtfei_origin;
|
||||
@property (nonatomic ,assign) CGSize xtfei_size;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_width;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_height;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_x;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_y;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_centerX;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_centerY;
|
||||
|
||||
@property (nonatomic ,assign) CGFloat xtfei_right;
|
||||
@property (nonatomic ,assign) CGFloat xtfei_bottom;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// UIView+TFExtension.m
|
||||
// EmotionFM
|
||||
//
|
||||
// Created by 谢腾飞 on 2018/10/27.
|
||||
// Copyright © 2018 xtfei_2011@126.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+TFExtension.h"
|
||||
|
||||
@implementation UIView (TFExtension)
|
||||
|
||||
- (CGPoint)xtfei_origin
|
||||
{
|
||||
return self.frame.origin;
|
||||
}
|
||||
|
||||
- (void)setXtfei_origin:(CGPoint)point
|
||||
{
|
||||
CGRect rect = self.frame;
|
||||
rect.origin = point;
|
||||
self.frame = rect;
|
||||
}
|
||||
|
||||
- (CGSize)xtfei_size
|
||||
{
|
||||
return self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setXtfei_size:(CGSize)xtfei_size
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size = xtfei_size;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_width
|
||||
{
|
||||
return self.frame.size.width;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_height
|
||||
{
|
||||
return self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setXtfei_width:(CGFloat)xtfei_width
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size.width = xtfei_width;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (void)setXtfei_height:(CGFloat)xtfei_height
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size.height = xtfei_height;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_x
|
||||
{
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setXtfei_x:(CGFloat)xtfei_x
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = xtfei_x;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_y
|
||||
{
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setXtfei_y:(CGFloat)xtfei_y
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = xtfei_y;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_centerX
|
||||
{
|
||||
return self.center.x;
|
||||
}
|
||||
|
||||
- (void)setXtfei_centerX:(CGFloat)xtfei_centerX
|
||||
{
|
||||
CGPoint center = self.center;
|
||||
center.x = xtfei_centerX;
|
||||
self.center = center;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_centerY
|
||||
{
|
||||
return self.center.y;
|
||||
}
|
||||
|
||||
- (void)setXtfei_centerY:(CGFloat)xtfei_centerY
|
||||
{
|
||||
CGPoint center = self.center;
|
||||
center.y = xtfei_centerY;
|
||||
self.center = center;
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_right
|
||||
{
|
||||
return CGRectGetMaxX(self.frame);
|
||||
}
|
||||
|
||||
- (CGFloat)xtfei_bottom
|
||||
{
|
||||
return CGRectGetMaxY(self.frame);
|
||||
}
|
||||
|
||||
- (void)setXtfei_right:(CGFloat)xtfei_right
|
||||
{
|
||||
self.xtfei_x = xtfei_right - self.xtfei_width;
|
||||
}
|
||||
|
||||
- (void)setXtfei_bottom:(CGFloat)xtfei_bottom
|
||||
{
|
||||
self.xtfei_y = xtfei_bottom - self.xtfei_height;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// UIViewController+Present.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/10/9.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIViewController (Present)
|
||||
|
||||
@property (nonatomic, assign) BOOL LL_automaticallySetModalPresentationStyle;
|
||||
|
||||
+ (BOOL)LL_automaticallySetModalPresentationStyle;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// UIViewController+Present.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2019/10/9.
|
||||
// Copyright © 2019 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIViewController+Present.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char *LL_automaticallySetModalPresentationStyleKey;
|
||||
|
||||
@implementation UIViewController (Present)
|
||||
|
||||
+ (void)load {
|
||||
Method originAddObserverMethod = class_getInstanceMethod(self, @selector(presentViewController:animated:completion:));
|
||||
Method swizzledAddObserverMethod = class_getInstanceMethod(self, @selector(LL_presentViewController:animated:completion:));
|
||||
method_exchangeImplementations(originAddObserverMethod, swizzledAddObserverMethod);
|
||||
}
|
||||
|
||||
- (void)setLL_automaticallySetModalPresentationStyle:(BOOL)LL_automaticallySetModalPresentationStyle {
|
||||
objc_setAssociatedObject(self, LL_automaticallySetModalPresentationStyleKey, @(LL_automaticallySetModalPresentationStyle), OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
- (BOOL)LL_automaticallySetModalPresentationStyle {
|
||||
id obj = objc_getAssociatedObject(self, LL_automaticallySetModalPresentationStyleKey);
|
||||
if (obj) {
|
||||
return [obj boolValue];
|
||||
}
|
||||
return [self.class LL_automaticallySetModalPresentationStyle];
|
||||
}
|
||||
|
||||
+ (BOOL)LL_automaticallySetModalPresentationStyle {
|
||||
if ([self isKindOfClass:[UIImagePickerController class]] || [self isKindOfClass:[UIAlertController class]]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)LL_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if (viewControllerToPresent.LL_automaticallySetModalPresentationStyle && ![NSStringFromClass([viewControllerToPresent class]) isEqualToString:@"BUDislikeViewController"] && ![NSStringFromClass([viewControllerToPresent class]) isEqualToString:@"BUDislikeNewViewController"]) {
|
||||
viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
}
|
||||
[self LL_presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
[self LL_presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// YYAnimatedImageView+Util.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/10/9.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "YYAnimatedImageView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface YYAnimatedImageView (Util)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// YYAnimatedImageView+Util.m
|
||||
// WXReader
|
||||
//
|
||||
// Created by LL on 2020/10/9.
|
||||
// Copyright © 2020 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "YYAnimatedImageView+Util.h"
|
||||
|
||||
@implementation YYAnimatedImageView (Util)
|
||||
|
||||
+ (void)load {
|
||||
// 获取系统的对象方法
|
||||
Method displayLayerMethod = class_getInstanceMethod(self, @selector(displayLayer:));
|
||||
|
||||
// 获取自己定义的对象方法
|
||||
Method displayLayerNewMethod = class_getInstanceMethod(self, @selector(displayLayerNew:));
|
||||
|
||||
// 方法交换
|
||||
method_exchangeImplementations(displayLayerMethod, displayLayerNewMethod);
|
||||
}
|
||||
|
||||
- (void)displayLayerNew:(CALayer *)layer {
|
||||
|
||||
Ivar imgIvar = class_getInstanceVariable([self class], "_curFrame");
|
||||
UIImage *img = object_getIvar(self, imgIvar);
|
||||
if (img) {
|
||||
layer.contents = (__bridge id)img.CGImage;
|
||||
} else {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
[super displayLayer:layer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user