TopPopupView.m 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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 avatar:(nonnull NSString *)avatar 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 avatar:avatar 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 avatar:(nonnull NSString *)avatar message:(NSString *)message chatId:(NSString *)chatId type:(NSInteger)type{
  80. self.nicknameLabel.text = nickname;
  81. self.messageLabel.text = message;
  82. if (avatar) {
  83. [self.avatar sd_setImageWithURL:getURL(avatar) placeholderImage:kImageMake(@"Avatar")];
  84. }
  85. // 布局
  86. CGFloat padding = 12.0f;
  87. CGFloat labelWidth = self.bounds.size.width - 2 * padding;
  88. self.avatar.frame = CGRectMake(padding, padding, 60, 60);
  89. self.nicknameLabel.frame = CGRectMake(padding+60+padding, padding, labelWidth, 20);
  90. self.messageLabel.frame = CGRectMake(padding+60+padding, CGRectGetMaxY(self.nicknameLabel.frame) + 4, labelWidth, 40);
  91. }
  92. - (void)show {
  93. // 初始位置在屏幕外
  94. CGRect startFrame = self.frame;
  95. // 动画目标位置
  96. CGRect endFrame = startFrame;
  97. endFrame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height + 10;
  98. // 执行显示动画
  99. [UIView animateWithDuration:kPopupShowDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  100. self.frame = endFrame;
  101. } completion:^(BOOL finished) {
  102. // 启动自动消失计时器
  103. [self startDismissTimer];
  104. }];
  105. }
  106. - (void)startDismissTimer {
  107. self.dismissTimer = [NSTimer scheduledTimerWithTimeInterval:kPopupDisplayTime target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
  108. }
  109. - (void)dismiss {
  110. if (self.isDismissing) return;
  111. self.isDismissing = YES;
  112. // 取消计时器
  113. [self.dismissTimer invalidate];
  114. self.dismissTimer = nil;
  115. // 动画目标位置
  116. CGRect endFrame = self.frame;
  117. endFrame.origin.y = -kPopupHeight;
  118. // 执行消失动画
  119. [UIView animateWithDuration:kPopupHideDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
  120. self.frame = endFrame;
  121. } completion:^(BOOL finished) {
  122. [self removeFromSuperview];
  123. }];
  124. }
  125. - (void)handleTap {
  126. if (self.clickBlock) {
  127. self.clickBlock();
  128. }
  129. [self dismiss];
  130. }
  131. - (void)handleSwipe {
  132. [self dismiss];
  133. }
  134. - (void)dealloc {
  135. [self.dismissTimer invalidate];
  136. }
  137. @end