TopPopupView.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //
  2. // TopPopupView.m
  3. // AIIM
  4. //
  5. // Created by qitewei on 2025/6/17.
  6. //
  7. #import "TopPopupView.h"
  8. #import "GroupNetApi.h"
  9. static const CGFloat kPopupHeight = 80.0f;
  10. static const CGFloat kPopupCornerRadius = 20.0f;
  11. static const NSTimeInterval kPopupShowDuration = 0.3;
  12. static const NSTimeInterval kPopupHideDuration = 0.3;
  13. static const NSTimeInterval kPopupDisplayTime = 3.0;
  14. @interface TopPopupView ()
  15. @property (nonatomic, strong) UIImageView * avatar;
  16. @property (nonatomic, strong) UILabel *nicknameLabel;
  17. @property (nonatomic, strong) UILabel *messageLabel;
  18. @property (nonatomic, strong) NSTimer *dismissTimer;
  19. @property (nonatomic, assign) BOOL isDismissing;
  20. @end
  21. @implementation TopPopupView
  22. + (void)showWithNickname:(NSString *)nickname message:(NSString *)message chatId:(nonnull NSString *)chatId type:(NSInteger)type clickBlock:(PopupClickBlock)clickBlock {
  23. // 确保在主线程执行
  24. dispatch_async(dispatch_get_main_queue(), ^{
  25. // 移除可能已经存在的弹窗
  26. UIWindow *keyWindow = [UIApplication sharedApplication].delegate.window;
  27. for (UIView *subview in keyWindow.subviews) {
  28. if ([subview isKindOfClass:[TopPopupView class]]) {
  29. [subview removeFromSuperview];
  30. }
  31. }
  32. // 创建新弹窗
  33. TopPopupView *popup = [[TopPopupView alloc] initWithFrame:CGRectMake(20, -kPopupHeight, keyWindow.bounds.size.width - 40, kPopupHeight)];
  34. popup.clickBlock = clickBlock;
  35. [popup setupWithNickname:nickname message:message chatId:chatId type:type];
  36. [keyWindow addSubview:popup];
  37. // 显示动画
  38. [popup show];
  39. });
  40. }
  41. - (instancetype)initWithFrame:(CGRect)frame {
  42. self = [super initWithFrame:frame];
  43. if (self) {
  44. [self setupUI];
  45. }
  46. return self;
  47. }
  48. - (void)setupUI {
  49. // 背景设置
  50. self.backgroundColor = [UIColor whiteColor];
  51. self.layer.cornerRadius = kPopupCornerRadius;
  52. self.layer.shadowColor = [UIColor blackColor].CGColor;
  53. self.layer.shadowOffset = CGSizeMake(0, 2);
  54. self.layer.shadowOpacity = 0.2;
  55. self.layer.shadowRadius = 4;
  56. self.avatar = [[UIImageView alloc] init];
  57. [self addSubview:self.avatar];
  58. self.avatar.layer.cornerRadius = 30.f;
  59. self.avatar.layer.masksToBounds = YES;
  60. // 昵称标签
  61. self.nicknameLabel = [[UILabel alloc] init];
  62. self.nicknameLabel.font = [UIFont boldSystemFontOfSize:16];
  63. self.nicknameLabel.textColor = [UIColor blackColor];
  64. [self addSubview:self.nicknameLabel];
  65. // 消息标签
  66. self.messageLabel = [[UILabel alloc] init];
  67. self.messageLabel.font = [UIFont systemFontOfSize:14];
  68. self.messageLabel.textColor = [UIColor blackColor];
  69. self.messageLabel.numberOfLines = 2;
  70. [self addSubview:self.messageLabel];
  71. // 添加点击手势
  72. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
  73. [self addGestureRecognizer:tap];
  74. // 添加上滑手势
  75. UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe)];
  76. swipe.direction = UISwipeGestureRecognizerDirectionUp;
  77. [self addGestureRecognizer:swipe];
  78. }
  79. - (void)setupWithNickname:(NSString *)nickname message:(NSString *)message chatId:(NSString *)chatId type:(NSInteger)type{
  80. self.nicknameLabel.text = nickname;
  81. self.messageLabel.text = message;
  82. if (type == 0) {
  83. [self.avatar sd_setImageWithURL:getURL(chatId)];
  84. }else{
  85. [GroupNetApi getGroupInfo:chatId succ:^(int code, NSDictionary * _Nullable result) {
  86. NSDictionary * userinfo=result[@"data"];
  87. if (userinfo[@"avatar"]) {
  88. [self.avatar sd_setImageWithURL:getURL(userinfo[@"avatar"])];
  89. self.nicknameLabel.text = [NSString stringWithFormat:@"%@(%@)",nickname,userinfo[@"name"]];
  90. }
  91. } fail:^(NSError * _Nonnull error) {
  92. }];
  93. }
  94. // 布局
  95. CGFloat padding = 12.0f;
  96. CGFloat labelWidth = self.bounds.size.width - 2 * padding;
  97. self.avatar.frame = CGRectMake(padding, padding, 60, 60);
  98. self.nicknameLabel.frame = CGRectMake(padding+60+padding, padding, labelWidth, 20);
  99. self.messageLabel.frame = CGRectMake(padding+60+padding, CGRectGetMaxY(self.nicknameLabel.frame) + 4, labelWidth, 40);
  100. }
  101. - (void)show {
  102. // 初始位置在屏幕外
  103. CGRect startFrame = self.frame;
  104. // 动画目标位置
  105. CGRect endFrame = startFrame;
  106. endFrame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height + 10;
  107. // 执行显示动画
  108. [UIView animateWithDuration:kPopupShowDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  109. self.frame = endFrame;
  110. } completion:^(BOOL finished) {
  111. // 启动自动消失计时器
  112. [self startDismissTimer];
  113. }];
  114. }
  115. - (void)startDismissTimer {
  116. self.dismissTimer = [NSTimer scheduledTimerWithTimeInterval:kPopupDisplayTime target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
  117. }
  118. - (void)dismiss {
  119. if (self.isDismissing) return;
  120. self.isDismissing = YES;
  121. // 取消计时器
  122. [self.dismissTimer invalidate];
  123. self.dismissTimer = nil;
  124. // 动画目标位置
  125. CGRect endFrame = self.frame;
  126. endFrame.origin.y = -kPopupHeight;
  127. // 执行消失动画
  128. [UIView animateWithDuration:kPopupHideDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
  129. self.frame = endFrame;
  130. } completion:^(BOOL finished) {
  131. [self removeFromSuperview];
  132. }];
  133. }
  134. - (void)handleTap {
  135. if (self.clickBlock) {
  136. self.clickBlock();
  137. }
  138. [self dismiss];
  139. }
  140. - (void)handleSwipe {
  141. [self dismiss];
  142. }
  143. - (void)dealloc {
  144. [self.dismissTimer invalidate];
  145. }
  146. @end