Files
peko-ios/YuMi/Modules/YMRoom/View/AnimationView/GameUniversalBannerView.m

374 lines
13 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// GameUniversalBannerView.m
// YuMi
//
// Created by P on 2024/10/15.
//
#import "GameUniversalBannerView.h"
#import <POP.h>
#import <SVGA.h>
#import "AttachmentModel.h"
#import "PIUniversalBannerModel.h"
@interface GameUniversalBannerView ()
@property (nonatomic, strong) NetImageView *bgImageView;
@property (nonatomic, strong) SVGAImageView *bgSVGA;
@property (nonatomic, strong) NetImageView *gameIcon;
@property (nonatomic, strong) NetImageView *avatarIcon;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *goButton;
@property (nonatomic, assign) NSString *gameID;
@property (nonatomic, strong) SVGAParser *parser;
@property(nonatomic, assign) bool alreadyCancel;
@property (nonatomic, copy) void(^completeDisplay)(void);
@property (nonatomic, copy) void(^didTapGo)(NSInteger gameID);
@end
@implementation GameUniversalBannerView
+ (void)display:(UIView *)superView
with:(AttachmentModel *)attachment
complete:(void(^)(void))complete
goToGame:(void(^)(NSInteger gameID))go {
CGFloat width = KScreenWidth;
CGFloat height = kGetScaleWidth(70);
PIUniversalBannerModel *model = [PIUniversalBannerModel modelWithDictionary:attachment.data];
GameUniversalBannerView *bannerView = [[GameUniversalBannerView alloc] initWithFrame:CGRectMake(KScreenWidth, 0, width, height)];
bannerView.model = model;
bannerView.completeDisplay = complete;
bannerView.didTapGo = go;
bannerView.gameID = model.skipContent;
[superView addSubview:bannerView];
[bannerView addNotification];
@kWeakify(bannerView);
[bannerView popEnterAnimation:^(BOOL finished) {
if (finished && bannerView.alreadyCancel == NO) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@kStrongify(bannerView);
[bannerView popLeaveAnimation:^(bool finished) {
if (bannerView.completeDisplay) {
bannerView.completeDisplay();
}
[bannerView removeFromSuperview];
}];
});
}
}];
}
- (void)addNotification {
@kWeakify(self);
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull notification) {
@kStrongify(self);
[self dismissBanner];
}];
}
- (void)dismissBanner {
NSLog(@"🚨 GameUniversalBannerView dismissBanner 被调用");
self.alreadyCancel = YES;
[self pop_removeAllAnimations]; // 停止所有动画
[self popLeaveAnimation:^(bool finished) {
NSLog(@"🚨 GameUniversalBannerView 动画完成,调用回调");
if (self.completeDisplay) {
self.completeDisplay();
} else {
NSLog(@"🚨 警告: completeDisplay 回调为空");
}
[self removeFromSuperview];
}];
}
- (void)popEnterAnimation:(void(^)(BOOL finished))finish {
NSInteger height = kGetScaleWidth(70);
POPSpringAnimation *enterAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
enterAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, KScreenWidth, height)];
enterAnimation.springBounciness = 10; // 弹性系数
enterAnimation.springSpeed = 12; // 动画速度
enterAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finish) {
finish(finished);
}
};
[self pop_addAnimation:enterAnimation forKey:@"enterAnimation"];
}
- (void)popLeaveAnimation:(void(^)(bool finished))finish {
NSInteger height = kGetScaleWidth(70);
POPBasicAnimation *exitAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewFrame];
exitAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(-KScreenWidth, 0, KScreenWidth, height)];
exitAnimation.duration = 0.25; // 动画持续时间
exitAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
exitAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finish) {
finish(finished);
}
};
[self pop_addAnimation:exitAnimation forKey:@"exitAnimation"];
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self addSubview:self.bgSVGA];
[self.bgSVGA mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self addSubview:self.bgImageView];
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self addSubview:self.gameIcon];
[self.gameIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(44);
make.height.mas_equalTo(44);
make.centerY.mas_equalTo(self);
make.leading.mas_equalTo(35);
}];
[self addSubview:self.avatarIcon];
[self.avatarIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(28);
make.height.mas_equalTo(28);
make.centerY.mas_equalTo(self);
make.leading.mas_equalTo(self.gameIcon.mas_trailing).offset(5);
}];
[self addSubview:self.goButton];
[self.goButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self);
make.trailing.mas_equalTo(-36);
make.size.mas_equalTo(CGSizeMake(35, 20));
}];
[self addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(117);
make.trailing.mas_equalTo(-80);
make.centerY.mas_equalTo(self.goButton);
make.height.mas_equalTo(70);
}];
}
return self;
}
- (void)setEntity:(SVGAVideoEntity *)entity {
_entity = entity;
self.bgSVGA.videoItem = entity;
[self.bgSVGA autoPlay];
}
- (void)setModel:(PIUniversalBannerModel *)model {
_model = model;
NSDictionary *textDic = model.template;
if(textDic.allKeys.count == 0) {
return ;
}
NSString *key = [NSBundle uploadLanguageText];
NSString *title = textDic[key] == nil ? textDic[textDic.allKeys.firstObject] : textDic[key];
if(title.length == 0) {
return;
}
[title stringByReplacingOccurrencesOfString:@"\n" withString:@""];
if (_model.fontSize <= 0){
_model.fontSize = 12;
}
CGFloat font = _model.fontSize;
NSMutableAttributedString * attribute = [[NSMutableAttributedString alloc] initWithString:title
attributes:@{
NSFontAttributeName:[UIFont systemFontOfSize:font],
NSForegroundColorAttributeName:[DJDKMIMOMColor colorWithHexString:_model.textColor]}];
for (PIUniversalBannerItemModel *model in _model.contents) {
if([model.type isEqualToString:@"TEXT"]){
NSDictionary *subTextDic = model.text;
if(subTextDic.allKeys.count > 0){
NSString *subText = subTextDic[key] == nil ? subTextDic[subTextDic.allKeys.firstObject] : subTextDic[key];
NSAttributedString *attText = [[NSAttributedString alloc]initWithString:subText attributes:@{NSForegroundColorAttributeName:[DJDKMIMOMColor colorWithHexString:model.textColor],NSFontAttributeName:[UIFont systemFontOfSize:font]}];
if ([attribute.string containsString:[NSString stringWithFormat:@"{%@}",model.key]]){
[attribute replaceCharactersInRange:[attribute.string rangeOfString:[NSString stringWithFormat:@"{%@}",model.key]] withAttributedString:attText];
}
}
} else if ([model.type isEqualToString:@"IMAGE"]) {
if ([model.key isEqualToString:@"avatar"]) {
[self.avatarIcon loadImageWithUrl:model.image completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) {
if (!image) {
[self.avatarIcon mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(0);
}];
} else {
self.avatarIcon.image = image;
}
}];
} else if ([model.key isEqualToString:@"gameIcon"]) {
[self.gameIcon loadImageWithUrl:model.image completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) {
if (!image) {
[self.gameIcon mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(0);
}];
} else {
self.gameIcon.image = image;
}
}];
}
if ([attribute.string containsString:[NSString stringWithFormat:@"{%@}",model.key]]){
[attribute replaceCharactersInRange:[attribute.string rangeOfString:[NSString stringWithFormat:@"{%@}",model.key]] withAttributedString:[NSAttributedString new]];
}
}
}
self.titleLabel.attributedText = attribute;
BOOL isSvga = [model.resourceType.uppercaseString isEqualToString:@"SVGA"];
@kWeakify(self);
if (isSvga == YES) {
self.bgSVGA.hidden = NO;
self.bgImageView.hidden = YES;
if (!_parser) {
_parser = [SVGAParser new];
}
[self.parser parseWithURL:[NSURL URLWithString:model.resourceContent] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
self.bgSVGA.videoItem = videoItem;
} failureBlock:^(NSError * _Nonnull error) {
@kStrongify(self);
[self loadLocalSVGA];
}];
}else{
self.bgSVGA.hidden = YES;
self.bgImageView.hidden = NO;
@kWeakify(self);
[self.bgImageView loadImageWithUrl:model.resourceContent completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) {
@kStrongify(self);
if (image) {
self.bgImageView.image = image;
} else {
[self loadLocalSVGA];
}
}];
}
}
- (void)loadLocalSVGA {
self.bgSVGA.hidden = NO;
self.bgImageView.hidden = YES;
@kWeakify(self);
[self.parser parseWithNamed:@"game_floating_bg"
inBundle:[NSBundle mainBundle]
completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
self.bgSVGA.videoItem = videoItem;
} failureBlock:^(NSError * _Nonnull error) {
}];
}
- (void)setupNotification {
}
- (void)handleTapGo {
if (self.didTapGo) {
self.didTapGo(self.gameID.integerValue);
}
}
#pragma mark -
- (NetImageView *)bgImageView {
if (!_bgImageView) {
_bgImageView = [[NetImageView alloc] init];
_bgImageView.layer.cornerRadius = 2;
_bgImageView.layer.masksToBounds = YES;
}
return _bgImageView;
}
- (SVGAImageView *)bgSVGA {
if (!_bgSVGA) {
_bgSVGA = [[SVGAImageView alloc] init];
_bgSVGA.autoPlay = YES;
_bgSVGA.loops = -1;
}
return _bgSVGA;
}
- (NetImageConfig *)avatarConfig {
NetImageConfig * config = [[NetImageConfig alloc]init];
config.imageType = ImageTypeUserIcon;
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
return config;
}
- (NetImageView *)gameIcon {
if (!_gameIcon) {
_gameIcon = [[NetImageView alloc] initWithConfig:[self avatarConfig]];
_gameIcon.layer.cornerRadius = 2;
_gameIcon.layer.masksToBounds = YES;
}
return _gameIcon;
}
- (NetImageView *)avatarIcon {
if (!_avatarIcon) {
_avatarIcon = [[NetImageView alloc] initWithConfig:[self avatarConfig]];
_avatarIcon.layer.cornerRadius = 28/2;
_avatarIcon.layer.masksToBounds = YES;
}
return _avatarIcon;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_titleLabel.numberOfLines = 0;
_titleLabel.adjustsFontSizeToFitWidth = YES;
_titleLabel.minimumScaleFactor = 0.5;
}
return _titleLabel;
}
- (UIButton *)goButton {
if (!_goButton) {
_goButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_goButton setImage:kImage(@"game_banner_go")
forState:UIControlStateNormal];
[_goButton addTarget:self
action:@selector(handleTapGo)
forControlEvents:UIControlEventTouchUpInside];
}
return _goButton;
}
// 在主实现体内添加事件穿透逻辑
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
return nil;
}
CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
return self.goButton;
}
// 其他区域返回self允许触摸事件被处理包括手势识别器
return self;
}
@end