Commit a3f51f51 authored by 朱璇's avatar 朱璇

Merge branch 'zx/flutterSdk' into 'master'

Zx/flutter sdk

See merge request !34
parents 8f48499a 29a0c285
......@@ -309,7 +309,6 @@
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/GMBase/GMBase.framework",
"${BUILT_PRODUCTS_DIR}/GMCache/GMCache.framework",
"${PODS_ROOT}/../../GMFlutterSDK/Frameworks/App.framework",
"${PODS_ROOT}/../../GMFlutterSDK/Frameworks/Flutter.framework",
"${PODS_ROOT}/../../GMFlutterSDK/Frameworks/fluttertoast.framework",
"${PODS_ROOT}/../../GMFlutterSDK/Frameworks/flutter_boost.framework",
......@@ -343,7 +342,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMBase.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMCache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/App.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_boost.framework",
......
......@@ -15,7 +15,7 @@ PODS:
- AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession
- Alamofire (4.7.0)
- GMBase (1.2.1):
- GMBase (1.2.7):
- GMFoundation
- GMHud
- GMJSONModel
......@@ -32,49 +32,44 @@ PODS:
- GMFlutterSDK (0.1.0):
- GMBase
- GMPhobos
- GMFoundation (1.0.8)
- GMFoundation (1.0.9)
- GMHud (1.0.7):
- lottie-ios (= 2.5.2)
- MBProgressHUD (= 0.9.2)
- GMJSONModel (1.7.4)
- GMKit (1.3.2):
- GMKit/Category (= 1.3.2)
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/FDFullscreenPopGesture (= 1.3.2)
- GMKit/Kit (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMKit (1.4.1):
- GMKit/Category (= 1.4.1)
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Kit (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Category (1.3.2):
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMKit/Category (1.4.1):
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Color (1.3.2):
- GMKit/Color (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Constant (1.3.2):
- GMKit/Constant (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
- GMKit/FDFullscreenPopGesture (1.3.2):
- GMKit/Kit (1.4.1):
- GMKit/Category (= 1.4.1)
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Kit (1.3.2):
- GMKit/Category (= 1.3.2)
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Protocol (1.3.2):
- GMKit/Protocol (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
......@@ -96,10 +91,10 @@ PODS:
- Masonry (1.1.0)
- MBProgressHUD (0.9.2)
- MJExtension (3.2.2)
- MJRefresh (3.4.3)
- SDWebImage (5.8.4):
- SDWebImage/Core (= 5.8.4)
- SDWebImage/Core (5.8.4)
- MJRefresh (3.5.0)
- SDWebImage (5.9.1):
- SDWebImage/Core (= 5.9.1)
- SDWebImage/Core (5.9.1)
- TMCache (2.1.0)
- "UITableView+FDTemplateLayoutCell (1.4)"
......@@ -139,13 +134,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
Alamofire: 907e0a98eb68cdb7f9d1f541a563d6ac5dc77b25
GMBase: 8233aa9d51177f1c25d3b5bec479789cc304f6cb
GMBase: 694c79f9a944ef14394c42424df494a9d3acf236
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMFlutterSDK: 7fdedb842c536754d30fedffe87f14da91c1e02e
GMFoundation: e9f7fd9c6e5f133e09009b0ee5de4fce60ac5682
GMFoundation: 15130972d6b389f7ecfc9acfae6f90db23db7fb1
GMHud: feca48b3eda4f3a6f617f4bbaa3657316a245c1f
GMJSONModel: 5e81a98de668e9f93cf6ff77869f77b0d1a806be
GMKit: acc124a9e844ec1ce8300a6b9a8c3e26159f5963
GMKit: 25f9f79b51d9f8e3e1fdf18defcac051b0e95612
GMNetService: 78d729467b99b6ce9814d51efa4dcfa3ddebafe3
GMNetworking: 592b9b71f2a7d92203483276158ce3139ac789d2
GMPhobos: b4e16c162df6618c6f7d10f4649a5f32920961fd
......@@ -155,8 +150,8 @@ SPEC CHECKSUMS:
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1569cf7ace17a8bac47aabfbb8580a49690386d1
MJExtension: d9b9c74cbdeb724c1e9ecbb157b318276e62e876
MJRefresh: 53e3e3219f204425ee6d3e62e8733d3295944cd6
SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9
MJRefresh: 6afc955813966afb08305477dd7a0d9ad5e79a16
SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
TMCache: 95ebcc9b3c7e90fb5fd8fc3036cba3aa781c9bed
"UITableView+FDTemplateLayoutCell": 234e1582bcc4e18461af91155123bb96538ed030
......
......@@ -60,3 +60,12 @@
@property (nonatomic, assign) CGFloat fd_interactivePopMaxAllowedInitialDistanceToLeftEdge;
@end
typedef void (^_FDViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated);
@interface UIViewController (FDFullscreenPopGesturePrivate)
@property (nonatomic, copy) _FDViewControllerWillAppearInjectBlock fd_willAppearInjectBlock;
@end
......@@ -21,6 +21,7 @@
// SOFTWARE.
#import "UINavigationController+FDFullscreenPopGesture.h"
#import "GMPresentAnimation.h"
#import <objc/runtime.h>
@interface _FDFullscreenPopGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>
......@@ -64,19 +65,17 @@
return NO;
}
if ([topViewController conformsToProtocol:@protocol(GMCustomNavigationAnimationProtocol)]) {
id<GMCustomNavigationAnimationProtocol> controller = (id<GMCustomNavigationAnimationProtocol>)topViewController;
id<GMControllerAnimatedTransitioning> animation = controller.navigationAnimation;
[animation removeMaskWith:topViewController];
}
return YES;
}
@end
typedef void (^_FDViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated);
@interface UIViewController (FDFullscreenPopGesturePrivate)
@property (nonatomic, copy) _FDViewControllerWillAppearInjectBlock fd_willAppearInjectBlock;
@end
@implementation UIViewController (FDFullscreenPopGesturePrivate)
+ (void)load
......
......@@ -13,6 +13,8 @@
/// 自定义 navigation 动画类需要知道某一时刻是 push还是pop。
@property(nonatomic, assign) UINavigationControllerOperation transitionType;
@optional
- (void)removeMaskWith:(UIViewController *)topVc;
@end
/// 对于想要使用自定义 push、pop 动画的 controller,需要实现该协议。
......
......@@ -43,6 +43,11 @@
return nil;
}
//- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
// [super popViewControllerAnimated:animated];
//}
// 依据supportedInterfaceOrientations文档,控制旋转的代码需要写在root view controller,或者全屏的presenting controller
// app的root view controller就是这个GMNavigationController,所以相关控制代码在这里。
- (BOOL)shouldAutorotate {
......
......@@ -8,6 +8,10 @@
#import "GMCustomNavigationAnimationProtocol.h"
typedef NS_ENUM(NSUInteger, GMCustomAnimationType) {
GMCustomAnimationTypePush,
GMCustomAnimationTypePresent,
};
/// 模拟 presentController 动画
/// push 时下往上的位移动画,pop 时从上往下的位移动画
@interface GMPresentAnimation : NSObject <GMControllerAnimatedTransitioning>
......@@ -15,4 +19,7 @@
// 当 needMask = YES 时,会一个透明 mask 将 fromVC 与 toVC 隔开。默认为 NO。
@property (nonatomic, assign) BOOL needMask;
@property (nonatomic, assign) GMCustomAnimationType animationType;
- (void)removeMaskWith:(UIViewController *)topVc;
@end
......@@ -19,6 +19,7 @@
- (instancetype)init {
if (self = [super init]) {
self.animationType = GMCustomAnimationTypePresent;
self.duration = 0.3;
self.needMask = NO;
}
......@@ -49,7 +50,11 @@
// 先将toView放置在屏幕下边,为下一步的平移动画做准备
CGRect newFrame = toView.frame;
if (self.animationType == GMCustomAnimationTypePresent) {
newFrame.origin.y = CGRectGetHeight(bounds);
} else {
newFrame.origin.x = CGRectGetWidth(bounds);
}
toView.frame = newFrame;
// 从下到上的平移动画
......@@ -79,18 +84,20 @@
[[transitionContext containerView] insertSubview:toView belowSubview:toVC.snapshot];
CGRect newFrame = fromView.frame;
if (self.animationType == GMCustomAnimationTypePresent) {
newFrame.origin.y = CGRectGetHeight(bound);
} else {
newFrame.origin.x = CGRectGetWidth(bound);
}
// toView.frame = newFrame;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromView.frame = newFrame;
_mask.alpha = 0;
} completion:^(BOOL finished) {
if (self.needMask) {
[_mask removeFromSuperview];
}
// 动画结束后移除toVC.snapshot,留着会挡住toVC,用户无法交互
[toVC.snapshot removeFromSuperview];
// 需要将toVC.snapshot清空,下一次弹窗时再重新生成 snapshot,确保每一次 snapshot 为最新画面
toVC.snapshot = nil;
[self removeMaskWith:toVC];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
......@@ -107,4 +114,16 @@
}
}
- (void)removeMaskWith:(UIViewController *)topVc {
if (_mask.superview) {
[_mask removeFromSuperview];
}
// 动画结束后移除toVC.snapshot,留着会挡住toVC,用户无法交互
[topVc.snapshot removeFromSuperview];
// 需要将toVC.snapshot清空,下一次弹窗时再重新生成 snapshot,确保每一次 snapshot 为最新画面
topVc.snapshot = nil;
}
@end
......@@ -186,7 +186,6 @@
[_table reloadData];
[_table.mj_header endRefreshing];
[_table.mj_footer endRefreshing];
}
[self updateOtherUIData];
......
......@@ -98,6 +98,9 @@
/** @brief 获取http数据分页第一页起始位置,默认为0,下一页为startNum+每页的数据条数(默认为10) */
@property (nonatomic,assign) NSInteger startNum;
/** @brief 获取http数据分页第一页起始位置,默认为1,下一页为pag 1 */
@property (nonatomic,assign) NSInteger page;
/** @brief 获取http数据,每页获取数据(默认为10) */
@property (nonatomic,assign) NSInteger count;
......
......@@ -19,6 +19,7 @@
_dataArray = [[NSMutableArray alloc] init];
_startNum = 0;
_page = 1;
_params = nil;
_count = 10;
_deduplicationDic = [NSMutableDictionary dictionary];
......@@ -37,7 +38,8 @@
*/
- (void)buildParams{
_params = @{@"start_num":@(self.startNum),
@"count":@(self.count)};
@"count":@(self.count)
};
}
- (BOOL)shouldClearDataForResponse:(id)response{
......@@ -100,6 +102,7 @@
// 因为 clearData 可能会被外部调用,所以 self.startNum = 0 要确认执行,不能少
self.startNum = 0;
_deleteCount = 0;
_page = 1;
[self.dataArray removeAllObjects];
[_deduplicationDic removeAllObjects];
}
......@@ -107,12 +110,14 @@
- (void)handleHeaderRefreshing
{
self.startNum = 0;
self.page = 1;
[self fetchRemoteData];
}
- (void)handleFooterRereshing
{
self.startNum = self.dataArray.count + _deleteCount;
self.page+=1;
[self fetchRemoteData];
}
......
......@@ -28,13 +28,18 @@
*/
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string trimBothEndSpace:(BOOL)tripSpace trimInnerReturn:(BOOL)trimReturn font:(UIFont *)font color:(UIColor *)color lineSpacing:(CGFloat)spacing;
/**
* @brief 使用该方法返回 attributedString 的大小。比如指定{320, 99},那么就会返回一个不超过该大小的 size,且宽高都经过 ceilf 处理
* @brief 使用该方法返回 attributedString 的大小。比如指定{320, 99},那么就会返回一个不超过该大小的 size,且宽高都经过 ceilf 处理,内部变更AttributedString的lineBreakMode为NSLineBreakByTruncatingTail
*
* @param maxSize 指定的最大的 string 大小。
*
* @return 经过 ceilf 处理的最大 size
*/
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize;
/// 计算AttributedString的Size,内部不会变更AttributedString的lineBreakMode
/// @param maxSize 限制Size
- (CGSize)sizeForAttributeBoundingRectSize:(CGSize)maxSize;
@end
@interface NSMutableAttributedString (GM)
......
......@@ -82,6 +82,8 @@
return [attributedString mutableCopy];
}
/// 计算AttributedString的Size,内部变更AttributedString的lineBreakMode为NSLineBreakByTruncatingTail
/// @param maxSize 限制Size
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize{
// mutableCopy 以防修复原来的 string
......@@ -90,6 +92,7 @@
return CGSizeZero;
}
// 修改 lineBreakMode 为 NSLineBreakByWordWrapping,因为 Truncate tail 会在 boundingRectWithSize 中指定,在这里指定了,反而会导致 boundingRectWithSize 方法计算不准确
// 此处获取到的originStyle为原始NSMutableAttributedString的,对它进行变更,会直接影响到原NSMutableAttributedString
NSMutableParagraphStyle *originStyle = [self attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
originStyle.lineBreakMode = NSLineBreakByWordWrapping;
......@@ -98,6 +101,27 @@
originStyle.lineBreakMode = NSLineBreakByTruncatingTail;
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
/// 计算AttributedString的Size,内部不会变更AttributedString的lineBreakMode
/// @param maxSize 限制Size
- (CGSize)sizeForAttributeBoundingRectSize:(CGSize)maxSize {
NSMutableAttributedString *newAttribute = [self mutableCopy];
if (![newAttribute.string isNonEmpty]) {
return CGSizeZero;
}
NSMutableParagraphStyle *originStyle = [newAttribute attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
if (originStyle!= NSLineBreakByWordWrapping || originStyle!= NSLineBreakByCharWrapping) {
NSMutableParagraphStyle *newStyle = [NSMutableParagraphStyle new];
newStyle.lineBreakMode = NSLineBreakByWordWrapping;
[newAttribute addAttributes:@{NSParagraphStyleAttributeName:newStyle} range:NSMakeRange(0, newAttribute.string.length)];
[newAttribute addAttributes:@{NSParagraphStyleAttributeName:newStyle} range:NSMakeRange(0, newAttribute.string.length)];
}
CGSize size = [newAttribute boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:[[NSStringDrawingContext alloc] init]].size;
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
@end
@implementation NSMutableAttributedString (GM)
......
......@@ -171,6 +171,20 @@
*/
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size lineSpacing:(CGFloat)lineSpacing;
/// 计算String在限定size下的宽高
/// @param font String的font
/// @param size String限定的size
/// @param lineBreakMode 文字显示模式
- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode;
/// 计算String在某个字体下的宽度
/// @param font String的font
- (CGFloat)widthForFont:(UIFont *)font;
/// 计算String在限定宽度下的高度
/// @param font font String的font
/// @param width 限定宽度
- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width;
@end
......
......@@ -245,6 +245,39 @@
return CGSizeMake(ceil(resultSize.width), ceil(resultSize.height));
}
- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode {
CGSize result;
if (!font) font = [UIFont systemFontOfSize:12];
if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
NSMutableDictionary *attr = [NSMutableDictionary new];
attr[NSFontAttributeName] = font;
if (lineBreakMode != NSLineBreakByWordWrapping) {
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = lineBreakMode;
attr[NSParagraphStyleAttributeName] = paragraphStyle;
}
CGRect rect = [self boundingRectWithSize:size
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:attr context:nil];
result = rect.size;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
#pragma clang diagnostic pop
}
return result;
}
- (CGFloat)widthForFont:(UIFont *)font {
CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
return size.width;
}
- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width {
CGSize size = [self sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping];
return size.height;
}
@end
......
......@@ -12,20 +12,28 @@
typedef NS_ENUM(NSUInteger, GMEmptyViewType) {
GMEmptyViewTypeEmpty,
GMEmptyViewTypeException
GMEmptyViewTypeException,
GMEmptyViewTypeService
};
@protocol GMEmptyViewDelegate <NSObject>
- (void)emptyViewDidClickReload;
@optional
- (void)emptyViewDidClickSettingNetWork;
- (void)emptyViewDidClickService;
@end
@interface GMEmptyView : UIView
// tipIcon居上的距离
@property (nonatomic, assign) NSInteger iconTop;
/// 显示EmptyViewType
@property (nonatomic, assign) GMEmptyViewType type;
@property (nonatomic, weak) id<GMEmptyViewDelegate> delegate;
@property (nonatomic, strong) UIImageView *tipIcon;
@property (nonatomic, strong) UILabel *tipLabel;
@property (nonatomic, strong) GMButton *tipButton;
@property (nonatomic, strong) GMButton *checkNetworkButton;
@property (nonatomic, assign) GMEmptyViewType type;
@property (nonatomic, weak) id<GMEmptyViewDelegate> delegate;
@end
......@@ -15,127 +15,110 @@
#import <Constant.h>
#import <GMPhobos/Phobos.h>
#import <GMPhobos/UIResponder+PhobosPV.h>
@interface GMEmptyView()
@property (nonatomic, strong) UIButton *serviceBtn;;
@end
@implementation GMEmptyView
- (instancetype)initWithFrame:(CGRect)frame
{
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_iconTop = 155;
[self setup];
}
return self;
}
- (void)awakeFromNib{
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (void)setup{
- (void)setup {
self.backgroundColor = UIColor.whiteColor;
_tipIcon = [UIImageView new];
_tipLabel = [UILabel new];
_tipButton = [GMButton buttonWithCustomType:GMButtonTypeRedSemicircleGradient];
_tipButton.frame = CGRectMake(0, 0, 10, 10); //给一个默认的rect,让系统调用DrawRect方法
_checkNetworkButton = [GMButton buttonWithCustomType:GMButtonTypeGraySemicircleBorder];
_checkNetworkButton.frame = CGRectMake(0, 0, 10, 10); //给一个默认的rect,让系统调用DrawRect方法
[self addSubview:_tipIcon];
[_tipIcon addSubview:_tipLabel];
[self addSubview:_tipButton];
[self addSubview:_checkNetworkButton];
_tipLabel.numberOfLines = 2;
_tipLabel.preferredMaxLayoutWidth = 300;
_tipLabel.textColor = UIColor.bodyText;
_tipLabel.font = [UIFont gmFont:15];
_tipLabel.textAlignment = NSTextAlignmentCenter;
_tipButton.hidden = YES;
[_tipButton setTitle:@"重新加载" forState:UIControlStateNormal];
_tipButton.titleLabel.font = [UIFont gmFont:16];
[_tipButton setTitleColor:UIColor.bodyText forState:UIControlStateNormal];
[_tipButton addTarget:self action:@selector(reloadBtnTap) forControlEvents:UIControlEventTouchUpInside];
_checkNetworkButton.hidden = YES;
[_checkNetworkButton setTitle:@"检查网络设置" forState:UIControlStateNormal];
_checkNetworkButton.titleLabel.font = [UIFont gmFont:16];
[_checkNetworkButton setTitleColor:[UIColor colorWithHex:0xFF6080] forState:UIControlStateNormal];
_checkNetworkButton.layer.borderColor = [UIColor colorWithHex:0xFF5963].CGColor;
[_checkNetworkButton setBackgroundColor:[UIColor colorWithHex:0xFFFFFF] forState:UIControlStateNormal];
[_checkNetworkButton setBackgroundColor:[UIColor colorWithHex:0xFFFFFF] forState:UIControlStateHighlighted];
[_checkNetworkButton addTarget:self action:@selector(checkNetwork) forControlEvents:UIControlEventTouchUpInside];
// 剩下的位置信息将在layoutSubViews在指定
[_tipLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(_tipIcon.mas_bottom).offset(-15);
make.centerX.mas_equalTo(self);
}];
[_tipButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.width.mas_equalTo(150);
make.height.mas_equalTo(33);
}];
[_checkNetworkButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.width.mas_equalTo(150);
make.height.mas_equalTo(33);
}];
}
- (void)setType:(GMEmptyViewType)type{
_type = type;
switch (self.type) {
case GMEmptyViewTypeEmpty:{
_tipButton.hidden = YES;
_checkNetworkButton.hidden = YES;
_tipIcon.image = [UIImage imageNamed:@"empty"];
_tipLabel.text = @"此处太寂寥,社区等你撩";
self.tipLabel.textColor = UIColor.bodyText;
self.tipButton.hidden = YES;
self.checkNetworkButton.hidden = YES;
self.serviceBtn.hidden = YES;
self.tipIcon.image = [UIImage imageNamed:@"empty"];
self.tipLabel.text = @"此处太寂寥,社区等你撩";
break;
}
case GMEmptyViewTypeException:{
_tipButton.hidden = NO;
_checkNetworkButton.hidden = NO;
_tipIcon.image = [UIImage imageNamed:@"network_failed"];
_tipLabel.text = @"原谅我一看到美人就不淡定";
self.tipLabel.textColor = UIColor.bodyText;
self.tipButton.hidden = NO;
self.checkNetworkButton.hidden = YES;
self.serviceBtn.hidden = YES;
self.tipIcon.image = [UIImage imageNamed:@"network_failed"];
self.tipLabel.text = @"原谅我一看到美人就不淡定";
break;
}
case GMEmptyViewTypeService:{
self.tipButton.hidden = YES;
self.checkNetworkButton.hidden = YES;
self.serviceBtn.hidden = NO;
self.tipIcon.image = [UIImage imageNamed:@"search_result_empty"];
[self.serviceBtn setBackgroundImage:[UIImage imageNamed:@"empty_service"] forState:UIControlStateNormal];
[self.serviceBtn setBackgroundImage:[UIImage imageNamed:@"empty_service"] forState:UIControlStateHighlighted];
self.tipLabel.textColor = RGBCOLOR_HEX(0x666666);
self.tipLabel.text = @"找不到合适的机构?撩一下更美咨询师吧~";
break;
}
default:
break;
}
[self updateViewConstraints];
}
- (void)layoutSubviews {
[super layoutSubviews];
// 在即将显示时,通过判断emptyView.y的坐标来优化subviews的坐标,以达到UI的要求
CGRect emptyViewFrameInWindow = [self.superview convertRect:self.frame toView:[UIApplication sharedApplication].keyWindow];
CGRect newTipIconFrameInWindow = CGRectMake(0, 0, 175, 199);
newTipIconFrameInWindow.origin.x = (MAINSCREEN_WIDTH - newTipIconFrameInWindow.size.width) / 2;
/*
以下坐标均相对于window
按照设计图
如果emptyViewFrameInWindow.y <= 64,那么tipIcon.y = 155
如果emptyViewFrameInWindow.y > 64 && y < 140,那么tipIcon.y = 185
另外测试时发现标签详情页的头部更多,所有else分支也成为了一种可能
如果emptyViewFrameInWindow.y > 140,那么tipIcon.y = 220
*/
// 按照设计图总结出来,
if (emptyViewFrameInWindow.origin.y <= 64) {
// 正常空间
newTipIconFrameInWindow.origin.y = 155;
} else if (emptyViewFrameInWindow.origin.y > 64.0 && emptyViewFrameInWindow.origin.y <= 140){
// 需要更多空间
newTipIconFrameInWindow.origin.y = 185;
} else {
newTipIconFrameInWindow.origin.y = 220;
}
CGRect newTipIconFrame = [[UIApplication sharedApplication].keyWindow convertRect:newTipIconFrameInWindow toView:self];
newTipIconFrameInWindow.origin.y = newTipIconFrame.origin.y;
_tipIcon.frame = newTipIconFrameInWindow;
_tipButton.top = _tipIcon.bottom + 15;
_checkNetworkButton.top = _tipButton.bottom + 20;
- (void)updateViewConstraints {
[self.tipIcon mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.iconTop);
make.centerX.mas_equalTo(0);
}];
[self.tipLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.tipIcon.mas_bottom).offset(-15);
make.centerX.mas_equalTo(0);
}];
[self.tipButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.tipIcon.mas_bottom).offset(10);
make.centerX.mas_equalTo(0);
make.width.mas_equalTo(150);
make.height.mas_equalTo(33);
}];
[self.checkNetworkButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.tipIcon.mas_bottom).offset(10);
make.centerX.mas_equalTo(0);
make.width.mas_equalTo(150);
make.height.mas_equalTo(33);
}];
[self.serviceBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.tipIcon.mas_bottom).offset(10);
make.centerX.mas_equalTo(0);
make.width.mas_equalTo(125);
make.height.mas_equalTo(35);
}];
}
- (void)clickService {
if ([self.delegate respondsToSelector:@selector(emptyViewDidClickService)]) {
[self.delegate emptyViewDidClickService];
}
}
- (void)reloadBtnTap {
......@@ -151,4 +134,66 @@
NSURL *appSettings = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:appSettings];
}
#pragma mark - UILabel
- (UIImageView *)tipIcon {
if (!_tipIcon) {
_tipIcon = [UIImageView new];
[self addSubview:_tipIcon];
}
return _tipIcon;
}
- (UILabel *)tipLabel {
if (!_tipLabel) {
_tipLabel = [UILabel new];
_tipLabel.numberOfLines = 2;
_tipLabel.preferredMaxLayoutWidth = 300;
_tipLabel.textColor = UIColor.bodyText;
_tipLabel.font = [UIFont gmFont:15];
_tipLabel.textAlignment = NSTextAlignmentCenter;
[self.tipIcon addSubview:_tipLabel];
}
return _tipLabel;
}
-(GMButton *)tipButton {
if (!_tipButton) {
_tipButton = [GMButton buttonWithCustomType:GMButtonTypeRedSemicircleGradient];
_tipButton.hidden = YES;
[_tipButton setTitle:@"重新加载" forState:UIControlStateNormal];
_tipButton.titleLabel.font = [UIFont gmFont:16];
[_tipButton setTitleColor:UIColor.bodyText forState:UIControlStateNormal];
[_tipButton addTarget:self action:@selector(reloadBtnTap) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_tipButton];
}
return _tipButton;
}
- (GMButton *)checkNetworkButton {
if (!_checkNetworkButton) {
//给一个默认的rect,让系统调用DrawRect方法
_checkNetworkButton = [GMButton buttonWithCustomType:GMButtonTypeGraySemicircleBorder];
[_checkNetworkButton setTitle:@"检查网络设置" forState:UIControlStateNormal];
_checkNetworkButton.titleLabel.font = [UIFont gmFont:16];
[_checkNetworkButton setTitleColor:[UIColor colorWithHex:0xFF6080] forState:UIControlStateNormal];
_checkNetworkButton.layer.borderColor = [UIColor colorWithHex:0xFF5963].CGColor;
[_checkNetworkButton setBackgroundColor:[UIColor colorWithHex:0xFFFFFF] forState:UIControlStateNormal];
[_checkNetworkButton setBackgroundColor:[UIColor colorWithHex:0xFFFFFF] forState:UIControlStateHighlighted];
_checkNetworkButton.hidden = YES;
[_checkNetworkButton addTarget:self action:@selector(checkNetwork) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_checkNetworkButton];
}
return _checkNetworkButton;
}
- (UIButton *)serviceBtn {
if (!_serviceBtn) {
_serviceBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_serviceBtn addTarget:self action:@selector(clickService) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_serviceBtn];
}
return _serviceBtn;
}
@end
......@@ -14,6 +14,10 @@ typedef NS_ENUM(NSUInteger, WYSegmentViewWidthStyle) {
WYSegmentViewWidthStyleEqual // Segment width is equal
};
typedef NS_ENUM(NSUInteger, GMSegmentBtnStyle) {
GMSegmentBtnStyleCommon = 0, // 普通的文字
GMSegmentBtnStyleLive = 1, // live 图片
};
@interface WYSegmentView : GMView
/**
......@@ -21,6 +25,12 @@ typedef NS_ENUM(NSUInteger, WYSegmentViewWidthStyle) {
*/
@property (nonatomic, strong) NSArray *sectionTitles;
/**
如果含有非文字类型的btn,则在该数组中对应的index 传入相关的类型和图片url,如果全是文字类型的,可不使用该字段
eg:[{'btnStyle':'GMSegmentBtnStylexxx','tabNameImage':'tab图片','iconUrl':'live动图'}]
*/
@property (nonatomic, strong) NSArray *sectionTitlesInfor;
@property (nonatomic, readonly) NSInteger selectedSegmentIndex;
@property (nonatomic, copy) void (^didSelectedBlock)(NSUInteger index);
......
......@@ -16,6 +16,9 @@
#import <UIColor+GMTheme.h>
#import "GMButton.h"
#import "UIDevice+Resolutions.h"
#import "UIButton+WebCache.h"
#import "UIImage+MultiFormat.h"
#import "UIImageView+WebCache.h"
#define BUTTON_TAG 1010
@interface WYSegmentView ()
......@@ -103,12 +106,77 @@
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
NSString *title = _sectionTitles[i];
NSAttributedString *attriTitle = [[NSAttributedString alloc] initWithString:title attributes:self.titleTextAttributes];
[button setAttributedTitle:attriTitle forState:UIControlStateNormal];
NSAttributedString *seletedAttriTitle = [[NSAttributedString alloc] initWithString:title attributes:self.selectedTitleTextAttributes];
__block CGFloat btnW = [seletedAttriTitle size].width;
CGFloat btnTitleH = [seletedAttriTitle size].height;
if (self.sectionTitlesInfor != nil &&
self.sectionTitlesInfor.count > i &&
[self.sectionTitlesInfor[i] isKindOfClass:[NSDictionary class]] &&
((GMSegmentBtnStyle)[(self.sectionTitlesInfor[i][@"btnStyle"]) integerValue]) == GMSegmentBtnStyleLive) {
NSString *imgurl = self.sectionTitlesInfor[i][@"tabNameImage"];
if (imgurl && imgurl.length > 0) {
__block CGFloat imgW = 32;
CGFloat imgH = btnTitleH;
UIImageView *contentIv = [UIImageView new];
[button addSubview:contentIv];
contentIv.tag = 1;
[contentIv sd_setImageWithURL:[NSURL URLWithString:imgurl] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
// 防止多次下载同一张图片,上次下载被取消后返回nil的造成的carsh
if (image == nil) return;
// 如果该button已经被移除了,就不再进行约束更新操作
if (contentIv.superview.superview == nil) return;
imgW = ceil((image.size.width * 40)/image.size.height);
[contentIv mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(imgW);
}];
btnW = imgW;
}];
[contentIv mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(imgW);
make.height.mas_equalTo(40);
make.center.mas_equalTo(button.center);
}];
NSString *iconUrl = self.sectionTitlesInfor[i][@"iconUrl"];
if (iconUrl && iconUrl.length > 0) {
UIImageView *liveIv = [UIImageView new];
liveIv.tag = 2;
__block CGFloat liveIvW = 40;
[liveIv sd_setImageWithURL:[NSURL URLWithString:iconUrl] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
// 防止多次下载同一张图片,上次下载被取消后返回nil的造成的carsh
if (image == nil) return;
// 如果该button已经被移除了,就不再进行约束更新操作
if (liveIv.superview.superview == nil) return;
liveIvW = (image.size.width * 40.0)/image.size.height;
[liveIv mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(liveIvW);
}];
}];
liveIv.clipsToBounds = NO;
[button addSubview:liveIv];
[liveIv mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(liveIvW);
make.height.mas_equalTo(40);
make.left.mas_equalTo(contentIv.mas_right).mas_offset(-7);
make.centerY.mas_equalTo(contentIv.centerY);
}];
}
}else{
// 如果是Live类型,但是没有图片url,则不显示该btn
btnW = 0;
button.alpha = 0;
}
}else{
[button setAttributedTitle:attriTitle forState:UIControlStateNormal];
[button setAttributedTitle:seletedAttriTitle forState:UIControlStateSelected];
}
[_container addSubview:button];
button.width = [seletedAttriTitle size].width;
button.width = btnW;
allTitleSize += button.width;
}
// 为buttons添加约束信息
......@@ -141,7 +209,8 @@
make.right.mas_equalTo(0);
}
}else { // 动态样式
make.width.mas_equalTo(ceilf(button.width + _itemHorizonalPadding * 2));
// button.width == 0 兼容 非文字的btn并且未获取到图片url的情况
make.width.mas_equalTo(button.width > 0 ? ceilf(button.width + _itemHorizonalPadding * 2) : 0);
if(i == 0) {
make.left.mas_equalTo(0);
}else {
......@@ -184,6 +253,13 @@
_indicatorView.backgroundColor = _indicatorColor;
}
- (void)setSectionTitlesInfor:(NSArray *)sectionTitlesInfor
{
if (sectionTitlesInfor.copy == 0) {
return;
}
_sectionTitlesInfor = sectionTitlesInfor;
}
#pragma mark - Layout Views
- (void)layoutSegments
......
//
// MJRefreshTrailer.h
// MJRefresh
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshComponent.h"
NS_ASSUME_NONNULL_BEGIN
@interface MJRefreshTrailer : MJRefreshComponent
/** 创建trailer*/
+ (instancetype)trailerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock;
/** 创建trailer */
+ (instancetype)trailerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
/** 忽略多少scrollView的contentInset的right */
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetRight;
@end
NS_ASSUME_NONNULL_END
//
// MJRefreshTrailer.m
// MJRefresh
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshTrailer.h"
@interface MJRefreshTrailer()
@property (assign, nonatomic) NSInteger lastRefreshCount;
@property (assign, nonatomic) CGFloat lastRightDelta;
@end
@implementation MJRefreshTrailer
#pragma mark - 构造方法
+ (instancetype)trailerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock {
MJRefreshTrailer *cmp = [[self alloc] init];
cmp.refreshingBlock = refreshingBlock;
return cmp;
}
+ (instancetype)trailerWithRefreshingTarget:(id)target refreshingAction:(SEL)action {
MJRefreshTrailer *cmp = [[self alloc] init];
[cmp setRefreshingTarget:target refreshingAction:action];
return cmp;
}
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change {
[super scrollViewContentOffsetDidChange:change];
// 如果正在刷新,直接返回
if (self.state == MJRefreshStateRefreshing) return;
_scrollViewOriginalInset = self.scrollView.mj_inset;
// 当前的contentOffset
CGFloat currentOffsetX = self.scrollView.mj_offsetX;
// 尾部控件刚好出现的offsetX
CGFloat happenOffsetX = [self happenOffsetX];
// 如果是向右滚动到看不见右边控件,直接返回
if (currentOffsetX <= happenOffsetX) return;
CGFloat pullingPercent = (currentOffsetX - happenOffsetX) / self.mj_w;
// 如果已全部加载,仅设置pullingPercent,然后返回
if (self.state == MJRefreshStateNoMoreData) {
self.pullingPercent = pullingPercent;
return;
}
if (self.scrollView.isDragging) {
self.pullingPercent = pullingPercent;
// 普通 和 即将刷新 的临界点
CGFloat normal2pullingOffsetX = happenOffsetX + self.mj_w;
if (self.state == MJRefreshStateIdle && currentOffsetX > normal2pullingOffsetX) {
self.state = MJRefreshStatePulling;
} else if (self.state == MJRefreshStatePulling && currentOffsetX <= normal2pullingOffsetX) {
// 转为普通状态
self.state = MJRefreshStateIdle;
}
} else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
// 开始刷新
[self beginRefreshing];
} else if (pullingPercent < 1) {
self.pullingPercent = pullingPercent;
}
}
- (void)setState:(MJRefreshState)state {
MJRefreshCheckState
// 根据状态来设置属性
if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
// 刷新完毕
if (MJRefreshStateRefreshing == oldState) {
[UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
if (self.endRefreshingAnimationBeginAction) {
self.endRefreshingAnimationBeginAction();
}
self.scrollView.mj_insetR -= self.lastRightDelta;
// 自动调整透明度
if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
} completion:^(BOOL finished) {
self.pullingPercent = 0.0;
if (self.endRefreshingCompletionBlock) {
self.endRefreshingCompletionBlock();
}
}];
}
CGFloat deltaW = [self widthForContentBreakView];
// 刚刷新完毕
if (MJRefreshStateRefreshing == oldState && deltaW > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) {
self.scrollView.mj_offsetX = self.scrollView.mj_offsetX;
}
} else if (state == MJRefreshStateRefreshing) {
// 记录刷新前的数量
self.lastRefreshCount = self.scrollView.mj_totalDataCount;
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
CGFloat right = self.mj_w + self.scrollViewOriginalInset.right;
CGFloat deltaW = [self widthForContentBreakView];
if (deltaW < 0) { // 如果内容宽度小于view的宽度
right -= deltaW;
}
self.lastRightDelta = right - self.scrollView.mj_insetR;
self.scrollView.mj_insetR = right;
// 设置滚动位置
CGPoint offset = self.scrollView.contentOffset;
offset.x = [self happenOffsetX] + self.mj_w;
[self.scrollView setContentOffset:offset animated:NO];
} completion:^(BOOL finished) {
[self executeRefreshingCallback];
}];
}
}
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change {
[super scrollViewContentSizeDidChange:change];
// 内容的宽度
CGFloat contentWidth = self.scrollView.mj_contentW + self.ignoredScrollViewContentInsetRight;
// 表格的宽度
CGFloat scrollWidth = self.scrollView.mj_w - self.scrollViewOriginalInset.left - self.scrollViewOriginalInset.right + self.ignoredScrollViewContentInsetRight;
// 设置位置和尺寸
self.mj_x = MAX(contentWidth, scrollWidth);
}
- (void)placeSubviews {
[super placeSubviews];
self.mj_h = _scrollView.mj_h;
// 设置自己的宽度
self.mj_w = MJRefreshTrailWidth;
}
- (void)willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
if (newSuperview) {
// 设置支持水平弹簧效果
_scrollView.alwaysBounceHorizontal = YES;
_scrollView.alwaysBounceVertical = NO;
}
}
#pragma mark 刚好看到上拉刷新控件时的contentOffset.x
- (CGFloat)happenOffsetX {
CGFloat deltaW = [self widthForContentBreakView];
if (deltaW > 0) {
return deltaW - self.scrollViewOriginalInset.left;
} else {
return - self.scrollViewOriginalInset.left;
}
}
#pragma mark 获得scrollView的内容 超出 view 的宽度
- (CGFloat)widthForContentBreakView {
CGFloat w = self.scrollView.frame.size.width - self.scrollViewOriginalInset.right - self.scrollViewOriginalInset.left;
return self.scrollView.contentSize.width - w;
}
@end
//
// MJRefreshNormalTrailer.h
// MJRefreshExample
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshStateTrailer.h"
NS_ASSUME_NONNULL_BEGIN
@interface MJRefreshNormalTrailer : MJRefreshStateTrailer
@property (weak, nonatomic, readonly) UIImageView *arrowView;
@end
NS_ASSUME_NONNULL_END
//
// MJRefreshNormalTrailer.m
// MJRefreshExample
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshNormalTrailer.h"
#import "NSBundle+MJRefresh.h"
@interface MJRefreshNormalTrailer() {
__unsafe_unretained UIImageView *_arrowView;
}
@end
@implementation MJRefreshNormalTrailer
#pragma mark - 懒加载子控件
- (UIImageView *)arrowView {
if (!_arrowView) {
UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_trailArrowImage]];
[self addSubview:_arrowView = arrowView];
}
return _arrowView;
}
- (void)placeSubviews {
[super placeSubviews];
CGSize arrowSize = self.arrowView.image.size;
// 箭头的中心点
CGPoint selfCenter = CGPointMake(self.mj_w * 0.5, self.mj_h * 0.5);
CGPoint arrowCenter = CGPointMake(arrowSize.width * 0.5 + 5, self.mj_h * 0.5);
BOOL stateHidden = self.stateLabel.isHidden;
if (self.arrowView.constraints.count == 0) {
self.arrowView.mj_size = self.arrowView.image.size;
self.arrowView.center = stateHidden ? selfCenter : arrowCenter ;
}
self.arrowView.tintColor = self.stateLabel.textColor;
if (stateHidden) return;
BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
CGFloat stateLabelW = ceil(self.stateLabel.font.pointSize);
// 状态
if (noConstrainsOnStatusLabel) {
BOOL arrowHidden = self.arrowView.isHidden;
CGFloat stateCenterX = (self.mj_w + arrowSize.width) * 0.5;
self.stateLabel.center = arrowHidden ? selfCenter : CGPointMake(stateCenterX, self.mj_h * 0.5);
self.stateLabel.mj_size = CGSizeMake(stateLabelW, self.mj_h) ;
}
}
- (void)setState:(MJRefreshState)state {
MJRefreshCheckState
// 根据状态做事情
if (state == MJRefreshStateIdle) {
if (oldState == MJRefreshStateRefreshing) {
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);
} completion:^(BOOL finished) {
self.arrowView.transform = CGAffineTransformIdentity;
}];
} else {
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowView.transform = CGAffineTransformIdentity;
}];
}
} else if (state == MJRefreshStatePulling) {
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);
}];
}
}
@end
//
// MJRefreshStateTrailer.h
// MJRefreshExample
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshTrailer.h"
NS_ASSUME_NONNULL_BEGIN
@interface MJRefreshStateTrailer : MJRefreshTrailer
#pragma mark - 状态相关
/** 显示刷新状态的label */
@property (weak, nonatomic, readonly) UILabel *stateLabel;
/** 设置state状态下的文字 */
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
@end
NS_ASSUME_NONNULL_END
//
// MJRefreshStateTrailer.m
// MJRefreshExample
//
// Created by kinarobin on 2020/5/3.
// Copyright © 2020 小码哥. All rights reserved.
//
#import "MJRefreshStateTrailer.h"
@interface MJRefreshStateTrailer() {
/** 显示刷新状态的label */
__unsafe_unretained UILabel *_stateLabel;
}
/** 所有状态对应的文字 */
@property (strong, nonatomic) NSMutableDictionary *stateTitles;
@end
@implementation MJRefreshStateTrailer
#pragma mark - 懒加载
- (NSMutableDictionary *)stateTitles {
if (!_stateTitles) {
self.stateTitles = [NSMutableDictionary dictionary];
}
return _stateTitles;
}
- (UILabel *)stateLabel {
if (!_stateLabel) {
UILabel *stateLabel = [UILabel mj_label];
stateLabel.numberOfLines = 0;
[self addSubview:_stateLabel = stateLabel];
}
return _stateLabel;
}
#pragma mark - 公共方法
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state {
if (title == nil) return;
self.stateTitles[@(state)] = title;
}
#pragma mark - 覆盖父类的方法
- (void)prepare {
[super prepare];
// 初始化文字
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerIdleText] forState:MJRefreshStateIdle];
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerPullingText] forState:MJRefreshStatePulling];
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerPullingText] forState:MJRefreshStateRefreshing];
}
- (void)setState:(MJRefreshState)state {
MJRefreshCheckState
// 设置状态文字
self.stateLabel.text = self.stateTitles[@(state)];
}
- (void)placeSubviews {
[super placeSubviews];
if (self.stateLabel.hidden) return;
BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
CGFloat stateLabelW = ceil(self.stateLabel.font.pointSize);
// 状态
if (noConstrainsOnStatusLabel) {
self.stateLabel.center = CGPointMake(self.mj_w * 0.5, self.mj_h * 0.5);
self.stateLabel.mj_size = CGSizeMake(stateLabelW, self.mj_h) ;
}
}
@end
......@@ -2,6 +2,9 @@
"MJRefreshHeaderPullingText" = "鬆開立即刷新";
"MJRefreshHeaderRefreshingText" = "正在刷新數據中...";
"MJRefreshTrailerIdleText" = "滑動查看圖文詳情";
"MJRefreshTrailerPullingText" = "釋放查看圖文詳情";
"MJRefreshAutoFooterIdleText" = "點擊或上拉加載更多";
"MJRefreshAutoFooterRefreshingText" = "正在加載更多的數據...";
"MJRefreshAutoFooterNoMoreDataText" = "已經全部加載完畢";
......
......@@ -12,3 +12,5 @@
#import "MJRefreshBackGifFooter.h"
#import "MJRefreshAutoNormalFooter.h"
#import "MJRefreshAutoGifFooter.h"
#import "MJRefreshNormalTrailer.h"
......@@ -33,6 +33,7 @@
UIKIT_EXTERN const CGFloat MJRefreshLabelLeftInset;
UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight;
UIKIT_EXTERN const CGFloat MJRefreshFooterHeight;
UIKIT_EXTERN const CGFloat MJRefreshTrailWidth;
UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration;
UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration;
......@@ -47,6 +48,9 @@ UIKIT_EXTERN NSString *const MJRefreshHeaderIdleText;
UIKIT_EXTERN NSString *const MJRefreshHeaderPullingText;
UIKIT_EXTERN NSString *const MJRefreshHeaderRefreshingText;
UIKIT_EXTERN NSString *const MJRefreshTrailerIdleText;
UIKIT_EXTERN NSString *const MJRefreshTrailerPullingText;
UIKIT_EXTERN NSString *const MJRefreshAutoFooterIdleText;
UIKIT_EXTERN NSString *const MJRefreshAutoFooterRefreshingText;
UIKIT_EXTERN NSString *const MJRefreshAutoFooterNoMoreDataText;
......
......@@ -5,6 +5,7 @@
const CGFloat MJRefreshLabelLeftInset = 25;
const CGFloat MJRefreshHeaderHeight = 54.0;
const CGFloat MJRefreshFooterHeight = 44.0;
const CGFloat MJRefreshTrailWidth = 60.0;
const CGFloat MJRefreshFastAnimationDuration = 0.25;
const CGFloat MJRefreshSlowAnimationDuration = 0.4;
......@@ -19,6 +20,9 @@ NSString *const MJRefreshHeaderIdleText = @"MJRefreshHeaderIdleText";
NSString *const MJRefreshHeaderPullingText = @"MJRefreshHeaderPullingText";
NSString *const MJRefreshHeaderRefreshingText = @"MJRefreshHeaderRefreshingText";
NSString *const MJRefreshTrailerIdleText = @"MJRefreshTrailerIdleText";
NSString *const MJRefreshTrailerPullingText = @"MJRefreshTrailerPullingText";
NSString *const MJRefreshAutoFooterIdleText = @"MJRefreshAutoFooterIdleText";
NSString *const MJRefreshAutoFooterRefreshingText = @"MJRefreshAutoFooterRefreshingText";
NSString *const MJRefreshAutoFooterNoMoreDataText = @"MJRefreshAutoFooterNoMoreDataText";
......
......@@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface NSBundle (MJRefresh)
+ (instancetype)mj_refreshBundle;
+ (UIImage *)mj_arrowImage;
+ (UIImage *)mj_trailArrowImage;
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(nullable NSString *)value;
+ (NSString *)mj_localizedStringForKey:(NSString *)key;
@end
......
......@@ -30,6 +30,14 @@
return arrowImage;
}
+ (UIImage *)mj_trailArrowImage {
static UIImage *arrowImage = nil;
if (arrowImage == nil) {
arrowImage = [[UIImage imageWithContentsOfFile:[[self mj_refreshBundle] pathForResource:@"trail_arrow@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
return arrowImage;
}
+ (NSString *)mj_localizedStringForKey:(NSString *)key
{
return [self mj_localizedStringForKey:key value:nil];
......
......@@ -5,12 +5,12 @@
//
// Created by MJ Lee on 15/3/4.
// Copyright (c) 2015年 小码哥. All rights reserved.
// 给ScrollView增加下拉刷新、上拉刷新的功能
// 给ScrollView增加下拉刷新、上拉刷新、 左滑刷新的功能
#import <UIKit/UIKit.h>
#import "MJRefreshConst.h"
@class MJRefreshHeader, MJRefreshFooter;
@class MJRefreshHeader, MJRefreshFooter, MJRefreshTrailer;
NS_ASSUME_NONNULL_BEGIN
......@@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic, nullable) MJRefreshFooter *mj_footer;
@property (strong, nonatomic, nullable) MJRefreshFooter *footer MJRefreshDeprecated("使用mj_footer");
/** 左滑刷新控件 */
@property (strong, nonatomic, nullable) MJRefreshTrailer *mj_trailer;
#pragma mark - other
- (NSInteger)mj_totalDataCount;
......
......@@ -10,6 +10,7 @@
#import "UIScrollView+MJRefresh.h"
#import "MJRefreshHeader.h"
#import "MJRefreshFooter.h"
#import "MJRefreshTrailer.h"
#import <objc/runtime.h>
@implementation UIScrollView (MJRefresh)
......@@ -54,6 +55,24 @@ static const char MJRefreshFooterKey = '\0';
return objc_getAssociatedObject(self, &MJRefreshFooterKey);
}
#pragma mark - footer
static const char MJRefreshTrailerKey = '\0';
- (void)setMj_trailer:(MJRefreshTrailer *)mj_trailer {
if (mj_trailer != self.mj_trailer) {
// 删除旧的,添加新的
[self.mj_trailer removeFromSuperview];
[self insertSubview:mj_trailer atIndex:0];
// 存储新的
objc_setAssociatedObject(self, &MJRefreshTrailerKey,
mj_trailer, OBJC_ASSOCIATION_RETAIN);
}
}
- (MJRefreshTrailer *)mj_trailer {
return objc_getAssociatedObject(self, &MJRefreshTrailerKey);
}
#pragma mark - 过期
- (void)setFooter:(MJRefreshFooter *)footer
{
......
......@@ -15,7 +15,7 @@ PODS:
- AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession
- Alamofire (4.7.0)
- GMBase (1.2.1):
- GMBase (1.2.7):
- GMFoundation
- GMHud
- GMJSONModel
......@@ -32,49 +32,44 @@ PODS:
- GMFlutterSDK (0.1.0):
- GMBase
- GMPhobos
- GMFoundation (1.0.8)
- GMFoundation (1.0.9)
- GMHud (1.0.7):
- lottie-ios (= 2.5.2)
- MBProgressHUD (= 0.9.2)
- GMJSONModel (1.7.4)
- GMKit (1.3.2):
- GMKit/Category (= 1.3.2)
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/FDFullscreenPopGesture (= 1.3.2)
- GMKit/Kit (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMKit (1.4.1):
- GMKit/Category (= 1.4.1)
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Kit (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Category (1.3.2):
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMKit/Category (1.4.1):
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Color (1.3.2):
- GMKit/Color (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Constant (1.3.2):
- GMKit/Constant (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
- GMKit/FDFullscreenPopGesture (1.3.2):
- GMKit/Kit (1.4.1):
- GMKit/Category (= 1.4.1)
- GMKit/Color (= 1.4.1)
- GMKit/Constant (= 1.4.1)
- GMKit/Protocol (= 1.4.1)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Kit (1.3.2):
- GMKit/Category (= 1.3.2)
- GMKit/Color (= 1.3.2)
- GMKit/Constant (= 1.3.2)
- GMKit/Protocol (= 1.3.2)
- GMPhobos
- Masonry
- SDWebImage
- GMKit/Protocol (1.3.2):
- GMKit/Protocol (1.4.1):
- GMPhobos
- Masonry
- SDWebImage
......@@ -96,10 +91,10 @@ PODS:
- Masonry (1.1.0)
- MBProgressHUD (0.9.2)
- MJExtension (3.2.2)
- MJRefresh (3.4.3)
- SDWebImage (5.8.4):
- SDWebImage/Core (= 5.8.4)
- SDWebImage/Core (5.8.4)
- MJRefresh (3.5.0)
- SDWebImage (5.9.1):
- SDWebImage/Core (= 5.9.1)
- SDWebImage/Core (5.9.1)
- TMCache (2.1.0)
- "UITableView+FDTemplateLayoutCell (1.4)"
......@@ -139,13 +134,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
Alamofire: 907e0a98eb68cdb7f9d1f541a563d6ac5dc77b25
GMBase: 8233aa9d51177f1c25d3b5bec479789cc304f6cb
GMBase: 694c79f9a944ef14394c42424df494a9d3acf236
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMFlutterSDK: 7fdedb842c536754d30fedffe87f14da91c1e02e
GMFoundation: e9f7fd9c6e5f133e09009b0ee5de4fce60ac5682
GMFoundation: 15130972d6b389f7ecfc9acfae6f90db23db7fb1
GMHud: feca48b3eda4f3a6f617f4bbaa3657316a245c1f
GMJSONModel: 5e81a98de668e9f93cf6ff77869f77b0d1a806be
GMKit: acc124a9e844ec1ce8300a6b9a8c3e26159f5963
GMKit: 25f9f79b51d9f8e3e1fdf18defcac051b0e95612
GMNetService: 78d729467b99b6ce9814d51efa4dcfa3ddebafe3
GMNetworking: 592b9b71f2a7d92203483276158ce3139ac789d2
GMPhobos: b4e16c162df6618c6f7d10f4649a5f32920961fd
......@@ -155,8 +150,8 @@ SPEC CHECKSUMS:
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1569cf7ace17a8bac47aabfbb8580a49690386d1
MJExtension: d9b9c74cbdeb724c1e9ecbb157b318276e62e876
MJRefresh: 53e3e3219f204425ee6d3e62e8733d3295944cd6
SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9
MJRefresh: 6afc955813966afb08305477dd7a0d9ad5e79a16
SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
TMCache: 95ebcc9b3c7e90fb5fd8fc3036cba3aa781c9bed
"UITableView+FDTemplateLayoutCell": 234e1582bcc4e18461af91155123bb96538ed030
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Copyright (c) 2009-2018 Olivier Poitrey rs@dailymotion.com
Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -38,7 +38,7 @@ This library provides an async image downloader with cache support. For convenie
## Supported Image Formats
- Image formats supported by Apple system (JPEG, PNG, TIFF, HEIC, ...), including GIF/APNG/HEIC animation
- WebP format, including animated WebP (use the [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) project)
- WebP format, including animated WebP (use the [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) project). Note iOS 14/macOS 11.0 supports built-in WebP decoding (no encoding).
- Support extendable coder plugins for new image formats like BPG, AVIF. And vector format like PDF, SVG. See all the list in [Image coder plugin List](https://github.com/SDWebImage/SDWebImage/wiki/Coder-Plugin-List)
## Additional modules and Ecosystem
......@@ -54,7 +54,7 @@ We support SwiftUI by building a brand new framework called [SDWebImageSwiftUI](
The new framework introduce two View structs `WebImage` and `AnimatedImage` for SwiftUI world, `ImageIndicator` modifier for any View, `ImageManager` observable object for data source. Supports iOS 13+/macOS 10.15+/tvOS 13+/watchOS 6+ and Swift 5.1. Have a nice try and provide feedback!
#### Coders for additional image formats
- [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) - coder for WebP format. Based on [libwebp](https://chromium.googlesource.com/webm/libwebp)
- [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) - coder for WebP format. iOS 8+/macOS 10.10+. Based on [libwebp](https://chromium.googlesource.com/webm/libwebp)
- [SDWebImageHEIFCoder](https://github.com/SDWebImage/SDWebImageHEIFCoder) - coder for HEIF format, iOS 8+/macOS 10.10+ support. Based on [libheif](https://github.com/strukturag/libheif)
- [SDWebImageBPGCoder](https://github.com/SDWebImage/SDWebImageBPGCoder) - coder for BPG format. Based on [libbpg](https://github.com/mirrorer/libbpg)
- [SDWebImageFLIFCoder](https://github.com/SDWebImage/SDWebImageFLIFCoder) - coder for FLIF format. Based on [libflif](https://github.com/FLIF-hub/FLIF)
......
......@@ -13,10 +13,8 @@
#else
#import <MobileCoreServices/MobileCoreServices.h>
#endif
#import "SDImageHEICCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
#define kSVGTagEnd @"</svg>"
@implementation NSData (ImageContentType)
......@@ -76,15 +74,12 @@
}
}
case 0x3C: {
if (data.length > 100) {
// Check end with SVG tag
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 100, 100)] encoding:NSASCIIStringEncoding];
if ([testString containsString:kSVGTagEnd]) {
if ([data rangeOfData:[kSVGTagEnd dataUsingEncoding:NSUTF8StringEncoding] options:NSDataSearchBackwards range: NSMakeRange(data.length - MIN(100, data.length), MIN(100, data.length))].location != NSNotFound) {
return SDImageFormatSVG;
}
}
}
}
return SDImageFormatUndefined;
}
......
......@@ -25,9 +25,7 @@ static CGFloat SDImageScaleFromPath(NSString *string) {
NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil];
[pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
if (result.range.location >= 3) {
scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue;
}
}];
return scale;
......
......@@ -14,7 +14,7 @@
#import "SDImageGIFCoder.h"
#import "SDImageAPNGCoder.h"
#import "SDImageHEICCoder.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageAWebPCoder.h"
@implementation SDAnimatedImageRep {
CGImageSourceRef _imageSource;
......@@ -34,6 +34,8 @@
}
// We should override init method for `NSBitmapImageRep` to do initialize about animated image format
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
- (instancetype)initWithData:(NSData *)data {
self = [super initWithData:data];
if (self) {
......@@ -70,6 +72,13 @@
[self setProperty:NSImageCurrentFrame withValue:@(0)];
NSUInteger loopCount = [SDImageHEICCoder imageLoopCountWithSource:imageSource];
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
} else if (CFStringCompare(type, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
// WebP
// Do initialize about frame count, current frame/duration and loop count
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
[self setProperty:NSImageCurrentFrame withValue:@(0)];
NSUInteger loopCount = [SDImageAWebPCoder imageLoopCountWithSource:imageSource];
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
}
}
return self;
......@@ -100,6 +109,9 @@
} else if (CFStringCompare(type, kSDUTTypeHEICS, 0) == kCFCompareEqualTo) {
// HEIC
frameDuration = [SDImageHEICCoder frameDurationAtIndex:index source:imageSource];
} else if (CFStringCompare(type, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
// WebP
frameDuration = [SDImageAWebPCoder frameDurationAtIndex:index source:imageSource];
}
if (!frameDuration) {
return;
......@@ -108,6 +120,7 @@
[super setProperty:NSImageCurrentFrameDuration withValue:@(frameDuration)];
}
}
#pragma clang diagnostic pop
@end
......
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDImageIOAnimatedCoder.h"
/**
This coder is used for Google WebP and Animated WebP(AWebP) image format.
Image/IO provide the WebP decoding support in iOS 14/macOS 11/tvOS 14/watchOS 7+.
@note Currently Image/IO seems does not supports WebP encoding, if you need WebP encoding, use the custom codec below.
@note If you need to support lower firmware version for WebP, you can have a try at https://github.com/SDWebImage/SDWebImageWebPCoder
*/
API_AVAILABLE(ios(14.0), tvos(14.0), macos(11.0), watchos(7.0))
@interface SDImageAWebPCoder : SDImageIOAnimatedCoder <SDProgressiveImageCoder, SDAnimatedImageCoder>
@property (nonatomic, class, readonly, nonnull) SDImageAWebPCoder *sharedCoder;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDImageAWebPCoder.h"
#import "SDImageIOAnimatedCoderInternal.h"
// These constants are available from iOS 14+ and Xcode 12. This raw value is used for toolchain and firmware compatibility
static NSString * kSDCGImagePropertyWebPDictionary = @"{WebP}";
static NSString * kSDCGImagePropertyWebPLoopCount = @"LoopCount";
static NSString * kSDCGImagePropertyWebPDelayTime = @"DelayTime";
static NSString * kSDCGImagePropertyWebPUnclampedDelayTime = @"UnclampedDelayTime";
@implementation SDImageAWebPCoder
+ (void)initialize {
#if __IPHONE_14_0 || __TVOS_14_0 || __MAC_11_0 || __WATCHOS_7_0
// Xcode 12
if (@available(iOS 14, tvOS 14, macOS 11, watchOS 7, *)) {
// Use SDK instead of raw value
kSDCGImagePropertyWebPDictionary = (__bridge NSString *)kCGImagePropertyWebPDictionary;
kSDCGImagePropertyWebPLoopCount = (__bridge NSString *)kCGImagePropertyWebPLoopCount;
kSDCGImagePropertyWebPDelayTime = (__bridge NSString *)kCGImagePropertyWebPDelayTime;
kSDCGImagePropertyWebPUnclampedDelayTime = (__bridge NSString *)kCGImagePropertyWebPUnclampedDelayTime;
}
#endif
}
+ (instancetype)sharedCoder {
static SDImageAWebPCoder *coder;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coder = [[SDImageAWebPCoder alloc] init];
});
return coder;
}
#pragma mark - SDImageCoder
- (BOOL)canDecodeFromData:(nullable NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Check WebP decoding compatibility
return [self.class canDecodeFromFormat:SDImageFormatWebP];
default:
return NO;
}
}
- (BOOL)canIncrementalDecodeFromData:(NSData *)data {
return [self canDecodeFromData:data];
}
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
switch (format) {
case SDImageFormatWebP:
// Check WebP encoding compatibility
return [self.class canEncodeToFormat:SDImageFormatWebP];
default:
return NO;
}
}
#pragma mark - Subclass Override
+ (SDImageFormat)imageFormat {
return SDImageFormatWebP;
}
+ (NSString *)imageUTType {
return (__bridge NSString *)kSDUTTypeWebP;
}
+ (NSString *)dictionaryProperty {
return kSDCGImagePropertyWebPDictionary;
}
+ (NSString *)unclampedDelayTimeProperty {
return kSDCGImagePropertyWebPUnclampedDelayTime;
}
+ (NSString *)delayTimeProperty {
return kSDCGImagePropertyWebPDelayTime;
}
+ (NSString *)loopCountProperty {
return kSDCGImagePropertyWebPLoopCount;
}
+ (NSUInteger)defaultLoopCount {
return 0;
}
@end
......@@ -103,8 +103,18 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
*/
@property (nonatomic, class, readonly, nonnull) SDImageCache *sharedImageCache;
/**
* Control the default disk cache directory. This will effect all the SDImageCache instance created after modification, even for shared image cache.
* This can be used to share the same disk cache with the App and App Extension (Today/Notification Widget) using `- [NSFileManager.containerURLForSecurityApplicationGroupIdentifier:]`.
* @note If you pass nil, the value will be reset to `~/Library/Caches/com.hackemist.SDImageCache`.
* @note We still preserve the `namespace` arg, which means, if you change this property into `/path/to/use`, the `SDImageCache.sharedImageCache.diskCachePath` should be `/path/to/use/default` because shared image cache use `default` as namespace.
* Defaults to nil.
*/
@property (nonatomic, class, readwrite, null_resettable) NSString *defaultDiskCacheDirectory;
/**
* Init a new cache store with a specific namespace
* The final disk cache directory should looks like ($directory/$namespace). And the default config of shared cache, should result in (~/Library/Caches/com.hackemist.SDImageCache/default/)
*
* @param ns The namespace to use for this cache store
*/
......@@ -112,7 +122,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
/**
* Init a new cache store with a specific namespace and directory.
* If you don't provide the disk cache directory, we will use the User Cache directory with prefix (~/Library/Caches/com.hackemist.SDImageCache/).
* The final disk cache directory should looks like ($directory/$namespace). And the default config of shared cache, should result in (~/Library/Caches/com.hackemist.SDImageCache/default/)
*
* @param ns The namespace to use for this cache store
* @param directory Directory to cache disk images in
......@@ -121,7 +131,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
diskCacheDirectory:(nullable NSString *)directory;
/**
* Init a new cache store with a specific namespace, directory and file manager
* Init a new cache store with a specific namespace, directory and config.
* The final disk cache directory should looks like ($directory/$namespace). And the default config of shared cache, should result in (~/Library/Caches/com.hackemist.SDImageCache/default/)
*
* @param ns The namespace to use for this cache store
......
......@@ -15,6 +15,8 @@
#import "UIImage+Metadata.h"
#import "UIImage+ExtendedCacheData.h"
static NSString * _defaultDiskCacheDirectory;
@interface SDImageCache ()
#pragma mark - Properties
......@@ -40,6 +42,17 @@
return instance;
}
+ (NSString *)defaultDiskCacheDirectory {
if (!_defaultDiskCacheDirectory) {
_defaultDiskCacheDirectory = [[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"];
}
return _defaultDiskCacheDirectory;
}
+ (void)setDefaultDiskCacheDirectory:(NSString *)defaultDiskCacheDirectory {
_defaultDiskCacheDirectory = [defaultDiskCacheDirectory copy];
}
- (instancetype)init {
return [self initWithNamespace:@"default"];
}
......@@ -72,12 +85,11 @@
_memoryCache = [[config.memoryCacheClass alloc] initWithConfig:_config];
// Init the disk cache
if (directory != nil) {
_diskCachePath = [directory stringByAppendingPathComponent:ns];
} else {
NSString *path = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:ns];
_diskCachePath = path;
if (!directory) {
// Use default disk cache directory
directory = [self.class defaultDiskCacheDirectory];
}
_diskCachePath = [directory stringByAppendingPathComponent:ns];
NSAssert([config.diskCacheClass conformsToProtocol:@protocol(SDDiskCache)], @"Custom disk cache class must conform to `SDDiskCache` protocol");
_diskCache = [[config.diskCacheClass alloc] initWithCachePath:_diskCachePath config:_config];
......@@ -121,7 +133,7 @@
return [self.diskCache cachePathForKey:key];
}
- (nullable NSString *)userCacheDirectory {
+ (nullable NSString *)userCacheDirectory {
NSArray<NSString *> *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
return paths.firstObject;
}
......@@ -131,9 +143,9 @@
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// ~/Library/Caches/com.hackemist.SDImageCache/default/
NSString *newDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:@"default"];
NSString *newDefaultPath = [[[self.class userCacheDirectory] stringByAppendingPathComponent:@"com.hackemist.SDImageCache"] stringByAppendingPathComponent:@"default"];
// ~/Library/Caches/default/com.hackemist.SDWebImageCache.default/
NSString *oldDefaultPath = [[[self userCacheDirectory] stringByAppendingPathComponent:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"];
NSString *oldDefaultPath = [[[self.class userCacheDirectory] stringByAppendingPathComponent:@"default"] stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"];
dispatch_async(self.ioQueue, ^{
[((SDDiskCache *)self.diskCache) moveCacheDirectoryFromPath:oldDefaultPath toPath:newDefaultPath];
});
......@@ -269,7 +281,7 @@
});
}
// Make sure to call form io queue by caller
// Make sure to call from io queue by caller
- (void)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key {
if (!imageData || !key) {
return;
......@@ -304,7 +316,7 @@
return exists;
}
// Make sure to call form io queue by caller
// Make sure to call from io queue by caller
- (BOOL)_diskImageDataExistsWithKey:(nullable NSString *)key {
if (!key) {
return NO;
......@@ -516,13 +528,10 @@
@autoreleasepool {
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
UIImage *diskImage;
SDImageCacheType cacheType = SDImageCacheTypeNone;
if (image) {
// the image is from in-memory cache, but need image data
diskImage = image;
cacheType = SDImageCacheTypeMemory;
} else if (diskData) {
cacheType = SDImageCacheTypeDisk;
// decode image data only if in-memory cache missed
diskImage = [self diskImageForKey:key data:diskData options:options context:context];
if (diskImage && self.config.shouldCacheImagesInMemory) {
......@@ -533,10 +542,10 @@
if (doneBlock) {
if (shouldQueryDiskSync) {
doneBlock(diskImage, diskData, cacheType);
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, diskData, cacheType);
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
});
}
}
......
......@@ -91,7 +91,8 @@
+ (UIImage * _Nullable)decodedImageWithImage:(UIImage * _Nullable)image;
/**
Return the decoded and probably scaled down image by the provided image. If the image is large than the limit size, will try to scale down. Or just works as `decodedImageWithImage:`
Return the decoded and probably scaled down image by the provided image. If the image pixels bytes size large than the limit bytes, will try to scale down. Or just works as `decodedImageWithImage:`, never scale up.
@warning You should not pass too small bytes, the suggestion value should be larger than 1MB. Even we use Tile Decoding to avoid OOM, however, small bytes will consume much more CPU time because we need to iterate more times to draw each tile.
@param image The image to be decoded and scaled down
@param bytes The limit bytes size. Provide 0 to use the build-in limit.
......@@ -101,7 +102,7 @@
/**
Control the default limit bytes to scale down largest images.
This value must be larger than or equal to 1MB. Defaults to 60MB on iOS/tvOS, 90MB on macOS, 30MB on watchOS.
This value must be larger than 4 Bytes (at least 1x1 pixel). Defaults to 60MB on iOS/tvOS, 90MB on macOS, 30MB on watchOS.
*/
@property (class, readwrite) NSUInteger defaultScaleDownLimitBytes;
......
......@@ -25,7 +25,6 @@ static const size_t kBytesPerPixel = 4;
static const size_t kBitsPerComponent = 8;
static const CGFloat kBytesPerMB = 1024.0f * 1024.0f;
static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel;
/*
* Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set
* Suggested value for iPad1 and iPhone 3GS: 60.
......@@ -379,8 +378,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
// see kDestImageSizeMB, and how it relates to destTotalPixels.
CGFloat imageScale = sqrt(destTotalPixels / sourceTotalPixels);
CGSize destResolution = CGSizeZero;
destResolution.width = (int)(sourceResolution.width * imageScale);
destResolution.height = (int)(sourceResolution.height * imageScale);
destResolution.width = MAX(1, (int)(sourceResolution.width * imageScale));
destResolution.height = MAX(1, (int)(sourceResolution.height * imageScale));
// device color space
CGColorSpaceRef colorspaceRef = [self colorSpaceGetDeviceRGB];
......@@ -419,7 +418,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
// The source tile height is dynamic. Since we specified the size
// of the source tile in MB, see how many rows of pixels high it
// can be given the input image width.
sourceTile.size.height = (int)(tileTotalPixels / sourceTile.size.width );
sourceTile.size.height = MAX(1, (int)(tileTotalPixels / sourceTile.size.width));
sourceTile.origin.x = 0.0f;
// The output tile is the same proportions as the input tile, but
// scaled to image scale.
......@@ -485,7 +484,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
}
+ (void)setDefaultScaleDownLimitBytes:(NSUInteger)defaultScaleDownLimitBytes {
if (defaultScaleDownLimitBytes < kBytesPerMB) {
if (defaultScaleDownLimitBytes < kBytesPerPixel) {
return;
}
kDestImageLimitBytes = defaultScaleDownLimitBytes;
......@@ -596,13 +595,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
}
CGFloat destTotalPixels;
if (bytes == 0) {
bytes = kDestImageLimitBytes;
bytes = [self defaultScaleDownLimitBytes];
}
bytes = MAX(bytes, kBytesPerPixel);
destTotalPixels = bytes / kBytesPerPixel;
if (destTotalPixels <= kPixelsPerMB) {
// Too small to scale down
return NO;
}
float imageScale = destTotalPixels / sourceTotalPixels;
if (imageScale < 1) {
shouldScaleDown = YES;
......
......@@ -17,6 +17,7 @@
@note This coder is not in the default coder list for now, since HEIC animated image is really rare, and Apple's implementation still contains performance issues. You can enable if you need this.
@note If you need to support lower firmware version for HEIF, you can have a try at https://github.com/SDWebImage/SDWebImageHEIFCoder
*/
API_AVAILABLE(ios(13.0), tvos(13.0), macos(10.15), watchos(6.0))
@interface SDImageHEICCoder : SDImageIOAnimatedCoder <SDProgressiveImageCoder, SDAnimatedImageCoder>
@property (nonatomic, class, readonly, nonnull) SDImageHEICCoder *sharedCoder;
......
......@@ -7,7 +7,7 @@
*/
#import "SDImageHEICCoder.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// These constants are available from iOS 13+ and Xcode 11. This raw value is used for toolchain and firmware compatibility
static NSString * kSDCGImagePropertyHEICSDictionary = @"{HEICS}";
......@@ -45,10 +45,10 @@ static NSString * kSDCGImagePropertyHEICSUnclampedDelayTime = @"UnclampedDelayTi
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatHEIC:
// Check HEIC decoding compatibility
return [self.class canDecodeFromHEICFormat];
return [self.class canDecodeFromFormat:SDImageFormatHEIC];
case SDImageFormatHEIF:
// Check HEIF decoding compatibility
return [self.class canDecodeFromHEIFFormat];
return [self.class canDecodeFromFormat:SDImageFormatHEIF];
default:
return NO;
}
......@@ -62,78 +62,15 @@ static NSString * kSDCGImagePropertyHEICSUnclampedDelayTime = @"UnclampedDelayTi
switch (format) {
case SDImageFormatHEIC:
// Check HEIC encoding compatibility
return [self.class canEncodeToHEICFormat];
return [self.class canEncodeToFormat:SDImageFormatHEIC];
case SDImageFormatHEIF:
// Check HEIF encoding compatibility
return [self.class canEncodeToHEIFFormat];
return [self.class canEncodeToFormat:SDImageFormatHEIF];
default:
return NO;
}
}
#pragma mark - HEIF Format
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format {
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers();
if ([imageUTTypes containsObject:(__bridge NSString *)(imageUTType)]) {
return YES;
}
return NO;
}
+ (BOOL)canDecodeFromHEICFormat {
static BOOL canDecode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canDecode = [self canDecodeFromFormat:SDImageFormatHEIC];
});
return canDecode;
}
+ (BOOL)canDecodeFromHEIFFormat {
static BOOL canDecode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canDecode = [self canDecodeFromFormat:SDImageFormatHEIF];
});
return canDecode;
}
+ (BOOL)canEncodeToFormat:(SDImageFormat)format {
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
// Create an image destination.
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
if (!imageDestination) {
// Can't encode to HEIC
return NO;
} else {
// Can encode to HEIC
CFRelease(imageDestination);
return YES;
}
}
+ (BOOL)canEncodeToHEICFormat {
static BOOL canEncode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canEncode = [self canEncodeToFormat:SDImageFormatHEIC];
});
return canEncode;
}
+ (BOOL)canEncodeToHEIFFormat {
static BOOL canEncode = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canEncode = [self canEncodeToFormat:SDImageFormatHEIF];
});
return canEncode;
}
#pragma mark - Subclass Override
+ (SDImageFormat)imageFormat {
......
......@@ -108,6 +108,36 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Utils
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format {
static dispatch_once_t onceToken;
static NSSet *imageUTTypeSet;
dispatch_once(&onceToken, ^{
NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers();
imageUTTypeSet = [NSSet setWithArray:imageUTTypes];
});
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
if ([imageUTTypeSet containsObject:(__bridge NSString *)(imageUTType)]) {
// Can decode from target format
return YES;
}
return NO;
}
+ (BOOL)canEncodeToFormat:(SDImageFormat)format {
static dispatch_once_t onceToken;
static NSSet *imageUTTypeSet;
dispatch_once(&onceToken, ^{
NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageDestinationCopyTypeIdentifiers();
imageUTTypeSet = [NSSet setWithArray:imageUTTypes];
});
CFStringRef imageUTType = [NSData sd_UTTypeFromImageFormat:format];
if ([imageUTTypeSet containsObject:(__bridge NSString *)(imageUTType)]) {
// Can encode to target format
return YES;
}
return NO;
}
+ (NSUInteger)imageLoopCountWithSource:(CGImageSourceRef)source {
NSUInteger loopCount = self.defaultLoopCount;
NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, NULL);
......@@ -182,7 +212,8 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
decodingOptions = [NSMutableDictionary dictionary];
}
CGImageRef imageRef;
if (thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height)) {
BOOL createFullImage = thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height);
if (createFullImage) {
if (isVector) {
if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
// Provide the default pixel count for vector images, simply just use the screen size
......@@ -221,8 +252,8 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
if (!imageRef) {
return nil;
}
if (thumbnailSize.width > 0 && thumbnailSize.height > 0) {
// Thumbnail image post-process
if (!createFullImage) {
if (preserveAspectRatio) {
// kCGImageSourceCreateThumbnailWithTransform will apply EXIF transform as well, we should not apply twice
exifOrientation = kCGImagePropertyOrientationUp;
......
......@@ -11,7 +11,6 @@
#import "NSImage+Compatibility.h"
#import <ImageIO/ImageIO.h>
#import "UIImage+Metadata.h"
#import "SDImageHEICCoderInternal.h"
#import "SDImageIOAnimatedCoderInternal.h"
// Specify File Size for lossy format encoding, like JPEG
......@@ -55,19 +54,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Decode
- (BOOL)canDecodeFromData:(nullable NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Do not support WebP decoding
return NO;
case SDImageFormatHEIC:
// Check HEIC decoding compatibility
return [SDImageHEICCoder canDecodeFromHEICFormat];
case SDImageFormatHEIF:
// Check HEIF decoding compatibility
return [SDImageHEICCoder canDecodeFromHEIFFormat];
default:
return YES;
}
}
- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderOptions *)options {
......@@ -205,19 +192,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#pragma mark - Encode
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
switch (format) {
case SDImageFormatWebP:
// Do not support WebP encoding
return NO;
case SDImageFormatHEIC:
// Check HEIC encoding compatibility
return [SDImageHEICCoder canEncodeToHEICFormat];
case SDImageFormatHEIF:
// Check HEIF encoding compatibility
return [SDImageHEICCoder canEncodeToHEIFFormat];
default:
return YES;
}
}
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(nullable SDImageCoderOptions *)options {
......
......@@ -160,7 +160,8 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
SDWebImageFromLoaderOnly = 1 << 16,
/**
* By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well.
* By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image when the callback from manager is asynchronous (from network, or disk cache query)
* This mask can force to apply view transition for any cases, like memory cache query, or sync disk cache query.
*/
SDWebImageForceTransition = 1 << 17,
......@@ -200,7 +201,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* We usually don't apply transform on vector images, because vector images supports dynamically changing to any size, rasterize to a fixed size will loss details. To modify vector images, you can process the vector data at runtime (such as modifying PDF tag / SVG element).
* Use this flag to transform them anyway.
*/
SDWebImageTransformVectorImage = 1 << 23,
SDWebImageTransformVectorImage = 1 << 23
};
......
......@@ -174,7 +174,29 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
#if SD_UIKIT || SD_MAC
// check whether we should use the image transition
SDWebImageTransition *transition = nil;
if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) {
BOOL shouldUseTransition = NO;
if (options & SDWebImageForceTransition) {
// Always
shouldUseTransition = YES;
} else if (cacheType == SDImageCacheTypeNone) {
// From network
shouldUseTransition = YES;
} else {
// From disk (and, user don't use sync query)
if (cacheType == SDImageCacheTypeMemory) {
shouldUseTransition = NO;
} else if (cacheType == SDImageCacheTypeDisk) {
if (options & SDWebImageQueryMemoryDataSync || options & SDWebImageQueryDiskDataSync) {
shouldUseTransition = NO;
} else {
shouldUseTransition = YES;
}
} else {
// Not valid cache type, fallback
shouldUseTransition = NO;
}
}
if (finished && shouldUseTransition) {
transition = self.sd_imageTransition;
}
#endif
......
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDImageHEICCoder.h"
// AVFileTypeHEIC/AVFileTypeHEIF is defined in AVFoundation via iOS 11, we use this without import AVFoundation
#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic")
#define kSDUTTypeHEIF ((__bridge CFStringRef)@"public.heif")
// HEIC Sequence (Animated Image)
#define kSDUTTypeHEICS ((__bridge CFStringRef)@"public.heics")
@interface SDImageHEICCoder ()
+ (BOOL)canDecodeFromHEICFormat;
+ (BOOL)canDecodeFromHEIFFormat;
+ (BOOL)canEncodeToHEICFormat;
+ (BOOL)canEncodeToHEIFFormat;
@end
......@@ -9,10 +9,20 @@
#import <Foundation/Foundation.h>
#import "SDImageIOAnimatedCoder.h"
// AVFileTypeHEIC/AVFileTypeHEIF is defined in AVFoundation via iOS 11, we use this without import AVFoundation
#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic")
#define kSDUTTypeHEIF ((__bridge CFStringRef)@"public.heif")
// HEIC Sequence (Animated Image)
#define kSDUTTypeHEICS ((__bridge CFStringRef)@"public.heics")
// kUTTypeWebP seems not defined in public UTI framework, Apple use the hardcode string, we define them :)
#define kSDUTTypeWebP ((__bridge CFStringRef)@"org.webmproject.webp")
@interface SDImageIOAnimatedCoder ()
+ (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source;
+ (NSUInteger)imageLoopCountWithSource:(nonnull CGImageSourceRef)source;
+ (nullable UIImage *)createFrameAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source scale:(CGFloat)scale preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize options:(nullable NSDictionary *)options;
+ (BOOL)canEncodeToFormat:(SDImageFormat)format;
+ (BOOL)canDecodeFromFormat:(SDImageFormat)format;
@end
......@@ -70,6 +70,7 @@ FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[];
#import <SDWebImage/SDWebImageOptionsProcessor.h>
#import <SDWebImage/SDImageIOAnimatedCoder.h>
#import <SDWebImage/SDImageHEICCoder.h>
#import <SDWebImage/SDImageAWebPCoder.h>
// Mac
#if __has_include(<SDWebImage/NSImage+Compatibility.h>)
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -34,6 +34,7 @@
#import "UIViewController+UrlScheme.h"
#import "WMBaseViewController+FadeNavigation.h"
#import "WMBaseViewController+OCNavigationBar.h"
#import "UINavigationController+FDFullscreenPopGesture.h"
#import "GMBaseUtil.h"
#import "GMCustomNavigationAnimationProtocol.h"
#import "GMNavigationController.h"
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.8</string>
<string>1.0.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.3.2</string>
<string>1.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -29,7 +29,6 @@
#import "UIColor+GMTheme.h"
#import "Constant.h"
#import "SystemVersion.h"
#import "UINavigationController+FDFullscreenPopGesture.h"
#import "GMAnnotation.h"
#import "GMButton.h"
#import "GMCollectionView.h"
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.4.3</string>
<string>3.5.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -15,6 +15,7 @@
#import "MJRefreshComponent.h"
#import "MJRefreshFooter.h"
#import "MJRefreshHeader.h"
#import "MJRefreshTrailer.h"
#import "MJRefreshAutoGifFooter.h"
#import "MJRefreshAutoNormalFooter.h"
#import "MJRefreshAutoStateFooter.h"
......@@ -24,6 +25,8 @@
#import "MJRefreshGifHeader.h"
#import "MJRefreshNormalHeader.h"
#import "MJRefreshStateHeader.h"
#import "MJRefreshNormalTrailer.h"
#import "MJRefreshStateTrailer.h"
#import "MJRefresh.h"
#import "MJRefreshConfig.h"
#import "MJRefreshConst.h"
......
......@@ -405,7 +405,7 @@ THE SOFTWARE.
## SDWebImage
Copyright (c) 2009-2018 Olivier Poitrey rs@dailymotion.com
Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -524,7 +524,7 @@ THE SOFTWARE.</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2009-2018 Olivier Poitrey rs@dailymotion.com
<string>Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -201,7 +201,6 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
install_framework "${BUILT_PRODUCTS_DIR}/GMBase/GMBase.framework"
install_framework "${BUILT_PRODUCTS_DIR}/GMCache/GMCache.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/App.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/Flutter.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/fluttertoast.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/flutter_boost.framework"
......@@ -234,7 +233,6 @@ if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
install_framework "${BUILT_PRODUCTS_DIR}/GMBase/GMBase.framework"
install_framework "${BUILT_PRODUCTS_DIR}/GMCache/GMCache.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/App.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/Flutter.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/fluttertoast.framework"
install_framework "${PODS_ROOT}/../../GMFlutterSDK/Frameworks/flutter_boost.framework"
......
......@@ -3,7 +3,7 @@ FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetwork
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase/GMBase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache/GMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK/GMFlutterSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation/GMFoundation.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud/GMHud.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel/GMJSONModel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit/GMKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService/GMNetService.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking/GMNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos/GMPhobos.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh/GMRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord/MagicalRecord.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache/TMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell/UITableView_FDTemplateLayoutCell.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -ObjC -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "App" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_LDFLAGS = $(inherited) -ObjC -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
......@@ -3,7 +3,7 @@ FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetwork
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase/GMBase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache/GMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK/GMFlutterSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation/GMFoundation.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud/GMHud.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel/GMJSONModel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit/GMKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService/GMNetService.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking/GMNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos/GMPhobos.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh/GMRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord/MagicalRecord.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache/TMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell/UITableView_FDTemplateLayoutCell.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -ObjC -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "App" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_LDFLAGS = $(inherited) -ObjC -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/../../GMFlutterSDK/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase/GMBase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache/GMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK/GMFlutterSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation/GMFoundation.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud/GMHud.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel/GMJSONModel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit/GMKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService/GMNetService.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking/GMNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos/GMPhobos.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh/GMRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord/MagicalRecord.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache/TMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell/UITableView_FDTemplateLayoutCell.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
OTHER_LDFLAGS = $(inherited) -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "App" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_LDFLAGS = $(inherited) -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/../../GMFlutterSDK/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMBase/GMBase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMCache/GMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFlutterSDK/GMFlutterSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMFoundation/GMFoundation.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMHud/GMHud.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMJSONModel/GMJSONModel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMKit/GMKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetService/GMNetService.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMNetworking/GMNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMPhobos/GMPhobos.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GMRefresh/GMRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MagicalRecord/MagicalRecord.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TMCache/TMCache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/UITableView+FDTemplateLayoutCell/UITableView_FDTemplateLayoutCell.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
OTHER_LDFLAGS = $(inherited) -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "App" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
OTHER_LDFLAGS = $(inherited) -l"z" -framework "AFNetworking" -framework "Alamofire" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "FMDB" -framework "Flutter" -framework "Foundation" -framework "GMBase" -framework "GMCache" -framework "GMFlutterSDK" -framework "GMFoundation" -framework "GMHud" -framework "GMJSONModel" -framework "GMKit" -framework "GMNetService" -framework "GMNetworking" -framework "GMPhobos" -framework "GMRefresh" -framework "ImageIO" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MagicalRecord" -framework "MapKit" -framework "Masonry" -framework "SDWebImage" -framework "TMCache" -framework "UIKit" -framework "UITableView_FDTemplateLayoutCell" -framework "flutter_boost" -framework "fluttertoast" -framework "path_provider" -framework "shared_preferences" -framework "sqflite" -framework "url_launcher" -weak_framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>5.8.4</string>
<string>5.9.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -21,6 +21,7 @@
#import "SDDiskCache.h"
#import "SDGraphicsImageRenderer.h"
#import "SDImageAPNGCoder.h"
#import "SDImageAWebPCoder.h"
#import "SDImageCache.h"
#import "SDImageCacheConfig.h"
#import "SDImageCacheDefine.h"
......
......@@ -37,7 +37,7 @@
- (void)viewDidLoad {
[super viewDidLoad];
// self.fd_interactivePopDisabled = YES;
self.fd_interactivePopDisabled = YES;
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment