更新 MedalsModel.h 和 MedalsModel.m,新增 expireDateString 方法以格式化过期时间;在 MedalsCollectionViewCell.m 和 MedalsCyclePagerCell.m 中优化 MP4 和图片的显示逻辑,增强降级处理;在 MedalsDetailView.m 中更新勋章显示逻辑,使用新的 URL 优先级;在 MedalsLevelIndicatorView.h 和 MedalsLevelIndicatorView.m 中新增重置等级指示器的方法;在 MedalsWearingControlCollectionViewCell.m 和 MedalsWearingListCollectionViewCell.m 中实现新的显示逻辑,支持 MP4 和图片的降级处理;在 NSString+Utils.h 和 NSString+Utils.m 中新增图片格式验证方法,提升代码健壮性和可读性。
This commit is contained in:
@@ -22,12 +22,17 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, copy) NSString *picUrl;
|
||||
@property (nonatomic, assign) BOOL useStatus;
|
||||
|
||||
/// 将 expireSeconds 转换为 "yyyy/MM/dd" 格式的字符串
|
||||
- (NSString *)expireDateString;
|
||||
|
||||
@end
|
||||
|
||||
@interface MedalSeriesItemVo : PIBaseModel
|
||||
|
||||
@property (nonatomic, assign) NSInteger medalLevel;
|
||||
@property (nonatomic, copy) NSString *seriesName;
|
||||
@property (nonatomic, copy) NSString *mp4Url;
|
||||
@property (nonatomic, copy) NSString *picUrl;
|
||||
@property (nonatomic, copy) NSArray <MedalVo *> *medalVos;
|
||||
|
||||
@end
|
||||
|
@@ -9,6 +9,23 @@
|
||||
|
||||
@implementation MedalVo
|
||||
|
||||
/// 将 expireSeconds 转换为 "yyyy/MM/dd" 格式的字符串
|
||||
- (NSString *)expireDateString {
|
||||
if (self.expireSeconds <= 0) {
|
||||
return YMLocalizedString(@"20.20.61_text_9");
|
||||
}
|
||||
|
||||
// 将秒转换为 NSDate
|
||||
NSDate *expireDate = [NSDate dateWithTimeIntervalSince1970:self.expireSeconds];
|
||||
|
||||
// 创建日期格式化器
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.dateFormat = @"yyyy/MM/dd";
|
||||
|
||||
// 返回格式化后的字符串
|
||||
return [NSString stringWithFormat:YMLocalizedString(@"20.20.61_text_8"), [formatter stringFromDate:expireDate]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalSeriesItemVo
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#import "MedalsLevelIndicatorView.h"
|
||||
|
||||
|
||||
@interface MedalsCollectionViewCell ()
|
||||
@interface MedalsCollectionViewCell () <VAPWrapViewDelegate, HWDMP4PlayDelegate>
|
||||
|
||||
@property(nonatomic, copy) NSString *imagePath;
|
||||
@property(nonatomic, copy) NSString *mp4Path;
|
||||
@@ -154,10 +154,19 @@
|
||||
self.mp4Path = nil;
|
||||
self.imagePath = nil;
|
||||
self.isVisible = NO;
|
||||
self.displayModel = nil; // 重置数据模型
|
||||
self.currentItemVo = nil; // 重置当前项
|
||||
|
||||
// 清空文本
|
||||
self.titleLabel.text = @"";
|
||||
self.subLabel.text = @"";
|
||||
|
||||
// 重置等级指示器
|
||||
[self.levelIndicatorView resetToLevel:0];
|
||||
|
||||
// 清空图片
|
||||
self.imageView.image = nil;
|
||||
self.imageView.imageUrl = @"";
|
||||
}
|
||||
|
||||
- (void)updateCell:(MedalSeriesVo *)model {
|
||||
@@ -172,11 +181,12 @@
|
||||
// 设置指示器类型为带图片
|
||||
self.levelIndicatorView.indicatorType = MedalsLevelIndicatorTypeNormal;
|
||||
|
||||
// 为每个等级设置对应的图片
|
||||
// 为每个等级设置对应的图片,使用新的 URL 优先级逻辑
|
||||
for (NSInteger i = 0; i < itemVos.medalVos.count; i++) {
|
||||
MedalVo *medalVo = [itemVos.medalVos xpSafeObjectAtIndex:i];
|
||||
if (medalVo) {
|
||||
[self.levelIndicatorView setImageUrl:medalVo.picUrl forLevel:i + 1];
|
||||
NSString *imageUrl = [self getImageUrlForMedal:medalVo];
|
||||
[self.levelIndicatorView setImageUrl:imageUrl forLevel:i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,21 +194,104 @@
|
||||
}
|
||||
|
||||
- (void)updateDisplayWithCurrentModel {
|
||||
if (self.displayModel) {
|
||||
if ([self.displayModel.picUrl hasSuffix:@"mp4"]) {
|
||||
[self setMp4Path:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
if (!self.displayModel || !self.currentItemVo) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 要手动 fix mp4 不播放的问题
|
||||
|
||||
// 优化后的判断逻辑:更严格的 MP4 URL 验证
|
||||
NSString *mp4Url = self.currentItemVo.mp4Url;
|
||||
NSString *picUrl = self.currentItemVo.picUrl;
|
||||
|
||||
// 首先检查是否有明确的 MP4 URL
|
||||
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
|
||||
[self setMp4Path:mp4Url];
|
||||
[self updateTextLabels];
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查 picUrl 是否实际上是 MP4(兼容旧逻辑)
|
||||
if (![NSString isEmpty:picUrl]) {
|
||||
if ([self isValidMP4URL:picUrl]) {
|
||||
[self setMp4Path:picUrl];
|
||||
[self updateTextLabels];
|
||||
return;
|
||||
} else if ([NSString isValidImageURL:picUrl]) {
|
||||
[self setImagePath:picUrl];
|
||||
[self updateTextLabels];
|
||||
return;
|
||||
}
|
||||
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
if (self.displayModel.expireSeconds == 0) {
|
||||
self.subLabel.text = YMLocalizedString(@"20.20.61_text_9");
|
||||
}
|
||||
|
||||
// 都不满足,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
|
||||
// 设置文本信息(无论是否有有效的媒体内容都要设置)
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = [self.displayModel expireDateString];
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
|
||||
/// 验证是否为有效的 MP4 URL
|
||||
- (BOOL)isValidMP4URL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// 检查 URL 是否以 mp4 结尾或包含 mp4 标识
|
||||
NSString *lowercaseUrl = [url lowercaseString];
|
||||
return [lowercaseUrl hasSuffix:@".mp4"] ||
|
||||
[lowercaseUrl containsString:@"mp4"] ||
|
||||
[lowercaseUrl containsString:@"video"];
|
||||
}
|
||||
|
||||
/// 更新文本标签
|
||||
- (void)updateTextLabels {
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = [self.displayModel expireDateString];
|
||||
}
|
||||
|
||||
/// 显示默认占位图
|
||||
- (void)showDefaultPlaceholder {
|
||||
[self stopMP4Playback];
|
||||
self.mp4View.hidden = YES;
|
||||
self.imageView.hidden = NO;
|
||||
|
||||
// 设置默认占位图
|
||||
self.imageView.imageUrl = @"";
|
||||
self.imageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
|
||||
/// 根据新的优先级逻辑获取勋章的图片URL
|
||||
- (NSString *)getImageUrlForMedal:(MedalVo *)medal {
|
||||
if (!medal) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Debug 环境:如果数据不满足新条件,使用原有逻辑
|
||||
if ([NSString isEmpty:medal.mp4Url] && ![NSString isEmpty:medal.picUrl]) {
|
||||
return medal.picUrl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 新逻辑:优先使用 mp4URL
|
||||
if (![NSString isEmpty:medal.mp4Url]) {
|
||||
return medal.mp4Url;
|
||||
} else if (![NSString isEmpty:medal.picUrl]) {
|
||||
// mp4URL 为空,使用 picURL (需要验证是否为有效图片)
|
||||
if ([NSString isValidImageURL:medal.picUrl]) {
|
||||
return medal.picUrl;
|
||||
} else {
|
||||
self.subLabel.text = [NSString stringWithFormat:YMLocalizedString(@"20.20.61_text_8"),
|
||||
[NSDate timestampSwitchTime:self.displayModel.expireSeconds
|
||||
formatter:@"yyyy/mm/dd"]];
|
||||
// picURL 不是有效图片,返回空字符串
|
||||
return @"";
|
||||
}
|
||||
} else {
|
||||
// 都为空,返回空字符串
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,19 +327,43 @@
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl]) {
|
||||
// 只有当 cell 可见时才播放
|
||||
// 延迟播放机制:先标记为准备就绪,等待明确的播放信号
|
||||
self.mp4View.tag = 1; // 标记已准备好播放
|
||||
|
||||
// 如果当前 Cell 可见,立即播放
|
||||
if (self.isVisible) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
} else {
|
||||
// 存储 URL,但不立即播放
|
||||
self.mp4View.tag = 1; // 标记已准备好播放
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
NSLog(@"Failed to parse mp4: %@", error);
|
||||
@kStrongify(self);
|
||||
NSLog(@"[MedalsCollectionViewCell] Failed to parse mp4: %@, fallback to image", error);
|
||||
// MP4 解析失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
/// 开始 MP4 播放
|
||||
- (void)startMP4PlaybackWithURL:(NSString *)videoUrl {
|
||||
if (![NSString isEmpty:videoUrl] && self.mp4View && !self.mp4View.hidden) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:self];
|
||||
NSLog(@"[MedalsCollectionViewCell] Started MP4 playback: %@", videoUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理 MP4 播放失败,降级使用 picURL
|
||||
- (void)handleMP4FailureWithFallback {
|
||||
if (![NSString isEmpty:self.displayModel.picUrl]) {
|
||||
if ([NSString isValidImageURL:self.displayModel.picUrl]) {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MP4 播放控制
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
@@ -270,20 +387,58 @@
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:nil];
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 恢复播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
} else {
|
||||
[self.mp4View resumeHWDMP4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)vapWrap_viewDidFailPlayMP4:(NSError *)error {
|
||||
NSLog(@"%@", error);
|
||||
}
|
||||
|
||||
#pragma mark - HWDMP4PlayDelegate
|
||||
|
||||
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
|
||||
// MP4 播放完成,循环播放会自动重新开始
|
||||
}
|
||||
|
||||
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
|
||||
// MP4 播放停止
|
||||
}
|
||||
|
||||
- (void)viewDidFailPlayMP4:(NSError *)error {
|
||||
NSLog(@"MP4 播放失败: %@", error);
|
||||
// MP4 播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}
|
||||
|
||||
#pragma mark - 可见性管理
|
||||
|
||||
- (void)willDisplay {
|
||||
self.isVisible = YES;
|
||||
[self resumeMP4Playback];
|
||||
|
||||
// 如果有准备好的 MP4,立即开始播放
|
||||
if (self.mp4View.tag == 1 && !self.mp4View.hidden && self.mp4Path) {
|
||||
[self resumeMP4Playback];
|
||||
} else if (!self.mp4View.hidden) {
|
||||
// 恢复之前暂停的播放
|
||||
[self resumeMP4Playback];
|
||||
}
|
||||
|
||||
NSLog(@"[MedalsCollectionViewCell] willDisplay - isVisible: %@, mp4Path: %@",
|
||||
self.isVisible ? @"YES" : @"NO", self.mp4Path ?: @"nil");
|
||||
}
|
||||
|
||||
- (void)didEndDisplaying {
|
||||
@@ -327,7 +482,7 @@
|
||||
- (VAPView *)mp4View {
|
||||
if (!_mp4View) {
|
||||
_mp4View = [[VAPView alloc] init];
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFill;
|
||||
}
|
||||
return _mp4View;
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#import <QGVAPWrapView.h>
|
||||
#import "XPRoomGiftAnimationParser.h"
|
||||
|
||||
@interface MedalsCyclePagerCell ()
|
||||
@interface MedalsCyclePagerCell () <HWDMP4PlayDelegate>
|
||||
|
||||
@property(nonatomic, copy) NSString *imagePath;
|
||||
@property(nonatomic, copy) NSString *mp4Path;
|
||||
@@ -99,9 +99,11 @@
|
||||
self.mp4Path = nil;
|
||||
self.imagePath = nil;
|
||||
self.isVisible = YES;
|
||||
self.displayModel = nil; // 重置数据模型
|
||||
|
||||
// 清空图片
|
||||
self.imageView.image = nil;
|
||||
self.imageView.imageUrl = @"";
|
||||
}
|
||||
|
||||
- (void)updateCell:(MedalVo *)model {
|
||||
@@ -110,13 +112,60 @@
|
||||
}
|
||||
|
||||
- (void)updateDisplayWithCurrentModel {
|
||||
if (self.displayModel) {
|
||||
if ([self.displayModel.picUrl hasSuffix:@"mp4"]) {
|
||||
[self setMp4Path:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
if (!self.displayModel) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
// 优化后的判断逻辑:更严格的 MP4 URL 验证
|
||||
NSString *mp4Url = self.displayModel.mp4Url;
|
||||
NSString *picUrl = self.displayModel.picUrl;
|
||||
|
||||
// 首先检查是否有明确的 MP4 URL
|
||||
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
|
||||
[self setMp4Path:mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查 picUrl 是否实际上是 MP4(兼容旧逻辑)
|
||||
if (![NSString isEmpty:picUrl]) {
|
||||
if ([self isValidMP4URL:picUrl]) {
|
||||
[self setMp4Path:picUrl];
|
||||
return;
|
||||
} else if ([NSString isValidImageURL:picUrl]) {
|
||||
[self setImagePath:picUrl];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 都不满足,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
|
||||
/// 验证是否为有效的 MP4 URL
|
||||
- (BOOL)isValidMP4URL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// 检查 URL 是否以 mp4 结尾或包含 mp4 标识
|
||||
NSString *lowercaseUrl = [url lowercaseString];
|
||||
return [lowercaseUrl hasSuffix:@".mp4"] ||
|
||||
[lowercaseUrl containsString:@"mp4"] ||
|
||||
[lowercaseUrl containsString:@"video"];
|
||||
}
|
||||
|
||||
/// 显示默认占位图
|
||||
- (void)showDefaultPlaceholder {
|
||||
[self stopMP4Playback];
|
||||
self.mp4View.hidden = YES;
|
||||
self.imageView.hidden = NO;
|
||||
|
||||
// 设置默认占位图,如果没有可以使用透明图片或者空白
|
||||
self.imageView.imageUrl = @"";
|
||||
self.imageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
|
||||
- (void)setImagePath:(NSString *)imagePath {
|
||||
@@ -151,19 +200,43 @@
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl]) {
|
||||
// 只有当 cell 可见时才播放
|
||||
// 延迟播放机制:先标记为准备就绪,等待明确的播放信号
|
||||
self.mp4View.tag = 1; // 标记已准备好播放
|
||||
|
||||
// 如果当前 Cell 可见,立即播放
|
||||
if (self.isVisible) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
} else {
|
||||
// 存储 URL,但不立即播放
|
||||
self.mp4View.tag = 1; // 标记已准备好播放
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
NSLog(@"Failed to parse mp4: %@", error);
|
||||
@kStrongify(self);
|
||||
NSLog(@"[MedalsCyclePagerCell] Failed to parse mp4: %@, fallback to image", error);
|
||||
// MP4 解析失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
/// 开始 MP4 播放
|
||||
- (void)startMP4PlaybackWithURL:(NSString *)videoUrl {
|
||||
if (![NSString isEmpty:videoUrl] && self.mp4View && !self.mp4View.hidden) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:self];
|
||||
NSLog(@"[MedalsCyclePagerCell] Started MP4 playback: %@", videoUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理 MP4 播放失败,降级使用 picURL
|
||||
- (void)handleMP4FailureWithFallback {
|
||||
if (![NSString isEmpty:self.displayModel.picUrl]) {
|
||||
if ([NSString isValidImageURL:self.displayModel.picUrl]) {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MP4 播放控制
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
@@ -187,9 +260,13 @@
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:nil];
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 恢复播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
} else {
|
||||
[self.mp4View resumeHWDMP4];
|
||||
}
|
||||
@@ -200,7 +277,17 @@
|
||||
|
||||
- (void)willDisplay {
|
||||
self.isVisible = YES;
|
||||
[self resumeMP4Playback];
|
||||
|
||||
// 如果有准备好的 MP4,立即开始播放
|
||||
if (self.mp4View.tag == 1 && !self.mp4View.hidden && self.mp4Path) {
|
||||
[self resumeMP4Playback];
|
||||
} else if (!self.mp4View.hidden) {
|
||||
// 恢复之前暂停的播放
|
||||
[self resumeMP4Playback];
|
||||
}
|
||||
|
||||
NSLog(@"[MedalsCyclePagerCell] willDisplay - isVisible: %@, mp4Path: %@",
|
||||
self.isVisible ? @"YES" : @"NO", self.mp4Path ?: @"nil");
|
||||
}
|
||||
|
||||
- (void)didEndDisplaying {
|
||||
@@ -247,8 +334,31 @@
|
||||
if (!_mp4View) {
|
||||
_mp4View = [[VAPView alloc] init];
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFit;
|
||||
#if DEBUG
|
||||
_mp4View.backgroundColor = [UIColor redColor];
|
||||
#endif
|
||||
}
|
||||
return _mp4View;
|
||||
}
|
||||
|
||||
#pragma mark - HWDMP4PlayDelegate
|
||||
|
||||
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
|
||||
// MP4 播放完成,循环播放会自动重新开始
|
||||
}
|
||||
|
||||
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
|
||||
// MP4 播放停止
|
||||
}
|
||||
|
||||
- (void)viewDidFailPlayMP4:(NSError *)error {
|
||||
NSLog(@"MP4 播放失败: %@", error);
|
||||
// MP4 播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -130,11 +130,12 @@
|
||||
// 设置指示器类型为带图片
|
||||
self.levelIndicatorView.indicatorType = MedalsLevelIndicatorTypeWithImage;
|
||||
|
||||
// 为每个等级设置对应的图片
|
||||
// 为每个等级设置对应的图片,使用新的 URL 优先级逻辑
|
||||
for (NSInteger i = 0; i < self.currentSeriesItemVO.medalVos.count; i++) {
|
||||
MedalVo *medalVo = [self.currentSeriesItemVO.medalVos xpSafeObjectAtIndex:i];
|
||||
if (medalVo) {
|
||||
[self.levelIndicatorView setImageUrl:medalVo.picUrl forLevel:i + 1];
|
||||
NSString *imageUrl = [self getImageUrlForMedal:medalVo];
|
||||
[self.levelIndicatorView setImageUrl:imageUrl forLevel:i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,15 +143,86 @@
|
||||
}
|
||||
|
||||
- (void)updateDisplayWithCurrentModel {
|
||||
if (self.displayModel) {
|
||||
if (!self.displayModel) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Debug 环境:如果数据不满足新条件,使用原有逻辑
|
||||
if ([NSString isEmpty:self.displayModel.mp4Url] && ![NSString isEmpty:self.displayModel.picUrl]) {
|
||||
// 使用原有逻辑:通过 picUrl 后缀判断
|
||||
if ([self.displayModel.picUrl hasSuffix:@"mp4"]) {
|
||||
[self setMp4Path:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
}
|
||||
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = self.displayModel.medalDesc;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 新逻辑:优先使用 mp4URL
|
||||
if (![NSString isEmpty:self.displayModel.mp4Url]) {
|
||||
[self setMp4Path:self.displayModel.mp4Url];
|
||||
} else if (![NSString isEmpty:self.displayModel.picUrl]) {
|
||||
// mp4URL 为空,使用 picURL
|
||||
if ([NSString isValidImageURL:self.displayModel.picUrl]) {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
} else {
|
||||
// picURL 不是有效图片,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
} else {
|
||||
// 都为空,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = self.displayModel.medalDesc;
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
|
||||
/// 显示默认占位图
|
||||
- (void)showDefaultPlaceholder {
|
||||
[self stopMP4Playback];
|
||||
self.mp4View.hidden = YES;
|
||||
self.imageView.hidden = NO;
|
||||
|
||||
// 设置默认占位图
|
||||
self.imageView.imageUrl = @"";
|
||||
self.imageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
|
||||
/// 根据新的优先级逻辑获取勋章的图片URL
|
||||
- (NSString *)getImageUrlForMedal:(MedalVo *)medal {
|
||||
if (!medal) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Debug 环境:如果数据不满足新条件,使用原有逻辑
|
||||
if ([NSString isEmpty:medal.mp4Url] && ![NSString isEmpty:medal.picUrl]) {
|
||||
return medal.picUrl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 新逻辑:优先使用 mp4URL
|
||||
if (![NSString isEmpty:medal.mp4Url]) {
|
||||
return medal.mp4Url;
|
||||
} else if (![NSString isEmpty:medal.picUrl]) {
|
||||
// mp4URL 为空,使用 picURL (需要验证是否为有效图片)
|
||||
if ([NSString isValidImageURL:medal.picUrl]) {
|
||||
return medal.picUrl;
|
||||
} else {
|
||||
// picURL 不是有效图片,返回空字符串
|
||||
return @"";
|
||||
}
|
||||
} else {
|
||||
// 都为空,返回空字符串
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,9 +238,9 @@
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
return;
|
||||
}
|
||||
// if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 停止之前的 mp4 播放
|
||||
[self stopMP4Playback];
|
||||
@@ -189,10 +261,26 @@
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
NSLog(@"Failed to parse mp4: %@", error);
|
||||
// MP4 解析失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
/// 处理 MP4 播放失败,降级使用 picURL
|
||||
- (void)handleMP4FailureWithFallback {
|
||||
if (![NSString isEmpty:self.displayModel.picUrl]) {
|
||||
if ([NSString isValidImageURL:self.displayModel.picUrl]) {
|
||||
[self setImagePath:self.displayModel.picUrl];
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MP4 播放控制
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
@@ -218,7 +306,11 @@
|
||||
if (![NSString isEmpty:videoUrl]) {
|
||||
[self.mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
}
|
||||
} failureBlock:nil];
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 恢复播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
} else {
|
||||
[self.mp4View resumeHWDMP4];
|
||||
}
|
||||
|
@@ -23,6 +23,12 @@ typedef NS_ENUM(NSInteger, MedalsLevelIndicatorType) {
|
||||
- (void)setupWithMaxLevel:(NSInteger)maxLevel;
|
||||
- (void)setSelectedLevel:(NSInteger)level animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* 重置等级指示器到指定等级
|
||||
* @param level 等级(0表示重置到初始状态)
|
||||
*/
|
||||
- (void)resetToLevel:(NSInteger)level;
|
||||
|
||||
/**
|
||||
* 设置指定等级的图片
|
||||
* @param imageUrl 图片URL
|
||||
|
@@ -141,7 +141,17 @@
|
||||
}
|
||||
|
||||
- (void)setImageUrl:(NSString *)imageUrl {
|
||||
// 判断是 MP4 还是图片
|
||||
// 检查URL是否为空
|
||||
#if 0
|
||||
imageUrl = @"https://img.toto.im/mw600/9f0b0dd5ly1i2u07wq7g2j20n00w343s.jpg.webp";
|
||||
#endif
|
||||
if ([NSString isEmpty:imageUrl]) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Debug 环境:使用原有逻辑
|
||||
if ([imageUrl.lowercaseString hasSuffix:@"mp4"]) {
|
||||
[self setMP4Url:imageUrl];
|
||||
} else {
|
||||
@@ -157,6 +167,50 @@
|
||||
[self loadImageWithUrl:imageUrl];
|
||||
}
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
// 新逻辑:只显示图片,MP4 显示占位图
|
||||
if ([imageUrl.lowercaseString hasSuffix:@"mp4"]) {
|
||||
// MP4 URL:显示占位图(保留MP4处理代码备用)
|
||||
[self showDefaultPlaceholder];
|
||||
// [self setMP4Url:imageUrl]; // 保留备用
|
||||
} else if ([NSString isValidImageURL:imageUrl]) {
|
||||
// 验证为有效图片URL
|
||||
_hasImage = YES;
|
||||
_hasMP4 = NO;
|
||||
_cachedImageUrl = imageUrl;
|
||||
|
||||
// 停止 MP4 播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
// 如果已经创建了imageView,直接加载图片
|
||||
if (_imageView) {
|
||||
[self loadImageWithUrl:imageUrl];
|
||||
}
|
||||
} else {
|
||||
// URL 不是有效的图片,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
/// 显示默认占位图
|
||||
- (void)showDefaultPlaceholder {
|
||||
// 停止 MP4 播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
_hasImage = NO;
|
||||
_hasMP4 = NO;
|
||||
_cachedImageUrl = nil;
|
||||
_cachedMP4Url = nil;
|
||||
|
||||
if (_imageView) {
|
||||
_imageView.hidden = NO;
|
||||
_imageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
if (_mp4View) {
|
||||
_mp4View.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMP4Url:(NSString *)mp4Url {
|
||||
@@ -182,6 +236,7 @@
|
||||
@kStrongify(self);
|
||||
if (image) {
|
||||
UIImage *cutImage = [image cutImage:CGSizeMake(40, 40)];
|
||||
self.hasImage = YES;
|
||||
self.originalImage = cutImage;
|
||||
self.grayImage = [cutImage grayscaleImage];
|
||||
[self updateImageEffect];
|
||||
@@ -214,8 +269,10 @@
|
||||
});
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 加载失败时的处理
|
||||
NSLog(@"MP4 加载失败: %@", error);
|
||||
[self showDefaultPlaceholder];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -239,13 +296,13 @@
|
||||
}
|
||||
|
||||
// MP4 的选中效果处理 - 使用简单的 alpha 透明度
|
||||
if (_hasMP4 && _mp4View) {
|
||||
if (_isSelected) {
|
||||
_mp4View.alpha = 1.0; // 选中状态:完全不透明
|
||||
} else {
|
||||
_mp4View.alpha = 0.3; // 非选中状态:半透明
|
||||
}
|
||||
}
|
||||
// if (_hasMP4 && _mp4View) {
|
||||
// if (_isSelected) {
|
||||
// _mp4View.alpha = 1.0; // 选中状态:完全不透明
|
||||
// } else {
|
||||
// _mp4View.alpha = 0.3; // 非选中状态:半透明
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
@@ -484,6 +541,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetToLevel:(NSInteger)level {
|
||||
// 停止所有MP4播放
|
||||
for (LevelItemView *item in _levelItems) {
|
||||
[item stopMP4Playback];
|
||||
}
|
||||
|
||||
// 重置选中状态
|
||||
if (level <= 0) {
|
||||
// 重置到初始状态
|
||||
[self setSelectedLevel:1 animated:NO];
|
||||
} else {
|
||||
// 重置到指定等级
|
||||
[self setSelectedLevel:level animated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setIndicatorType:(MedalsLevelIndicatorType)indicatorType {
|
||||
_indicatorType = indicatorType;
|
||||
|
||||
|
@@ -815,6 +815,15 @@ typedef enum : NSInteger {
|
||||
[self.medalsCollectionView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - 数据刷新
|
||||
- (void)refreshDataAfterWearingChange {
|
||||
// 只有在 Mine 模式下才需要刷新(因为只有自己的勋章页面会受到佩戴变化影响)
|
||||
if (self.displayType == MedalsCenterDisplayType_Mine) {
|
||||
// 重新加载当前 tab 的数据
|
||||
[self loadMedalsList:self.currentTabType page:1];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Button actions
|
||||
- (void)didTapSquareButton:(UIButton *)sender {
|
||||
MedalsViewController *vc = [[MedalsViewController alloc] initForMedalsSquare];
|
||||
@@ -828,12 +837,30 @@ typedef enum : NSInteger {
|
||||
|
||||
- (void)didTapWearingButton:(UIButton *)sender {
|
||||
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
|
||||
|
||||
// 设置数据变化回调
|
||||
@kWeakify(self);
|
||||
vc.dataChangedCallback = ^{
|
||||
@kStrongify(self);
|
||||
// 刷新数据
|
||||
[self refreshDataAfterWearingChange];
|
||||
};
|
||||
|
||||
[self addChildViewController:vc];
|
||||
[self.view addSubview:vc.view];
|
||||
}
|
||||
|
||||
- (void)didTapEmptyMedalButton:(UIButton *)sender {
|
||||
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
|
||||
|
||||
// 设置数据变化回调
|
||||
@kWeakify(self);
|
||||
vc.dataChangedCallback = ^{
|
||||
@kStrongify(self);
|
||||
// 刷新数据
|
||||
[self refreshDataAfterWearingChange];
|
||||
};
|
||||
|
||||
[self addChildViewController:vc];
|
||||
[self.view addSubview:vc.view];
|
||||
}
|
||||
@@ -952,6 +979,9 @@ typedef enum : NSInteger {
|
||||
if (self.useMedals.count > 1 && self.displayType == MedalsCenterDisplayType_Square) {
|
||||
[self startAutoScroll:toIndex];
|
||||
}
|
||||
|
||||
MedalVo *vo = [self.useMedals xpSafeObjectAtIndex:toIndex];
|
||||
self.medalDescLabel.text = [vo expireDateString];
|
||||
}
|
||||
|
||||
#pragma mark - Lazy load
|
||||
|
@@ -88,6 +88,66 @@
|
||||
self.medalImageView.imageUrl = @"";
|
||||
return;
|
||||
}
|
||||
|
||||
// 按照新的显示逻辑处理(该 Cell 只支持图片显示)
|
||||
[self handleMedalDisplay:medalVo];
|
||||
}
|
||||
|
||||
#pragma mark - 新的显示逻辑
|
||||
- (void)handleMedalDisplay:(MedalVo *)medalVo {
|
||||
if (!medalVo) {
|
||||
self.medalImageView.imageUrl = @"";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug 环境:如果数据不满足新逻辑条件,使用现有逻辑
|
||||
if ([NSString isEmpty:medalVo.mp4Url] && [NSString isEmpty:medalVo.picUrl]) {
|
||||
// 都为空,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalVo];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSString isEmpty:medalVo.picUrl] && [NSString isEmpty:medalVo.mp4Url]) {
|
||||
// 只有 picUrl 有值,mp4Url 为空,检查是否符合新逻辑
|
||||
if (![NSString isImageFormat:medalVo.picUrl] && ![medalVo.picUrl.lowercaseString hasSuffix:@".mp4"]) {
|
||||
// picUrl 既不是图片也不是 mp4,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalVo];
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. 优先判断 mp4Url 是否有内容
|
||||
if (![NSString isEmpty:medalVo.mp4Url]) {
|
||||
// 该 Cell 不支持 mp4,降级使用 picUrl
|
||||
if (![NSString isEmpty:medalVo.picUrl] && [NSString isImageFormat:medalVo.picUrl]) {
|
||||
self.medalImageView.imageUrl = medalVo.picUrl;
|
||||
} else {
|
||||
// picUrl 不是图片格式或为空,显示默认占位图
|
||||
self.medalImageView.imageUrl = @"";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. mp4Url 为空,使用 picUrl
|
||||
if (![NSString isEmpty:medalVo.picUrl]) {
|
||||
// 3. 使用 picUrl 时,判断内容是否为图片
|
||||
if ([NSString isImageFormat:medalVo.picUrl]) {
|
||||
self.medalImageView.imageUrl = medalVo.picUrl;
|
||||
} else {
|
||||
// 不是图片格式,显示默认占位图
|
||||
self.medalImageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 都为空,显示默认占位图
|
||||
self.medalImageView.imageUrl = @"";
|
||||
}
|
||||
|
||||
#pragma mark - 旧版显示逻辑(用于 Debug 环境兼容)
|
||||
- (void)handleLegacyDisplay:(MedalVo *)medalVo {
|
||||
if (![medalVo.picUrl hasSuffix:@"mp4"]) {
|
||||
self.medalImageView.imageUrl = medalVo.picUrl;
|
||||
}
|
||||
@@ -122,6 +182,7 @@
|
||||
NetImageConfig *config = [[NetImageConfig alloc] init];
|
||||
config.placeHolder = kImage(@"medals_control_position");
|
||||
_medalImageView = [[NetImageView alloc] initWithConfig:config];
|
||||
_medalImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
}
|
||||
return _medalImageView;
|
||||
}
|
||||
|
@@ -22,6 +22,9 @@
|
||||
|
||||
@property (nonatomic, assign) BOOL isVisible; // 跟踪 cell 是否可见
|
||||
|
||||
// 新增属性:用于降级处理
|
||||
@property (nonatomic, strong) MedalVo *currentMedalModel; // 当前显示的 medal 模型
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalsWearingListCollectionViewCell
|
||||
@@ -43,6 +46,84 @@
|
||||
|
||||
- (void)updateCell:(MedalVo *)medalModel {
|
||||
self.selectedImageView.hidden = medalModel.useStatus==NO;
|
||||
|
||||
// 保存当前模型,用于降级处理
|
||||
self.currentMedalModel = medalModel;
|
||||
|
||||
// 按照新的显示逻辑处理
|
||||
[self handleMedalDisplay:medalModel];
|
||||
}
|
||||
|
||||
#pragma mark - 新的显示逻辑
|
||||
- (void)handleMedalDisplay:(MedalVo *)medalModel {
|
||||
if (!medalModel) {
|
||||
[self setImagePath:@""];
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug 环境:如果数据不满足新逻辑条件,使用现有逻辑
|
||||
if ([NSString isEmpty:medalModel.mp4Url] && [NSString isEmpty:medalModel.picUrl]) {
|
||||
// 都为空,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalModel];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSString isEmpty:medalModel.picUrl] && [NSString isEmpty:medalModel.mp4Url]) {
|
||||
// 只有 picUrl 有值,mp4Url 为空,检查是否符合新逻辑
|
||||
if (![NSString isImageFormat:medalModel.picUrl] && ![medalModel.picUrl.lowercaseString hasSuffix:@".mp4"]) {
|
||||
// picUrl 既不是图片也不是 mp4,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalModel];
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. 优先判断 mp4Url 是否有内容
|
||||
if (![NSString isEmpty:medalModel.mp4Url]) {
|
||||
[self setMp4Path:medalModel.mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. mp4Url 为空,使用 picUrl
|
||||
if (![NSString isEmpty:medalModel.picUrl]) {
|
||||
// 3. 使用 picUrl 时,判断内容是否为图片
|
||||
if ([NSString isImageFormat:medalModel.picUrl]) {
|
||||
[self setImagePath:medalModel.picUrl];
|
||||
} else {
|
||||
// 不是图片格式,显示默认占位图
|
||||
[self setImagePath:@""];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 都为空,显示默认占位图
|
||||
[self setImagePath:@""];
|
||||
}
|
||||
|
||||
#pragma mark - mp4 失败降级处理
|
||||
- (void)handleMp4FailureFallback {
|
||||
if (!self.currentMedalModel) {
|
||||
[self setImagePath:@""];
|
||||
return;
|
||||
}
|
||||
|
||||
// mp4 下载失败,降级使用 picUrl
|
||||
if (![NSString isEmpty:self.currentMedalModel.picUrl]) {
|
||||
if ([NSString isImageFormat:self.currentMedalModel.picUrl]) {
|
||||
[self setImagePath:self.currentMedalModel.picUrl];
|
||||
} else {
|
||||
// picUrl 也不是图片格式,显示默认占位图
|
||||
[self setImagePath:@""];
|
||||
}
|
||||
} else {
|
||||
// picUrl 为空,显示默认占位图
|
||||
[self setImagePath:@""];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 旧版显示逻辑(用于 Debug 环境兼容)
|
||||
- (void)handleLegacyDisplay:(MedalVo *)medalModel {
|
||||
if ([medalModel.picUrl hasSuffix:@"mp4"]) {
|
||||
[self setMp4Path:medalModel.picUrl];
|
||||
} else {
|
||||
@@ -135,6 +216,8 @@
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
NSLog(@"Failed to parse mp4: %@", error);
|
||||
// mp4 下载失败时,降级使用 picUrl
|
||||
[self handleMp4FailureFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -264,6 +347,7 @@
|
||||
self.mp4Path = nil;
|
||||
self.imagePath = nil;
|
||||
self.isVisible = NO;
|
||||
self.currentMedalModel = nil; // 重置当前模型
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -11,6 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MedalsWearingViewController : MvpViewController
|
||||
|
||||
/// 数据变化回调,当佩戴数据发生改变时触发
|
||||
@property (nonatomic, copy) void (^dataChangedCallback)(void);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@@ -26,6 +26,9 @@
|
||||
@property (nonatomic, copy) NSDictionary *vipSeatDic;
|
||||
@property (nonatomic, assign) NSInteger minVipLevelForSeats;
|
||||
|
||||
// 数据变化标记
|
||||
@property (nonatomic, assign) BOOL hasDataChanged;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalsWearingViewController
|
||||
@@ -42,6 +45,7 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
self.medalsAreaPage = 1;
|
||||
self.hasDataChanged = NO; // 初始化数据变化标记
|
||||
|
||||
[self setupUI];
|
||||
[self setupRefresh];
|
||||
@@ -88,6 +92,15 @@
|
||||
|
||||
#pragma mark - User Actions
|
||||
- (void)handleTapGesture:(id)sender {
|
||||
[self dismissViewController];
|
||||
}
|
||||
|
||||
- (void)dismissViewController {
|
||||
// 如果数据发生了变化,触发回调
|
||||
if (self.hasDataChanged && self.dataChangedCallback) {
|
||||
self.dataChangedCallback();
|
||||
}
|
||||
|
||||
[self.view removeFromSuperview];
|
||||
[self removeFromParentViewController];
|
||||
}
|
||||
@@ -123,6 +136,8 @@
|
||||
}
|
||||
|
||||
- (void)useMedalSuccess {
|
||||
// 标记数据已变化
|
||||
self.hasDataChanged = YES;
|
||||
[self headerRefresh];
|
||||
}
|
||||
|
||||
|
@@ -53,6 +53,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (NSString *)trimString:(NSString *)input lengthLimit:(NSInteger)limit;
|
||||
|
||||
+ (BOOL)isValidImageURL:(NSString *)url;
|
||||
|
||||
/// 检查字符串是否为图片格式(通过扩展名判断)
|
||||
+ (BOOL)isImageFormat:(NSString *)url;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
@@ -516,4 +516,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断 URL 是否为有效的图片格式
|
||||
+ (BOOL)isValidImageURL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *lowercaseURL = url.lowercaseString;
|
||||
NSArray *imageExtensions = @[@"png", @"jpg", @"jpeg", @"gif", @"webp", @"bmp", @"svg"];
|
||||
|
||||
for (NSString *extension in imageExtensions) {
|
||||
if ([lowercaseURL hasSuffix:extension]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/// 检查字符串是否为图片格式(通过扩展名判断)
|
||||
+ (BOOL)isImageFormat:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *lowercaseURL = url.lowercaseString;
|
||||
NSArray *imageExtensions = @[@".png", @".jpg", @".jpeg", @".gif", @".webp", @".bmp", @".svg"];
|
||||
|
||||
for (NSString *extension in imageExtensions) {
|
||||
if ([lowercaseURL hasSuffix:extension]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
Reference in New Issue
Block a user