fix: 优化送礼的内存效率 |

TODO:调整 combo 时的金币变动效果
This commit is contained in:
edwinQQQ
2024-12-09 19:27:02 +08:00
parent 8ba4eaf2f5
commit 57735e37c4
11 changed files with 1020 additions and 468 deletions

View File

@@ -500,6 +500,8 @@
4C6E1F752CEAEC3C0073D0A3 /* ShoppingMallTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F742CEAEC3C0073D0A3 /* ShoppingMallTagView.m */; };
4C6E1F792CEB12780073D0A3 /* UIView+GradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F782CEB12780073D0A3 /* UIView+GradientLayer.m */; };
4C6E1F7C2CEB25B10073D0A3 /* ShoppingMallItemPreview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F7B2CEB25B10073D0A3 /* ShoppingMallItemPreview.m */; };
4C71C69F2D069D2B00ECCA24 /* GiftAnimationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71C69E2D069D2B00ECCA24 /* GiftAnimationHelper.m */; };
4C71C6A22D06DB3D00ECCA24 /* GiftAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71C6A12D06DB3D00ECCA24 /* GiftAnimationManager.m */; };
4C815A172CFEB758002A46A6 /* SuperBlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C815A162CFEB758002A46A6 /* SuperBlockViewController.m */; };
4CC6195A2CEC7770008C1EE8 /* MyDressingDataPresent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC619592CEC7770008C1EE8 /* MyDressingDataPresent.m */; };
4CC6195D2CEC996E008C1EE8 /* MyDressingDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC6195C2CEC996E008C1EE8 /* MyDressingDataModel.m */; };
@@ -2588,6 +2590,10 @@
4C6E1F782CEB12780073D0A3 /* UIView+GradientLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+GradientLayer.m"; sourceTree = "<group>"; };
4C6E1F7A2CEB25B10073D0A3 /* ShoppingMallItemPreview.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShoppingMallItemPreview.h; sourceTree = "<group>"; };
4C6E1F7B2CEB25B10073D0A3 /* ShoppingMallItemPreview.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShoppingMallItemPreview.m; sourceTree = "<group>"; };
4C71C69D2D069D2B00ECCA24 /* GiftAnimationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GiftAnimationHelper.h; sourceTree = "<group>"; };
4C71C69E2D069D2B00ECCA24 /* GiftAnimationHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GiftAnimationHelper.m; sourceTree = "<group>"; };
4C71C6A02D06DB3D00ECCA24 /* GiftAnimationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GiftAnimationManager.h; sourceTree = "<group>"; };
4C71C6A12D06DB3D00ECCA24 /* GiftAnimationManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GiftAnimationManager.m; sourceTree = "<group>"; };
4C815A152CFEB758002A46A6 /* SuperBlockViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuperBlockViewController.h; sourceTree = "<group>"; };
4C815A162CFEB758002A46A6 /* SuperBlockViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SuperBlockViewController.m; sourceTree = "<group>"; };
4CC619582CEC7770008C1EE8 /* MyDressingDataPresent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyDressingDataPresent.h; sourceTree = "<group>"; };
@@ -8271,6 +8277,10 @@
E8998D7F28597B0300C68558 /* XPRoomLuckyBigPrizeView.m */,
E838D99E275E1BF60079E0B5 /* XPRoomAnimationView.h */,
E838D99F275E1BF60079E0B5 /* XPRoomAnimationView.m */,
4C71C6A02D06DB3D00ECCA24 /* GiftAnimationManager.h */,
4C71C6A12D06DB3D00ECCA24 /* GiftAnimationManager.m */,
4C71C69D2D069D2B00ECCA24 /* GiftAnimationHelper.h */,
4C71C69E2D069D2B00ECCA24 /* GiftAnimationHelper.m */,
23E9EA782A8385CC00B792F2 /* XPTreasureFairyGiftView.h */,
23E9EA772A8385CB00B792F2 /* XPTreasureFairyGiftView.m */,
E8E21A9928B4BD92008F7C9D /* XPRoomGraffitiGiftAnimationView.h */,
@@ -12378,6 +12388,7 @@
238B37C52AC55A2C00BFC9D5 /* XPTreasureFairyMoreView.m in Sources */,
E811FFF72742367B00918544 /* XPGiftEmptyCollectionViewCell.m in Sources */,
189DD67E26E1FD8900AB55B1 /* UIImage+Utils.m in Sources */,
4C71C6A22D06DB3D00ECCA24 /* GiftAnimationManager.m in Sources */,
E82D5C73276AE94800858D6D /* CarModel.m in Sources */,
E85E7B0B2A4EB0D200B6D00A /* XPGuildSetNamePresenter.m in Sources */,
E87E62762A3F5907002F68C9 /* XPNewHomePlayTableViewCell.m in Sources */,
@@ -12758,6 +12769,7 @@
E81DCCD0282B63FD0039E5C5 /* XPMomentsRecommendViewController.m in Sources */,
9B7D804A2753783D003DAC0C /* SessionViewController.m in Sources */,
E85E7BA92A4EC99300B6D00A /* XPMineConfirmGiveDiamondView.m in Sources */,
4C71C69F2D069D2B00ECCA24 /* GiftAnimationHelper.m in Sources */,
54C9A1102C3D3E1700C6D970 /* XPMineGameMateOrderView.m in Sources */,
E85E7BA72A4EC99300B6D00A /* XPMineGiveDiamondPasswordView.m in Sources */,
54283CEE2CE48B97009729B5 /* ShoppingMallDataPresent.m in Sources */,

View File

@@ -21,8 +21,8 @@
#import "ThirdUserInfo.h"
#import "AccountModel.h"
#import "DESEncrypt.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
//#import <FBSDKCoreKit/FBSDKCoreKit.h>
//#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import "YuMi-swift.h"
#import "FeedBackConfigModel.h"
@@ -33,25 +33,25 @@
- (instancetype)init{
self = [super init];
if(self){
[[NSNotificationCenter defaultCenter] addObserverForName:FBSDKProfileDidChangeNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:
^(NSNotification *notification) {
if ([FBSDKProfile currentProfile]) {
//
[FBSDKProfile loadCurrentProfileWithCompletion:
^(FBSDKProfile *profile, NSError *error) {
if (profile) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
AccountInfoStorage *accountStorage = [AccountInfoStorage instance];
accountStorage.thirdUserInfo.userName = profile.name;
accountStorage.thirdUserInfo.avatarUrl = profile.imageURL.absoluteString;
});
}
}];
}
}];
// [[NSNotificationCenter defaultCenter] addObserverForName:FBSDKProfileDidChangeNotification
// object:nil
// queue:[NSOperationQueue mainQueue]
// usingBlock:
// ^(NSNotification *notification) {
// if ([FBSDKProfile currentProfile]) {
// //
// [FBSDKProfile loadCurrentProfileWithCompletion:
// ^(FBSDKProfile *profile, NSError *error) {
// if (profile) {
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// AccountInfoStorage *accountStorage = [AccountInfoStorage instance];
// accountStorage.thirdUserInfo.userName = profile.name;
// accountStorage.thirdUserInfo.avatarUrl = profile.imageURL.absoluteString;
// });
// }
// }];
// }
// }];
}
return self;
}
@@ -200,31 +200,31 @@
}];
}
-(void)thirdLoginByFBWithPresentingViewController:(UIViewController *)presentingViewController {
[FBSDKProfile enableUpdatesOnAccessTokenChange:YES];
[FBSDKAccessToken setCurrentAccessToken:nil];
FBSDKLoginManager *manager = [[FBSDKLoginManager alloc] init];
[manager logOut];
[XNDJTDDLoadingTool showOnlyView:kWindow];
@kWeakify(self);
[manager logInWithPermissions:@[@"public_profile"]
fromViewController:presentingViewController
handler:^(FBSDKLoginManagerLoginResult * _Nullable result, NSError * _Nullable error) {
@kStrongify(self);
if (error) {
[XNDJTDDLoadingTool hideOnlyView:kWindow];
[[self getView] showErrorToast:YMLocalizedString(@"LoginPresenter1")];
} else if (result.isCancelled) {
[XNDJTDDLoadingTool hideOnlyView:kWindow];
[[self getView] showErrorToast:YMLocalizedString(@"LoginPresenter0")];
} else {
ThirdUserInfo * userInfo = [[ThirdUserInfo alloc] init];
userInfo.openid = result.token.userID;
userInfo.access_token = result.token.tokenString;
userInfo.unionid = result.token.userID;
[AccountInfoStorage instance].thirdUserInfo = userInfo;
[self loginWithThirdPartWithType:ThirdLoginType_FB];
}
}];
// [FBSDKProfile enableUpdatesOnAccessTokenChange:YES];
// [FBSDKAccessToken setCurrentAccessToken:nil];
// FBSDKLoginManager *manager = [[FBSDKLoginManager alloc] init];
// [manager logOut];
// [XNDJTDDLoadingTool showOnlyView:kWindow];
// @kWeakify(self);
// [manager logInWithPermissions:@[@"public_profile"]
// fromViewController:presentingViewController
// handler:^(FBSDKLoginManagerLoginResult * _Nullable result, NSError * _Nullable error) {
// @kStrongify(self);
// if (error) {
// [XNDJTDDLoadingTool hideOnlyView:kWindow];
// [[self getView] showErrorToast:YMLocalizedString(@"LoginPresenter1")];
// } else if (result.isCancelled) {
// [XNDJTDDLoadingTool hideOnlyView:kWindow];
// [[self getView] showErrorToast:YMLocalizedString(@"LoginPresenter0")];
// } else {
// ThirdUserInfo * userInfo = [[ThirdUserInfo alloc] init];
// userInfo.openid = result.token.userID;
// userInfo.access_token = result.token.tokenString;
// userInfo.unionid = result.token.userID;
// [AccountInfoStorage instance].thirdUserInfo = userInfo;
// [self loginWithThirdPartWithType:ThirdLoginType_FB];
// }
// }];
}
-(void)thirdLoginByGoogleWithPresentingViewController:(UIViewController *)presentingViewController configuration:(GIDConfiguration *)configuration{
@kWeakify(self);

View File

@@ -0,0 +1,29 @@
//
// GiftAnimationManager.h
// YuMi
//
// Created by P on 2024/12/9.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface GiftAnimationHelper : NSObject
/**
* Begins a gift animation from a start point to an end point
* @param giftUrl URL of the gift image to display
* @param startPoint Starting position of the animation
* @param endPoint Ending position of the animation
* @param isGiftCombing Flag to determine if this is a combo animation
*/
- (void)beginGiftAnimation:(NSString *)giftUrl
startPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint
isGiftCombing:(BOOL)isGiftCombing
toTargetView:(UIView *)targetView;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,335 @@
//
// GiftAnimationManager.m
// YuMi
//
// Created by P on 2024/12/9.
//
#import "GiftAnimationHelper.h"
// Constants
static const CGFloat kGiftImageSize = 55.0f;
static const CGFloat kStandardAnimationDuration = 3.2f;
static const CGFloat kComboAnimationDuration = 1.0f;
static const CGFloat kCleanupDelay = 0.25f;
static const CGFloat kComboInitialScale = 0.4f;
static const CGFloat kComboFinalScale = 2.0f;
static const CGFloat kComboScaleDuration = 0.1f;
static const CGFloat kComboMoveDuration = 0.5f;
static const CGFloat kComboTotalDuration = 0.6f;
static const CGFloat kStandardScaleDuration = 0.8f;
static const CGFloat kStandardTotalDuration = 3.2f;
static const CGFloat kStandardSecondPhaseDelay = 0.8f;
static const CGFloat kStandardFinalPhaseDelay = 2.6f;
@interface GiftAnimationHelper ()
@property (nonatomic, strong) NSMutableSet<NetImageView *> *giftReuseArray;
@property (nonatomic, strong) NSMutableSet<NetImageView *> *giftVisibleArray;
@property (nonatomic, strong) UIView *lowLevelView;
@end
@implementation GiftAnimationHelper
- (instancetype)init {
if (self = [super init]) {
self.giftReuseArray = [NSMutableSet set];
self.giftVisibleArray = [NSMutableSet set];
}
return self;
}
- (void)beginGiftAnimation:(NSString *)giftUrl
startPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint
isGiftCombing:(BOOL)isGiftCombing
toTargetView:(UIView *)targetView {
// Input validation
if (!giftUrl.length || CGPointEqualToPoint(startPoint, endPoint)) {
NSLog(@"Invalid input parameters for gift animation");
return;
}
if (targetView == nil) {
return;
}
self.lowLevelView = targetView;
// Get or create gift image view
NetImageView *giftImageView = [self dequeueGiftImageView];
[self configureGiftImageView:giftImageView
withGiftUrl:giftUrl
startPoint:startPoint];
// Add to view hierarchy
[self.lowLevelView addSubview:giftImageView];
// Create and apply animation
CGFloat animationDuration = isGiftCombing ? kComboAnimationDuration : kStandardAnimationDuration;
CAAnimationGroup *animationGroup = isGiftCombing ?
[self createGiftComboAnimationStartPoint:startPoint endPoint:endPoint] :
[self createGiftAnimationStartPoint:startPoint endPoint:endPoint];
// Ensure correct starting position
giftImageView.layer.position = startPoint;
[giftImageView.layer addAnimation:animationGroup forKey:@"giftDisplayViewAnimation"];
// Schedule cleanup
[self performSelector:@selector(animationDidFinish:)
withObject:giftImageView
afterDelay:(animationDuration + kCleanupDelay)];
}
- (NetImageView *)dequeueGiftImageView {
NetImageView *giftImageView = [self.giftReuseArray anyObject];
if (giftImageView) {
[self.giftReuseArray removeObject:giftImageView];
} else {
giftImageView = [[NetImageView alloc] initWithFrame:CGRectMake(0, 0, kGiftImageSize, kGiftImageSize)];
[self.giftVisibleArray addObject:giftImageView];
}
return giftImageView;
}
- (void)configureGiftImageView:(NetImageView *)giftImageView
withGiftUrl:(NSString *)giftUrl
startPoint:(CGPoint)startPoint {
giftImageView.center = startPoint;
giftImageView.alpha = 1.0;
giftImageView.layer.anchorPoint = CGPointMake(0.5, 0.5);
giftImageView.imageUrl = giftUrl;
giftImageView.hidden = NO;
}
- (void)animationDidFinish:(NetImageView *)giftImageView {
[giftImageView removeFromSuperview];
giftImageView.hidden = YES;
[self.giftReuseArray addObject:giftImageView];
}
- (CAAnimationGroup *)createGiftComboAnimationStartPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint {
// Initial shrink animation
CAKeyframeAnimation *initialScale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
initialScale.duration = kComboScaleDuration;
initialScale.values = @[@1.0, @(kComboInitialScale)];
initialScale.repeatCount = 1;
initialScale.calculationMode = kCAAnimationCubic;
initialScale.removedOnCompletion = NO;
initialScale.fillMode = kCAFillModeForwards;
// Movement animation
CAKeyframeAnimation *movement = [CAKeyframeAnimation animationWithKeyPath:@"position"];
movement.duration = kComboMoveDuration;
movement.beginTime = kComboScaleDuration;
movement.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
movement.values = @[
[NSValue valueWithCGPoint:startPoint],
[NSValue valueWithCGPoint:endPoint]
];
movement.repeatCount = 1;
movement.removedOnCompletion = NO;
movement.fillMode = kCAFillModeForwards;
// Growth during movement animation
CAKeyframeAnimation *growthDuringMove = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
growthDuringMove.duration = kComboMoveDuration;
growthDuringMove.beginTime = kComboScaleDuration;
growthDuringMove.values = @[@(kComboInitialScale), @(kComboFinalScale)];
growthDuringMove.repeatCount = 1;
growthDuringMove.calculationMode = kCAAnimationCubic;
growthDuringMove.removedOnCompletion = NO;
growthDuringMove.fillMode = kCAFillModeForwards;
// Combine animations
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = kComboTotalDuration;
group.animations = @[initialScale, movement, growthDuringMove];
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
return group;
}
/**
* Creates a complex gift animation with multiple phases
* @param startPoint Initial position of the gift
* @param endPoint Final position of the gift
* @return CAAnimationGroup containing multiple scale and position animations
*/
- (CAAnimationGroup *)createGiftAnimationStartPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint {
CGPoint centerPoint = CGPointMake(KScreenWidth / 2, KScreenHeight / 2);
// Initial scale up animation
CAKeyframeAnimation *initialScale = [CAKeyframeAnimation animation];
initialScale.duration = kStandardScaleDuration;
initialScale.keyPath = @"transform.scale";
initialScale.values = @[@1.0, @1.5, @2.0, @1.5];
initialScale.repeatCount = 1;
initialScale.calculationMode = kCAAnimationCubic;
initialScale.removedOnCompletion = NO;
initialScale.fillMode = kCAFillModeForwards;
// Second phase scale animation
CAKeyframeAnimation *secondScale = [CAKeyframeAnimation animation];
secondScale.duration = kStandardScaleDuration;
secondScale.beginTime = kStandardSecondPhaseDelay;
secondScale.keyPath = @"transform.scale";
secondScale.values = @[@1.5, @2.0, @2.5, @3.0];
secondScale.repeatCount = 1;
secondScale.calculationMode = kCAAnimationCubic;
secondScale.removedOnCompletion = NO;
secondScale.fillMode = kCAFillModeForwards;
// Move to center animation
CAKeyframeAnimation *moveToCenter = [CAKeyframeAnimation animation];
moveToCenter.duration = kStandardScaleDuration;
moveToCenter.beginTime = kStandardSecondPhaseDelay;
moveToCenter.keyPath = @"position";
moveToCenter.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
moveToCenter.values = @[
[NSValue valueWithCGPoint:startPoint],
[NSValue valueWithCGPoint:centerPoint]
];
moveToCenter.repeatCount = 1;
moveToCenter.removedOnCompletion = NO;
moveToCenter.fillMode = kCAFillModeForwards;
// Final scale down animation
CAKeyframeAnimation *finalScale = [CAKeyframeAnimation animation];
finalScale.duration = kStandardScaleDuration;
finalScale.beginTime = kStandardFinalPhaseDelay;
finalScale.keyPath = @"transform.scale";
finalScale.values = @[@3.0, @2.5, @2.0, @1.5, @1.0];
finalScale.repeatCount = 1;
// Move to final position animation
CAKeyframeAnimation *moveToEnd = [CAKeyframeAnimation animation];
moveToEnd.duration = kStandardScaleDuration;
moveToEnd.beginTime = kStandardFinalPhaseDelay;
moveToEnd.keyPath = @"position";
moveToEnd.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
moveToEnd.values = @[
[NSValue valueWithCGPoint:centerPoint],
[NSValue valueWithCGPoint:endPoint]
];
moveToEnd.repeatCount = 1;
// Combine all animations
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = kStandardTotalDuration;
group.animations = @[initialScale, secondScale, moveToCenter, finalScale, moveToEnd];
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
return group;
}
//- (CAAnimationGroup *)createGiftComboAnimationStartPoint:(CGPoint)startPoint
// endPoint:(CGPoint)endPoint {
// // 1: 0.4
// CAKeyframeAnimation *scaleAnimation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
// scaleAnimation1.duration = 0.1;
// scaleAnimation1.values = @[@1.0, @0.4];
// scaleAnimation1.repeatCount = 1;
// scaleAnimation1.calculationMode = kCAAnimationCubic;
// scaleAnimation1.removedOnCompletion = NO;
// scaleAnimation1.fillMode = kCAFillModeForwards;
//
// // : 0.5
// CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
// positionAnimation.duration = 0.5;
// positionAnimation.beginTime = 0.1; //
// positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// positionAnimation.values = @[[NSValue valueWithCGPoint:startPoint], [NSValue valueWithCGPoint:endPoint]];
// positionAnimation.repeatCount = 1;
// positionAnimation.removedOnCompletion = NO;
// positionAnimation.fillMode = kCAFillModeForwards;
//
// // 2: 1.2
// CAKeyframeAnimation *scaleAnimation2 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
// scaleAnimation2.duration = 0.5;
// scaleAnimation2.beginTime = 0.1; //
// scaleAnimation2.values = @[@0.4, @2];
// scaleAnimation2.repeatCount = 1;
// scaleAnimation2.calculationMode = kCAAnimationCubic;
// scaleAnimation2.removedOnCompletion = NO;
// scaleAnimation2.fillMode = kCAFillModeForwards;
//
// //
// CAAnimationGroup *group = [CAAnimationGroup animation];
// group.duration = 0.6; // 0.1 () + 0.5 ()
// group.animations = @[scaleAnimation1, positionAnimation, scaleAnimation2];
// group.repeatCount = 1;
// group.removedOnCompletion = NO;
// group.fillMode = kCAFillModeForwards;
//
// return group;
//}
//
/////
///// @param startPoint
///// @param endPoint
//- (CAAnimationGroup *)createGiftAnimationStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
// CGPoint centerPoint = CGPointMake(KScreenWidth / 2, KScreenHeight / 2);
// CAKeyframeAnimation *animation0 = [CAKeyframeAnimation animation];
// animation0.duration = 0.8;
// animation0.keyPath = @"transform.scale";
// animation0.values = @[@1.0,@1.5,@2.0,@1.5];
// animation0.repeatCount = 1;
// animation0.calculationMode = kCAAnimationCubic;
// animation0.removedOnCompletion = NO;
// animation0.fillMode = kCAFillModeForwards;
//
// CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
// animation1.duration = 0.8;
// animation1.beginTime = 0.8;
// animation1.keyPath = @"transform.scale";
// animation1.values = @[@1.5,@2.0,@2.5,@3.0];
// animation1.repeatCount = 1;
// animation1.calculationMode = kCAAnimationCubic;
// animation1.removedOnCompletion = NO;
// animation1.fillMode = kCAFillModeForwards;
//
// CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animation];
// animation2.duration = 0.8;
// animation2.beginTime = 0.8;
// animation2.keyPath = @"position";
// animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];;
// animation2.values = @[[NSValue valueWithCGPoint:startPoint],[NSValue valueWithCGPoint:CGPointMake(centerPoint.x ,centerPoint.y)]];
// animation2.repeatCount = 1;
// animation2.removedOnCompletion = NO;
// animation2.fillMode = kCAFillModeForwards;
//
// CAKeyframeAnimation *animation3 = [CAKeyframeAnimation animation];
// animation3.duration = 0.8;
// animation3.beginTime = 2.6;//0.8+0.8+1
// animation3.keyPath = @"transform.scale";
// animation3.values = @[@3,@2.5,@2,@1.5,@1];
// animation3.repeatCount = 1;
//
// CAKeyframeAnimation *animation4 = [CAKeyframeAnimation animation];
// animation4.duration = 0.8;
// animation4.beginTime = 2.6;
// animation4.keyPath = @"position";
// animation4.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
// animation4.values = @[[NSValue valueWithCGPoint:CGPointMake(centerPoint.x ,centerPoint.y)],[NSValue valueWithCGPoint:endPoint]];
// animation4.repeatCount = 1;
//
// CAAnimationGroup *group = [CAAnimationGroup animation];
// group.duration = 3.2;
// group.animations = @[animation0,animation1,animation2, animation3,animation4];
// group.repeatCount = 1;
// group.removedOnCompletion = NO;
// group.fillMode = kCAFillModeForwards;
//
// return group;
//}
@end

View File

@@ -0,0 +1,57 @@
//
// GiftAnimationManager.h
// YuMi
//
// Created by P on 2024/12/9.
//
#import <Foundation/Foundation.h>
@class GiftReceiveInfoModel;
NS_ASSUME_NONNULL_BEGIN
@protocol GiftAnimationDelegate <NSObject>
/**
* Returns the animation point for a given user ID in the stage view
* @param uid The user ID to get the animation point for
* @return CGPoint The point in the view's coordinate system where the animation should occur
*/
- (CGPoint)animationPointAtStageViewByUid:(NSString *)uid;
@optional
/**
* Called when a gift animation starts
* @param giftInfo The gift information model
*/
//- (void)didStartGiftAnimation:(GiftInfoModel *)giftInfo;
/**
* Called when a gift animation completes
* @param giftInfo The gift information model
*/
//- (void)didCompleteGiftAnimation:(GiftInfoModel *)giftInfo;
/**
* Called when the gift queue becomes empty
*/
- (void)didEmptyGiftQueue;
@end
@interface GiftAnimationManager : NSObject
@property (nonatomic, weak) id<GiftAnimationDelegate> delegate;
@property (nonatomic, strong) UIView *containerView;
// Configurable properties
@property (nonatomic, assign) NSTimeInterval animationInterval;
@property (nonatomic, assign) NSTimeInterval comboAnimationDelay;
@property (nonatomic, assign) NSTimeInterval standardAnimationDelay;
- (instancetype)initWithContainerView:(UIView *)containerView;
- (void)enqueueGift:(GiftReceiveInfoModel *)giftInfo;
- (void)startGiftQueue;
- (void)stopGiftQueue;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,195 @@
//
// GiftAnimationManager.m
// YuMi
//
// Created by P on 2024/12/9.
//
#import "GiftAnimationManager.h"
#import "GiftComboManager.h"
#import "GiftAnimationHelper.h"
#import "GiftReceiveInfoModel.h"
@interface GiftAnimationManager ()
@property (nonatomic, strong) dispatch_source_t giftTimer;
@property (nonatomic, strong) NSMutableArray<GiftReceiveInfoModel *> *giftQueue;
@property (nonatomic, strong) GiftAnimationHelper *animationHelper;
@end
@implementation GiftAnimationManager
- (instancetype)initWithContainerView:(UIView *)containerView {
self = [super init];
if (self) {
_containerView = containerView;
_giftQueue = [NSMutableArray array];
_animationHelper = [[GiftAnimationHelper alloc] init];
_animationInterval = 0.25;
_comboAnimationDelay = 0.25;
_standardAnimationDelay = 0.5;
}
return self;
}
- (void)startGiftQueue {
if (self.giftTimer) return;
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timer,
DISPATCH_TIME_NOW,
self.animationInterval * NSEC_PER_SEC,
0);
@kWeakify(self);
dispatch_source_set_event_handler(timer, ^{
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
[self processNextGift];
});
});
dispatch_resume(timer);
self.giftTimer = timer;
}
- (void)processNextGift {
if (self.giftQueue.count == 0) {
[self stopGiftQueue];
return;
}
GiftReceiveInfoModel *giftInfo = self.giftQueue.firstObject;
[self distributeGiftAnimation:giftInfo];
[self.giftQueue removeObjectAtIndex:0];
}
- (void)distributeGiftAnimation:(GiftReceiveInfoModel *)giftInfo {
NSArray<NSString *> *targetUids = [self resolveTargetUids:giftInfo];
CGPoint startPoint = [self calculateAnimationPoint:giftInfo.uid isEndPoint:NO];
BOOL isComboAnimation = [self shouldUseComboAnimationForSender:giftInfo.uid];
NSTimeInterval delay = isComboAnimation ? self.comboAnimationDelay : self.standardAnimationDelay;
for (NSString *targetUid in targetUids) {
CGPoint endPoint = [self calculateAnimationPoint:targetUid isEndPoint:YES];
[self scheduleAnimationWithDelay:delay
giftInfo:giftInfo.gift
startPoint:startPoint
endPoint:endPoint
isComboAnimation:isComboAnimation];
}
}
- (NSArray<NSString *> *)resolveTargetUids:(GiftReceiveInfoModel *)giftInfo {
if (giftInfo.isLuckyBagGift) {
return @[giftInfo.targetUid];
}
if (giftInfo.targetUids.count > 0) {
return [giftInfo.targetUids valueForKey:@"stringValue"];
}
if (giftInfo.targetUsers) {
NSArray *uidDatas = [self ensureArrayContainsOnlyStrings:[giftInfo.targetUsers valueForKeyPath:@"uid"]];
return uidDatas;//[giftInfo.targetUsers valueForKeyPath:@"uid"];
}
return [NSString isEmpty:giftInfo.targetUid] ? @[] : @[giftInfo.targetUid];
}
- (NSArray<NSString *> *)ensureArrayContainsOnlyStrings:(NSArray *)inputArray {
//
NSMutableArray<NSString *> *resultArray = [NSMutableArray array];
for (id item in inputArray) {
if ([item isKindOfClass:[NSString class]]) {
// NSString
[resultArray addObject:item];
} else if ([item isKindOfClass:[NSNumber class]]) {
// NSNumber NSString
[resultArray addObject:[item stringValue]];
} else {
// NSString NSNumber
NSLog(@"Warning: Unsupported item type: %@", [item class]);
}
}
return [resultArray copy]; //
}
- (CGPoint)calculateAnimationPoint:(NSString *)uid isEndPoint:(BOOL)isEndPoint {
CGPoint point = [self.delegate animationPointAtStageViewByUid:uid];
if (point.x <= 0 || point.y <= 0) {
point = [self fallbackPointForEndPoint:isEndPoint];
}
if ([self shouldUseComboAnimationForSender:uid] && !isEndPoint) {
point = [self comboAnimationStartPoint];
}
return point;
}
- (void)scheduleAnimationWithDelay:(NSTimeInterval)delay
giftInfo:(GiftInfoModel *)giftInfo
startPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint
isComboAnimation:(BOOL)isComboAnimation {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
[self.animationHelper beginGiftAnimation:giftInfo.giftUrl
startPoint:startPoint
endPoint:endPoint
isGiftCombing:isComboAnimation
toTargetView:self.containerView];
});
}
- (void)stopGiftQueue {
if (self.giftTimer) {
dispatch_source_cancel(self.giftTimer);
self.giftTimer = nil;
}
}
- (void)enqueueGift:(GiftReceiveInfoModel *)giftInfo {
[self.giftQueue addObject:giftInfo];
[self startGiftQueue];
}
// Helper methods
- (BOOL)shouldUseComboAnimationForSender:(NSString *)uid {
return [[GiftComboManager sharedManager] isGiftCombing] &&
[uid isEqualToString:[AccountInfoStorage instance].getUid];
}
- (CGPoint)fallbackPointForEndPoint:(BOOL)isEndPoint {
CGFloat x = [UIScreen mainScreen].bounds.size.width / 2;
if (isEndPoint) {
x += 30;
}
return CGPointMake(x, 44 + kSafeAreaTopHeight);
}
- (CGPoint)comboAnimationStartPoint {
if (isMSRTL()) {
return CGPointMake(kGetScaleWidth(86),
[UIScreen mainScreen].bounds.size.height - kSafeAreaTopHeight - kGetScaleWidth(140));
}
CGFloat x = KScreenWidth <= 375 ?
[UIScreen mainScreen].bounds.size.width - kGetScaleWidth(86) :
[UIScreen mainScreen].bounds.size.width - kGetScaleWidth(120);
return CGPointMake(x,
[UIScreen mainScreen].bounds.size.height - kSafeAreaBottomHeight - kGetScaleWidth(140));
}
@end

View File

@@ -13,36 +13,40 @@
#import "XPRoomViewController.h"
#import "XCCurrentVCStackManager.h"
// Constants
static const CGFloat kBannerWidth = 346.5f;
static const CGFloat kBannerHeight = 82.5f;
static const CGFloat kBannerTopMargin = 80.0f;
static const CGFloat kAvatarSize = 43.0f;
static const CGFloat kAnimationDuration = 0.25f;
static const CGFloat kDisplayDuration = 2.5f;
static const CGFloat kRoomTransitionDelay = 2.0f;
@interface LuckyGiftWinningBannerViewModel : PIBaseModel
// model
@property (nonatomic, copy) NSString *times;
@property (nonatomic, copy) NSString *avatar;
@property (nonatomic, copy) NSString *coins;
@property (nonatomic, copy) NSDictionary *giftNameMap;
@property (nonatomic, copy) NSString *roomUid;
- (NSString *)giftName;
@property (nonatomic, copy, readonly) NSString *times;
@property (nonatomic, copy, readonly) NSString *avatar;
@property (nonatomic, copy, readonly) NSString *coins;
@property (nonatomic, copy, readonly) NSDictionary *giftNameMap;
@property (nonatomic, copy, readonly) NSString *roomUid;
@property (nonatomic, copy, readonly) NSString *giftName;
@end
@implementation LuckyGiftWinningBannerViewModel
+ (NSDictionary *)replacedKeyFromPropertyName {
return @{
@"avatar":@"sender.avatar"
};
return @{@"avatar": @"sender.avatar"};
}
- (NSString *)giftName {
if ([self.giftNameMap.allKeys containsObject:@"ar"] && isMSRTL()) {
if (isMSRTL() && [self.giftNameMap[@"ar"] length]) {
return self.giftNameMap[@"ar"];
} else if ([self.giftNameMap.allKeys containsObject:@"zh"] && isMSZH()) {
return self.giftNameMap[@"zh"];
} else {
return self.giftNameMap[@"en"];
}
if (isMSZH() && [self.giftNameMap[@"zh"] length]) {
return self.giftNameMap[@"zh"];
}
return self.giftNameMap[@"en"] ?: @"";
}
@end
@@ -52,13 +56,11 @@
@property (nonatomic, strong) LuckyGiftWinningBannerViewModel *model;
@property (nonatomic, strong) UIImageView *backgroundImageView;
@property (nonatomic, strong) UIImageView *ballImageView;
@property (nonatomic, strong) NetImageView *avatarImage;
@property (nonatomic, strong) NetImageView *avatarImageView;
@property (nonatomic, strong) UILabel *giftNameLabel;
@property (nonatomic, strong) UILabel *timesLabel;
@property (nonatomic, strong) UILabel *coinsLabel;
@property (nonatomic, assign) NSInteger currentRoomUid;
@property (nonatomic, copy) void(^completeDisplay)(void);
@property (nonatomic, copy) void(^exitCurrentRoom)(void);
@@ -71,39 +73,66 @@
with:(AttachmentModel *)attachment
complete:(void(^)(void))complete
exitCurrentRoom:(void(^)(void))exit {
#if DEBUG
NSParameterAssert(superView);
NSParameterAssert(attachment);
#else
if (!superView || !attachment) {
if (complete) {
complete();
}
return;
}
#endif
LuckyGiftWinningBannerViewModel *model = [LuckyGiftWinningBannerViewModel modelWithDictionary:attachment.data];
CGFloat width = kGetScaleWidth(346.5);
CGFloat height = kGetScaleWidth(82.5);
LuckyGiftWinningBannerView *bannerView = [[LuckyGiftWinningBannerView alloc] initWithFrame:CGRectMake(KScreenWidth, 80, width, height)];
CGFloat width = kGetScaleWidth(kBannerWidth);
CGFloat height = kGetScaleWidth(kBannerHeight);
CGRect frame = CGRectMake(KScreenWidth, kBannerTopMargin, width, height);
LuckyGiftWinningBannerView *bannerView = [[LuckyGiftWinningBannerView alloc] initWithFrame:frame];
bannerView.model = model;
bannerView.completeDisplay = complete;
bannerView.exitCurrentRoom = exit;
bannerView.currentRoomUid = roomUid;
[superView addSubview:bannerView];
@kWeakify(bannerView);
[UIView animateWithDuration:0.25 animations:^{
bannerView.center = CGPointMake(superView.center.x, height/2 + 80);
[bannerView animateDisplay];
}
- (void)animateDisplay {
@kWeakify(self);
[UIView animateWithDuration:kAnimationDuration animations:^{
@kStrongify(self);
self.center = CGPointMake(self.superview.center.x, self.frame.size.height/2 + kBannerTopMargin);
} completion:^(BOOL finished) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
bannerView.frame = CGRectMake(-KScreenWidth, 80, width, height);
} completion:^(BOOL finished) {
@kStrongify(bannerView);
[bannerView removeFromSuperview];
if (bannerView.completeDisplay) {
bannerView.completeDisplay();
}
}];
@kStrongify(self);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDisplayDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self animateDisappear];
});
}];
}
- (void)animateDisappear {
@kWeakify(self);
[UIView animateWithDuration:kAnimationDuration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
@kStrongify(self);
self.frame = CGRectMake(-KScreenWidth, kBannerTopMargin, self.frame.size.width, self.frame.size.height);
} completion:^(BOOL finished) {
@kStrongify(self);
[self removeFromSuperview];
if (self.completeDisplay) {
self.completeDisplay();
}
}];
}
- (void)setModel:(LuckyGiftWinningBannerViewModel *)model {
_model = model;
self.avatarImage.imageUrl = model.avatar;
self.avatarImageView.imageUrl = model.avatar;
self.giftNameLabel.text = [model giftName];
self.timesLabel.text = model.times;
self.coinsLabel.text = [NSString formatNumberToKOrM:model.coins];
@@ -127,13 +156,13 @@ exitCurrentRoom:(void(^)(void))exit {
return;
}
__block NSString *targetRoomUid = self.model.roomUid;
@kWeakify(self);
[TTPopup alertWithMessage:YMLocalizedString(@"Combo_10") confirmHandler:^{
@kStrongify(self);
if (self.exitCurrentRoom) {
self.exitCurrentRoom();
}
NSString *targetRoomUid = self.model.roomUid;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:targetRoomUid
viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
@@ -153,8 +182,8 @@ exitCurrentRoom:(void(^)(void))exit {
make.width.mas_equalTo(self.ballImageView.mas_height);
}];
[self addSubview:self.avatarImage];
[self.avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
[self addSubview:self.avatarImageView];
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(kGetScaleWidth(8));
make.top.mas_equalTo(kGetScaleWidth(24));
make.width.height.mas_equalTo(kGetScaleWidth(43));
@@ -163,8 +192,8 @@ exitCurrentRoom:(void(^)(void))exit {
UILabel *titleLabel_1 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_0") font:kFontSemibold(14) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_1];
[titleLabel_1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.avatarImage).offset(2);
make.leading.mas_equalTo(self.avatarImage.mas_trailing).offset(10);
make.top.mas_equalTo(self.avatarImageView).offset(2);
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(10);
}];
[self addSubview:self.giftNameLabel];
@@ -176,8 +205,8 @@ exitCurrentRoom:(void(^)(void))exit {
UILabel *titleLabel_2 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_4") font:kFontSemibold(14) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_2];
[titleLabel_2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.avatarImage.mas_bottom).offset(-2);
make.leading.mas_equalTo(self.avatarImage.mas_trailing).offset(10);
make.bottom.mas_equalTo(self.avatarImageView.mas_bottom).offset(-2);
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(10);
}];
[self addSubview:self.timesLabel];
@@ -226,19 +255,17 @@ exitCurrentRoom:(void(^)(void))exit {
return _ballImageView;
}
- (NetImageView *)avatarImage {
if (!_avatarImage) {
- (NetImageView *)avatarImageView {
if (!_avatarImageView) {
NetImageConfig * config = [[NetImageConfig alloc]init];
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
config.imageType = ImageTypeCornerAvatar;
_avatarImage = [[NetImageView alloc] initWithConfig:config];
_avatarImage.backgroundColor = [UIColor clearColor];
_avatarImage.contentMode = UIViewContentModeScaleAspectFill;
_avatarImage.layer.cornerRadius = kGetScaleWidth(43/2);
_avatarImage.layer.masksToBounds = YES;
_avatarImage.clipsToBounds = YES;
_avatarImageView = [[NetImageView alloc] initWithConfig:config];
_avatarImageView.backgroundColor = [UIColor clearColor];
_avatarImageView.contentMode = UIViewContentModeScaleAspectFill;
[_avatarImageView setCornerRadius:kGetScaleWidth(43/2)];
}
return _avatarImage;
return _avatarImageView;
}
- (UILabel *)giftNameLabel {

View File

@@ -115,14 +115,6 @@
[stackView addArrangedSubview:self.coinIcon];
[stackView addArrangedSubview:self.winPriceLabel];
[self.coinIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(21, 21));
}];
[self.winPriceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(35);
}];
UIStackView *stackView_2 = [[UIStackView alloc] init];
stackView_2.spacing = 4;
[self addSubview:stackView_2];
@@ -149,10 +141,6 @@
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning" object:model.coins];
}
- (void)display {
}
#pragma mark -
- (UIImageView *)coinIcon {
if (!_coinIcon) {

View File

@@ -79,6 +79,9 @@
#import "GameUniversalBannerView.h"
#import "RoomHighValueGiftBannerAnimation.h"
#import "GiftAnimationHelper.h"
#import "GiftAnimationManager.h"
@interface XPRoomAnimationView ()<
SVGAPlayerDelegate,
NIMBroadcastManagerDelegate,
@@ -90,7 +93,9 @@ XPRoomStarKitchenBannerViewDelegate,
PAGViewListener,
XPRoomAnchorRankBannerViewDelegate,
PIRoomGiftBroadcastWindowDelegate,
PIUniversalBannerViewDelegate>
PIUniversalBannerViewDelegate,
GiftAnimationDelegate>
///
///
@property (nonatomic,strong) XPRoomAnimationHitView * lowLevelView;
@@ -116,24 +121,17 @@ PIUniversalBannerViewDelegate>
///
@property (nonatomic,weak) id<RoomHostDelegate>delegate;
///
@property (strong,nonatomic)NSMutableSet * bannerDequePool;
///
@property (strong,nonatomic)NSMutableSet * bannerVisiablePool;
/// 6s
@property (nonatomic,strong)dispatch_source_t giftEffectTimer;
#pragma mark -
///
@property (nonatomic,strong) NSMutableArray<GiftReceiveInfoModel *> *giftQueue;
///
@property (nonatomic ,strong)dispatch_source_t giftTimer;
///
@property (nonatomic,strong) NSMutableSet<NetImageView *> * giftReuseArray;
///
@property (nonatomic,strong) NSMutableSet<NetImageView *> * giftVisibleArray;
//@property (nonatomic,strong) NSMutableArray<GiftReceiveInfoModel *> *giftQueue;
/////
//@property (nonatomic ,strong)dispatch_source_t giftTimer;
@property(nonatomic, strong) GiftAnimationHelper *giftAnimationHelper;
@property(nonatomic, strong) GiftAnimationManager *giftAnimationManager;
///
@property (nonatomic,assign) BOOL isLargeGiftAnimating;
#pragma mark -
@@ -205,10 +203,10 @@ PIUniversalBannerViewDelegate>
self.giftEffectTimer = nil;
}
if(self.giftTimer != nil){
dispatch_source_cancel(self.giftTimer);
self.giftTimer = nil;
}
// if(self.giftTimer != nil){
// dispatch_source_cancel(self.giftTimer);
// self.giftTimer = nil;
// }
[self.giftPagView removeListener:self];
}
- (instancetype)initWithDelegate:(id<RoomHostDelegate>)delegate {
@@ -216,9 +214,14 @@ PIUniversalBannerViewDelegate>
if (self) {
[[NIMSDK sharedSDK].broadcastManager addDelegate:self];
self.delegate = delegate;
[self initSubViews];
[self initSubViewConstraints];
self.giftAnimationHelper = [[GiftAnimationHelper alloc] init];
self.giftAnimationManager = [[GiftAnimationManager alloc] initWithContainerView:self.lowLevelView];
self.giftAnimationManager.delegate = self;
_roomEffectModelsQueueV2 = [NSMutableArray array];
_GiftDynamicEffectListPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) xpSafeObjectAtIndex:0] stringByAppendingPathComponent:@"GiftDynamicEffectList"];
@@ -336,7 +339,11 @@ PIUniversalBannerViewDelegate>
receiveInfo.isBatch = (attachment.second == Custom_Message_Sub_AllBatchSend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend);
receiveInfo.isComboBatch = attachment.second == Custom_Message_Sub_AllMicroSend;
[self receiveGiftHandleSendGiftAnimation:attachment];
if (receiveInfo.gift.notifyFull && attachment.second == Custom_Message_Sub_Gift_Send) {
// return;
} else {
[self receiveGiftHandleSendGiftAnimation:attachment];
}
if (receiveInfo.isLuckyBagGift) {
if (!self.delegate.getRoomInfo.hasAnimationEffect) {return;}
@@ -1662,10 +1669,11 @@ PIUniversalBannerViewDelegate>
/// 使
receiveInfo.gift = giftInfo;
receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend);
[self.giftQueue addObject:receiveInfo];
if (self.giftTimer == nil && self.giftQueue > 0) {
[self startGiftQueueTimer];
}
[self.giftAnimationManager enqueueGift:receiveInfo];
// [self.giftQueue addObject:receiveInfo];
// if (self.giftTimer == nil && self.giftQueue > 0) {
// [self startGiftQueueTimer];
// }
}
#pragma mark -
@@ -1693,260 +1701,38 @@ PIUniversalBannerViewDelegate>
/// 使
receiveInfo.gift = giftInfo;
receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend);
[self.giftQueue addObject:receiveInfo];
if (self.giftTimer == nil && self.giftQueue > 0) {
[self startGiftQueueTimer];
}
[self.giftAnimationManager enqueueGift:receiveInfo];
// [self.giftQueue addObject:receiveInfo];
// if (self.giftTimer == nil && self.giftQueue > 0) {
// [self startGiftQueueTimer];
// }
}
//
- (void)startGiftQueueTimer {
NSTimeInterval period = 0.5; //
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, period * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (self.giftQueue.count) {
GiftReceiveInfoModel * receiveInfo = self.giftQueue.firstObject;
[self handoutGiftDistributeAnimation:receiveInfo];
[self.giftQueue removeObject:receiveInfo];
}else {
dispatch_source_cancel(_timer);
self.giftTimer = nil;
}
});
});
dispatch_resume(_timer);
self.giftTimer = _timer;
}
//- (void)startGiftQueueTimer {
// static NSTimeInterval period = 0.5; //
// dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
// dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, period * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
// dispatch_source_set_event_handler(_timer, ^{
// dispatch_async(dispatch_get_main_queue(), ^{
// if (self.giftQueue.count) {
// GiftReceiveInfoModel * receiveInfo = self.giftQueue.firstObject;
//// [self handoutGiftDistributeAnimation:receiveInfo];
// [self.giftAnimationManager enqueueGift:receiveInfo];
// [self.giftQueue removeObject:receiveInfo];
// }else {
// dispatch_source_cancel(_timer);
// self.giftTimer = nil;
// }
// });
// });
// dispatch_resume(_timer);
// self.giftTimer = _timer;
//}
///
- (void)handoutGiftDistributeAnimation:(GiftReceiveInfoModel *)receiveInfo {
GiftInfoModel * giftInfo = receiveInfo.gift;
NSString * sendUid = receiveInfo.uid;
CGPoint starPoint = [self getGiftAnimationPoint:sendUid isEnd:NO];
CGPoint endPoint;
NSArray * targetUids;
if (receiveInfo.isLuckyBagGift) {
targetUids = @[receiveInfo.targetUid];
} else {
targetUids = receiveInfo.targetUids;
if (targetUids.count <= 0) {
if (receiveInfo.targetUsers) {
targetUids = [receiveInfo.targetUsers valueForKeyPath:@"uid"];
}
if (targetUids.count <=0) {
targetUids = [NSString isEmpty:receiveInfo.targetUid] ? @[] : @[receiveInfo.targetUid];
}
}
}
#if DEBUG
for (NSInteger i=0;i<15;i++) {
endPoint = [self.delegate animationPointAtStageViewByIndex:i];
BOOL isCombing = [[GiftComboManager sharedManager] isGiftCombing] && [sendUid isEqualToString:[AccountInfoStorage instance].getUid];
CGFloat time = isCombing ? 0.25 : 0.5;
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, time * NSEC_PER_SEC);
dispatch_after(timer, dispatch_get_main_queue(), ^{
[self beginGiftAnimation:giftInfo.giftUrl
startPoint:starPoint
endPoint:endPoint
isGiftCombing:isCombing];
});
}
#else
for (NSString *targetUid in targetUids) {
NSString * userId = targetUid;
if ([userId isKindOfClass:[NSNumber class]]) {
userId = ((NSNumber *)userId).stringValue;
}
endPoint = [self getGiftAnimationPoint:userId isEnd:YES];
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC);
BOOL isCombing = [[GiftComboManager sharedManager] isGiftCombing] && [sendUid isEqualToString:[AccountInfoStorage instance].getUid];
if (isCombing) {
timer = dispatch_time(DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC);
}
dispatch_after(timer, dispatch_get_main_queue(), ^{
[self beginGiftAnimation:giftInfo.giftUrl
startPoint:starPoint
endPoint:endPoint
isGiftCombing:isCombing];
});
}
#endif
}
///
- (CGPoint)getGiftAnimationPoint:(NSString *)uid isEnd:(BOOL)isEnd{
CGPoint point = [self.delegate animationPointAtStageViewByUid:uid];
//
if (point.x <= 0 || point.y <= 0) {
if (isEnd) {
point = CGPointMake([UIScreen mainScreen].bounds.size.width /2 + 30, 44 + kSafeAreaTopHeight);
} else {
point = CGPointMake([UIScreen mainScreen].bounds.size.width / 2, 44 + kSafeAreaTopHeight);
}
}
if ([[GiftComboManager sharedManager] isGiftCombing] &&
[uid isEqualToString:[AccountInfoStorage instance].getUid] &&
isEnd == false) {
if (isMSRTL()) {
point = CGPointMake(kGetScaleWidth(86), [UIScreen mainScreen].bounds.size.height - kSafeAreaTopHeight - kGetScaleWidth(140));
} else {
if (KScreenWidth <= 375) {
point = CGPointMake(kGetScaleWidth([UIScreen mainScreen].bounds.size.width - kGetScaleWidth(86)), [UIScreen mainScreen].bounds.size.height - kSafeAreaBottomHeight - kGetScaleWidth(140));
} else {
point = CGPointMake(kGetScaleWidth([UIScreen mainScreen].bounds.size.width - kGetScaleWidth(150)), [UIScreen mainScreen].bounds.size.height - kSafeAreaBottomHeight - kGetScaleWidth(140));
}
}
}
return point;
}
- (void)beginGiftAnimation:(NSString *)giftUrl
startPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint
isGiftCombing:(BOOL)isGiftCombing {
NetImageView * giftImageView = [self.giftReuseArray anyObject];
if (giftImageView == nil) {
giftImageView = [[NetImageView alloc]initWithFrame:CGRectMake(0, 0 , 55, 55)];
giftImageView.center = startPoint;
giftImageView.alpha = 1;
giftImageView.layer.anchorPoint = CGPointMake(0.5, 0.5);
giftImageView.imageUrl = giftUrl;
[self.giftVisibleArray addObject:giftImageView];
}else {
[self.giftReuseArray removeObject:giftImageView];
}
giftImageView.hidden = NO;
giftImageView.imageUrl = giftUrl;
[self.lowLevelView addSubview:giftImageView];
CGFloat delay = 3.2;
CAAnimationGroup *group = [self createGiftAnimationStartPoint:startPoint endPoint:endPoint];
if (isGiftCombing) {
delay = 1.0;
group = [self createGiftComboAnimationStartPoint:startPoint endPoint:endPoint];
}
// startPoint
giftImageView.layer.position = startPoint;
[giftImageView.layer addAnimation:group forKey:@"giftDisplayViewAnimation"];
[self performSelector:@selector(aniationDidFinish:) withObject:giftImageView afterDelay:(delay+0.25)];
}
- (CAAnimationGroup *)createGiftComboAnimationStartPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint {
// 1: 0.4
CAKeyframeAnimation *scaleAnimation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation1.duration = 0.1;
scaleAnimation1.values = @[@1.0, @0.4];
scaleAnimation1.repeatCount = 1;
scaleAnimation1.calculationMode = kCAAnimationCubic;
scaleAnimation1.removedOnCompletion = NO;
scaleAnimation1.fillMode = kCAFillModeForwards;
// : 0.5
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
positionAnimation.duration = 0.5;
positionAnimation.beginTime = 0.1; //
positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
positionAnimation.values = @[[NSValue valueWithCGPoint:startPoint], [NSValue valueWithCGPoint:endPoint]];
positionAnimation.repeatCount = 1;
positionAnimation.removedOnCompletion = NO;
positionAnimation.fillMode = kCAFillModeForwards;
// 2: 1.2
CAKeyframeAnimation *scaleAnimation2 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation2.duration = 0.5;
scaleAnimation2.beginTime = 0.1; //
scaleAnimation2.values = @[@0.4, @2];
scaleAnimation2.repeatCount = 1;
scaleAnimation2.calculationMode = kCAAnimationCubic;
scaleAnimation2.removedOnCompletion = NO;
scaleAnimation2.fillMode = kCAFillModeForwards;
//
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 0.6; // 0.1 () + 0.5 ()
group.animations = @[scaleAnimation1, positionAnimation, scaleAnimation2];
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
return group;
}
///
/// @param startPoint
/// @param endPoint
- (CAAnimationGroup *)createGiftAnimationStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
CGPoint centerPoint = CGPointMake(KScreenWidth / 2, KScreenHeight / 2);
CAKeyframeAnimation *animation0 = [CAKeyframeAnimation animation];
animation0.duration = 0.8;
animation0.keyPath = @"transform.scale";
animation0.values = @[@1.0,@1.5,@2.0,@1.5];
animation0.repeatCount = 1;
animation0.calculationMode = kCAAnimationCubic;
animation0.removedOnCompletion = NO;
animation0.fillMode = kCAFillModeForwards;
CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
animation1.duration = 0.8;
animation1.beginTime = 0.8;
animation1.keyPath = @"transform.scale";
animation1.values = @[@1.5,@2.0,@2.5,@3.0];
animation1.repeatCount = 1;
animation1.calculationMode = kCAAnimationCubic;
animation1.removedOnCompletion = NO;
animation1.fillMode = kCAFillModeForwards;
CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animation];
animation2.duration = 0.8;
animation2.beginTime = 0.8;
animation2.keyPath = @"position";
animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];;
animation2.values = @[[NSValue valueWithCGPoint:startPoint],[NSValue valueWithCGPoint:CGPointMake(centerPoint.x ,centerPoint.y)]];
animation2.repeatCount = 1;
animation2.removedOnCompletion = NO;
animation2.fillMode = kCAFillModeForwards;
CAKeyframeAnimation *animation3 = [CAKeyframeAnimation animation];
animation3.duration = 0.8;
animation3.beginTime = 2.6;//0.8+0.8+1
animation3.keyPath = @"transform.scale";
animation3.values = @[@3,@2.5,@2,@1.5,@1];
animation3.repeatCount = 1;
CAKeyframeAnimation *animation4 = [CAKeyframeAnimation animation];
animation4.duration = 0.8;
animation4.beginTime = 2.6;
animation4.keyPath = @"position";
animation4.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
animation4.values = @[[NSValue valueWithCGPoint:CGPointMake(centerPoint.x ,centerPoint.y)],[NSValue valueWithCGPoint:endPoint]];
animation4.repeatCount = 1;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 3.2;
group.animations = @[animation0,animation1,animation2, animation3,animation4];
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
return group;
}
- (void)aniationDidFinish:(NetImageView *)giftImageView{
[giftImageView removeFromSuperview];
giftImageView.image = nil;
giftImageView.hidden = YES;
[self.giftVisibleArray removeObject:giftImageView];
[self.giftReuseArray addObject:giftImageView];
#pragma mark - GiftAnimationManagerDelegate
- (CGPoint)animationPointAtStageViewByUid:(NSString *)uid {
return [self.delegate animationPointAtStageViewByUid:uid];
}
#pragma mark -
@@ -1957,7 +1743,9 @@ PIUniversalBannerViewDelegate>
if (giftNotifyInfo.ceremonyGift)return;
// if(giftNotifyInfo.isHomeShow == YES)return; /// tabbar
// if(giftNotifyInfo.roomUid == self.delegate.getRoomInfo.uid)return; ///
if (self.animationListA.count == 0 && self.isPlayOfB == NO && self.isPlayOfA == NO) {
if (self.animationListA.count == 0 &&
self.isPlayOfB == NO &&
self.isPlayOfA == NO) {
[self createGiftBroadcastViewAnimation:giftNotifyInfo];
}
[self.animationListA addObject:giftNotifyInfo];
@@ -2057,8 +1845,6 @@ PIUniversalBannerViewDelegate>
[self.animationListB addObject:prizeModel];
}
- (void)createBigPrizeAnimation:(PIBaseAnimationViewModel *)prizeModel {
self.isPlayOfB = YES;
@@ -2094,11 +1880,6 @@ PIUniversalBannerViewDelegate>
[self.animationListB removeObjectAtIndex:0];
}
self.isPlayOfB = NO;
// if(self.isAnimationListAFinish == YES){
// self.isAnimationListAFinish = NO;
// [self playAnimationWithModel];
// return;
// }
[self playAnimationWithModel];
}
}];
@@ -3070,19 +2851,6 @@ PIUniversalBannerViewDelegate>
return _parser;
}
- (NSMutableSet *)bannerDequePool {
if (!_bannerDequePool) {
_bannerDequePool = [NSMutableSet set];
}
return _bannerDequePool;
}
- (NSMutableSet *)bannerVisiablePool {
if (!_bannerVisiablePool) {
_bannerVisiablePool = [NSMutableSet set];
}
return _bannerVisiablePool;
}
- (XPRoomAnimationHitView *)lowLevelView {
if (!_lowLevelView) {
_lowLevelView = [[XPRoomAnimationHitView alloc] init];
@@ -3110,26 +2878,12 @@ PIUniversalBannerViewDelegate>
return _highLevleView;
}
- (NSMutableArray<GiftReceiveInfoModel *> *)giftQueue {
if (!_giftQueue) {
_giftQueue = [NSMutableArray array];
}
return _giftQueue;
}
- (NSMutableSet<NetImageView *> *)giftReuseArray {
if (!_giftReuseArray) {
_giftReuseArray = [NSMutableSet set];
}
return _giftReuseArray;
}
- (NSMutableSet<NetImageView *> *)giftVisibleArray {
if (!_giftVisibleArray) {
_giftVisibleArray = [NSMutableSet set];
}
return _giftVisibleArray;
}
//- (NSMutableArray<GiftReceiveInfoModel *> *)giftQueue {
// if (!_giftQueue) {
// _giftQueue = [NSMutableArray array];
// }
// return _giftQueue;
//}
- (NSMutableArray<NSDictionary *> *)carEffectQueue {
if (_carEffectQueue == nil) {

View File

@@ -55,30 +55,64 @@
#pragma mark - UI
- (void)updateUIWithModel:(GiftReceiveInfoModel *)model {
if ([NSString isEmpty:self.cacheIcon]) {
self.cacheIcon = model.gift.giftUrl;
} else {
if ([self.cacheIcon isEqualToString:model.gift.giftUrl]) {
self.cacheIcon = model.gift.giftUrl;
self.giftIcon.imageUrl = model.gift.giftUrl;
}
}
if ([NSString isEmpty:self.cacheAvatar]) {
self.cacheIcon = model.avatar;
self.giftGiverAvatar.imageUrl = model.avatar;
} else {
if (![self.cacheAvatar isEqualToString:model.avatar]) {
self.cacheIcon = model.avatar;
self.giftGiverAvatar.imageUrl = model.avatar;
}
}
//
@kWeakify(self);
[self updateCacheForProperty:self.cacheIcon newValue:model.gift.giftUrl updateBlock:^(NSString *value) {
@kStrongify(self);
self.giftIcon.imageUrl = value;
}];
//
[self updateCacheForProperty:self.cacheAvatar newValue:model.avatar updateBlock:^(NSString *value) {
@kStrongify(self);
self.giftGiverAvatar.imageUrl = value;
}];
//
self.giftGiverNameLabel.text = model.nick;
//
self.giftReceiverNameLabel.text = [self receiverNameForModel:model];
//
NSInteger total = model.comboCount * model.giftNum * model.receiveUserCount;
NSString *countStr = [NSString stringWithFormat:@"x%ld", (long)total];
self.giftCountLabel.attributedText = [self generateAttributedStringForCount:countStr];
// if ([NSString isEmpty:self.cacheIcon]) {
// self.cacheIcon = model.gift.giftUrl;
// } else {
// if (![self.cacheIcon isEqualToString:model.gift.giftUrl]) {
// self.cacheIcon = model.gift.giftUrl;
// self.giftIcon.imageUrl = model.gift.giftUrl;
// }
// }
// if ([NSString isEmpty:self.cacheAvatar]) {
// self.cacheAvatar = model.avatar;
// self.giftGiverAvatar.imageUrl = model.avatar;
// } else {
// if (![self.cacheAvatar isEqualToString:model.avatar]) {
// self.cacheIcon = model.avatar;
// self.giftGiverAvatar.imageUrl = model.avatar;
// }
// }
// self.giftGiverNameLabel.text = model.nick;
//
// self.giftReceiverNameLabel.text = [self receiverNameForModel:model];
//
// NSInteger total = model.comboCount * model.giftNum * model.receiveUserCount;
// NSString *countStr = [NSString stringWithFormat:@"x%ld", (long)total];
// self.giftCountLabel.attributedText = [self generateAttributedStringForCount:countStr];
}
- (void)updateCacheForProperty:(NSString *)cacheProperty newValue:(NSString *)newValue updateBlock:(void (^)(NSString *value))updateBlock {
if ([NSString isEmpty:cacheProperty]) {
cacheProperty = newValue;
updateBlock(newValue);
} else if (![newValue isEqualToString:cacheProperty]) {
cacheProperty = newValue;
updateBlock(newValue);
}
}
- (NSMutableAttributedString *)generateAttributedStringForCount:(NSString *)countStr {
@@ -190,7 +224,9 @@
[self addSubview:self.giftIcon];
[self.giftIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.giftReceiverNameLabel.mas_trailing).offset(8);
// make.leading.mas_equalTo(self.giftGiverNameLabel.mas_trailing).offset(8);
make.leading.greaterThanOrEqualTo(self.giftGiverNameLabel.mas_trailing).offset(8);
make.leading.greaterThanOrEqualTo(self.giftReceiverNameLabel.mas_trailing).offset(8);
make.bottom.mas_equalTo(self.backgroundImageView);
make.size.mas_equalTo(CGSizeMake(kGetScaleWidth(48), kGetScaleWidth(48)));
}];

View File

@@ -18,6 +18,7 @@
@property (nonatomic, strong) UILabel *comboCountLabel;
@property(nonatomic, strong) UILabel *comboGoldLabel;
@property(nonatomic, strong) UILabel *updateGoldLabel;
@property(nonatomic, strong) UILabel *winPriceGoldLabel;
@property (nonatomic, strong) SVGAImageView *playImageView;
@property (nonatomic, strong) SVGAVideoEntity *svgaVideoEntity;
@property (nonatomic, strong) CountdownRingView *countdownRingView;
@@ -25,6 +26,8 @@
@property(nonatomic, strong) NSMutableArray *updateGoldQueue;
@property(nonatomic, assign) BOOL isAnimatingUpdateGold;
@property(nonatomic, strong) UIImpactFeedbackGenerator *f;
@end
@implementation GiftComboView
@@ -39,6 +42,7 @@
- (instancetype)init {
if (self = [super init]) {
self.f = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy];
self.updateGoldQueue = @[].mutableCopy;
[self setupNotification];
@@ -91,10 +95,6 @@
double price = [[dic objectForKey:@"Price"] doubleValue];
BOOL isFromWinning = [[dic objectForKey:@"isFromWinning"] boolValue];
[self updateCurrentGold:coin giftPrice:price isFromWinning:isFromWinning];
// [[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning"
// object:@{@"CurrentGold": receive.userPurse.diamonds,
// @"Price": @(receive.gift.goldPrice),
// @"isFromWinning":@(NO)}];
}
}];
}
@@ -175,8 +175,14 @@
[self addSubview:self.updateGoldLabel];
[self.updateGoldLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(bg);
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(0);
make.trailing.mas_equalTo(self.comboGoldLabel);
make.bottom.mas_equalTo(self.comboGoldLabel);
}];
[self addSubview:self.winPriceGoldLabel];
[self.winPriceGoldLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.trailing.mas_equalTo(self.comboGoldLabel);
make.bottom.mas_equalTo(self.comboGoldLabel);
}];
}
@@ -207,7 +213,9 @@
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@kStrongify(self);
// 1521 3
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
// AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
// AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate));
[self.f impactOccurred];
[[GiftComboManager sharedManager] sendGift];
[self.playImageView startAnimation];
@@ -231,39 +239,111 @@
}
- (void)updateCurrentGold:(double)gold giftPrice:(double)price isFromWinning:(BOOL)isFromWinning {
if (isFromWinning) {
[self.updateGoldQueue insertObject:[NSString stringWithFormat:@"+ %@", @(gold)] atIndex:0];
} else {
[self.updateGoldQueue addObject:@(-price).stringValue];
self.comboGoldLabel.text = @(gold).stringValue;
}
// if (isFromWinning) {
// [self.updateGoldQueue insertObject:[NSString stringWithFormat:@"+ %@", @(gold)] atIndex:0];
// [self processNextUpdateGold];
// } else {
// [self.updateGoldQueue addObject:@(-price).stringValue];
// self.comboGoldLabel.text = @(gold).stringValue;
// if (!self.isAnimatingUpdateGold) {
// [self processNextUpdateGold];
// }
// }
if (!self.isAnimatingUpdateGold) {
NSString *goldString = isFromWinning ? [NSString stringWithFormat:@"+ %@", @(gold)] : @(-price).stringValue;
if (isFromWinning) {
[self.updateGoldQueue insertObject:goldString atIndex:0];
[self processNextUpdateGold];
} else {
[self.updateGoldQueue addObject:goldString];
self.comboGoldLabel.text = @(gold).stringValue;
if (!self.isAnimatingUpdateGold) {
[self processNextUpdateGold];
}
}
}
- (void)processNextUpdateGold {
// if (self.updateGoldQueue.count == 0) {
// self.isAnimatingUpdateGold = NO;
// return;
// }
//
// NSNumber *goldNum = [self.updateGoldQueue xpSafeObjectAtIndex:0];
// [self.updateGoldQueue removeObjectAtIndex:0];
//
// self.isAnimatingUpdateGold = YES;
//
// if (goldNum.integerValue < 0) {
// self.updateGoldLabel.text = goldNum.stringValue;
// [self showGoldUpdateAnimation];
// } else {
// self.winPriceGoldLabel.text = goldNum.stringValue;
// [self showGoldWinPriceAnimation];
// }
if (self.updateGoldQueue.count == 0) {
self.isAnimatingUpdateGold = NO;
return;
}
NSNumber *goldNum = [self.updateGoldQueue xpSafeObjectAtIndex:0];
NSString *goldString = [self.updateGoldQueue xpSafeObjectAtIndex:0];
[self.updateGoldQueue removeObjectAtIndex:0];
self.isAnimatingUpdateGold = YES;
if (goldNum.integerValue < 0) {
self.updateGoldLabel.textColor = UIColorFromRGB(0xffd54c);
} else {
self.updateGoldLabel.textColor = UIColorFromRGB(0xBC36FF);
}
self.updateGoldLabel.text = goldNum.stringValue;
BOOL isWinning = [goldString containsString:@"+"]; //
UILabel *targetLabel = isWinning ? [self winPriceGoldLabel] : [self updateGoldLabel];
// [self addSubview:targetLabel];
// [targetLabel mas_makeConstraints:^(MASConstraintMaker *make) {
//// make.trailing.mas_equalTo(self.comboGoldLabel);
//// make.bottom.trailing.mas_equalTo(self.comboGoldLabel);
// make.leading.mas_equalTo(44);
// make.bottom.mas_equalTo(-44);
// }];
CGFloat offset = isWinning ? -80 : -40;
[self showGoldAnimationOnLabel:targetLabel withText:goldString offset:offset];
}
- (void)showGoldAnimationOnLabel:(UILabel *)label withText:(NSString *)text offset:(CGFloat)offset {
label.text = text;
label.alpha = 0;
[UIView animateWithDuration:0.2 animations:^{
[label mas_updateConstraints:^(MASConstraintMaker *make) {
// make.bottom.mas_equalTo(-44 + offset);
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(offset);
}];
label.alpha = 1;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.0
delay:0.2
options:UIViewAnimationOptionCurveLinear
animations:^{
[label mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(0);
}];
label.alpha = 0;
// [self layoutIfNeeded];
} completion:^(BOOL finished) {
// [label removeFromSuperview];
self.isAnimatingUpdateGold = NO;
[self processNextUpdateGold];
}];
// self.isAnimatingUpdateGold = NO;
// [self processNextUpdateGold];
}];
}
- (void)showGoldUpdateAnimation {
self.updateGoldLabel.alpha = 0;
[UIView animateWithDuration:0.1 animations:^{
[self.updateGoldLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(goldNum.integerValue > 0 ? -60 : -40);;
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(-40);;
}];
self.updateGoldLabel.alpha = 1;
[self layoutIfNeeded];
@@ -284,7 +364,31 @@
}];
}
#pragma mark -
- (void)showGoldWinPriceAnimation {
self.winPriceGoldLabel.alpha = 0;
[UIView animateWithDuration:0.1 animations:^{
[self.winPriceGoldLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(-60);
}];
self.winPriceGoldLabel.alpha = 1;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.0
delay:0.15
options:UIViewAnimationOptionCurveLinear
animations:^{
[self.winPriceGoldLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.comboGoldLabel.mas_bottom).offset(0);
}];
self.winPriceGoldLabel.alpha = 0;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
self.isAnimatingUpdateGold = NO;
[self processNextUpdateGold];
}];
}];
}
#pragma mark -
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// UITextView UICollectionView
@@ -323,12 +427,21 @@
}
- (UILabel *)updateGoldLabel {
// return [UILabel labelInitWithText:@"" font:kFontSemibold(24) textColor:UIColorFromRGB(0xffd54c)];;
if (!_updateGoldLabel) {
_updateGoldLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(24) textColor:UIColorFromRGB(0xffd54c)];
}
return _updateGoldLabel;
}
- (UILabel *)winPriceGoldLabel {
// return [UILabel labelInitWithText:@"" font:kFontSemibold(24) textColor:UIColorFromRGB(0xBC36FF)];
if (!_winPriceGoldLabel) {
_winPriceGoldLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(24) textColor:UIColorFromRGB(0xBC36FF)];
}
return _winPriceGoldLabel;
}
- (SVGAImageView *)playImageView {
if (_playImageView == nil) {
_playImageView = [[SVGAImageView alloc]init];
@@ -344,8 +457,14 @@
_countdownRingView = [[CountdownRingView alloc] initWithFrame:CGRectMake(0, 0, kGetScaleWidth(90), kGetScaleWidth(90))
duration:5];
_countdownRingView.userInteractionEnabled = YES;
//#if DEBUG
// UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
// longPress.minimumPressDuration = 0.2;
// [_countdownRingView addGestureRecognizer:longPress];
//#else
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
[_countdownRingView addGestureRecognizer:tap];
//#endif
}
return _countdownRingView;
}