mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
329 lines
9.8 KiB
Objective-C
329 lines
9.8 KiB
Objective-C
#import "TGTooltipView.h"
|
|
|
|
#import "LegacyComponentsInternal.h"
|
|
#import "TGFont.h"
|
|
#import "TGImageUtils.h"
|
|
|
|
#import <QuartzCore/QuartzCore.h>
|
|
|
|
@interface TGTooltipView () <UIScrollViewDelegate>
|
|
{
|
|
UIImageView *_backgroundView;
|
|
UIImageView *_arrowView;
|
|
UILabel *_textLabel;
|
|
|
|
CGFloat _arrowLocation;
|
|
}
|
|
|
|
@property (nonatomic, strong) ASHandle *watcherHandle;
|
|
|
|
@end
|
|
|
|
@implementation TGTooltipView
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
if (self)
|
|
{
|
|
self.alpha = 0.0f;
|
|
self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
|
|
|
|
_numberOfLines = 1;
|
|
|
|
_maxWidth = 320.0f;
|
|
|
|
_backgroundView = [[UIImageView alloc] initWithImage:[TGTintedImage(TGComponentsImageNamed(@"TooltipBackground"), UIColorRGBA(0x252525, 0.96f)) stretchableImageWithLeftCapWidth:9.0f topCapHeight:9.0f]];
|
|
[self addSubview:_backgroundView];
|
|
|
|
_arrowView = [[UIImageView alloc] initWithImage:TGTintedImage(TGComponentsImageNamed(@"TooltipArrow"), UIColorRGBA(0x252525, 0.96f))];
|
|
[self addSubview:_arrowView];
|
|
|
|
_arrowLocation = 50;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setForceArrowOnTop:(bool)forceArrowOnTop
|
|
{
|
|
_forceArrowOnTop = forceArrowOnTop;
|
|
_arrowView.image = [UIImage imageWithCGImage:_arrowView.image.CGImage scale:_arrowView.image.scale orientation:UIImageOrientationDown];
|
|
}
|
|
|
|
- (void)setText:(NSString *)text
|
|
{
|
|
[self setText:text animated:false];
|
|
}
|
|
|
|
- (void)setText:(NSString *)text animated:(bool)animated
|
|
{
|
|
if (_textLabel == nil)
|
|
{
|
|
_textLabel = [[UILabel alloc] init];
|
|
_textLabel.backgroundColor = [UIColor clearColor];
|
|
_textLabel.font = TGSystemFontOfSize(14);
|
|
_textLabel.textColor = [UIColor whiteColor];
|
|
_textLabel.userInteractionEnabled = false;
|
|
_textLabel.textAlignment = NSTextAlignmentCenter;
|
|
[self addSubview:_textLabel];
|
|
}
|
|
|
|
_textLabel.numberOfLines = _numberOfLines;
|
|
|
|
if (animated)
|
|
{
|
|
[UIView transitionWithView:_textLabel duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^
|
|
{
|
|
_textLabel.text = text;
|
|
} completion:nil];
|
|
|
|
[UIView animateWithDuration:0.2 animations:^
|
|
{
|
|
[self sizeToFit];
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
_textLabel.text = text;
|
|
|
|
if (_numberOfLines == 1) {
|
|
[_textLabel sizeToFit];
|
|
} else {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
CGSize textSize = [_textLabel.text sizeWithFont:_textLabel.font constrainedToSize:CGSizeMake(_maxWidth - 20.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
|
|
#pragma clang diagnostic pop
|
|
textSize.width = CGCeil(textSize.width);
|
|
textSize.height = CGCeil(textSize.height);
|
|
_textLabel.frame = CGRectMake(_textLabel.frame.origin.x, _textLabel.frame.origin.y, textSize.width, textSize.height);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)sizeToFit
|
|
{
|
|
CGAffineTransform transform = self.transform;
|
|
self.transform = CGAffineTransformIdentity;
|
|
|
|
CGFloat maxWidth = _maxWidth;
|
|
CGFloat inset = 9.0f;
|
|
|
|
if (_numberOfLines == 1) {
|
|
[_textLabel sizeToFit];
|
|
} else {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
CGSize textSize = [_textLabel.text sizeWithFont:_textLabel.font constrainedToSize:CGSizeMake(maxWidth - 20.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
|
|
#pragma clang diagnostic pop
|
|
textSize.width = CGCeil(textSize.width);
|
|
textSize.height = CGCeil(textSize.height);
|
|
_textLabel.frame = CGRectMake(_textLabel.frame.origin.x, _textLabel.frame.origin.y, textSize.width, textSize.height);
|
|
}
|
|
|
|
CGFloat minArrowX = 10.0f;
|
|
CGFloat maxArrowX = self.frame.size.width - 10.0f;
|
|
|
|
CGFloat arrowX = CGFloor(_arrowLocation - _arrowView.frame.size.width / 2);
|
|
arrowX = MIN(MAX(minArrowX, arrowX), maxArrowX);
|
|
|
|
_arrowView.frame = CGRectMake(arrowX + TGScreenPixel, _forceArrowOnTop ? 0.0f : 38.0f - TGScreenPixel, _arrowView.frame.size.width, _arrowView.frame.size.height);
|
|
|
|
CGFloat backgroundOffset = 19.0f + _textLabel.frame.size.height - 36.0f;
|
|
|
|
CGFloat backgroundWidth = MIN(maxWidth, _textLabel.frame.size.width + inset * 2.0f);
|
|
|
|
CGFloat labelWidth = backgroundWidth - inset * 2.0f;
|
|
if (_numberOfLines != 1) {
|
|
labelWidth = _textLabel.frame.size.width;
|
|
backgroundOffset += 1.0f;
|
|
}
|
|
|
|
CGFloat x = arrowX - (backgroundWidth - _arrowView.frame.size.width) / 2.0f;
|
|
x = MAX(4.0f, MIN(x, self.frame.size.width - backgroundWidth - 4.0f));
|
|
_backgroundView.frame = CGRectMake(x, 2.0f - backgroundOffset + (_forceArrowOnTop ? 7.0f : 0.0f), backgroundWidth, 36.0f + backgroundOffset);
|
|
_textLabel.frame = CGRectMake(_backgroundView.frame.origin.x + inset, 12.0f - TGScreenPixel - backgroundOffset + (_forceArrowOnTop ? 7.0f : 0.0f), labelWidth, _textLabel.frame.size.height);
|
|
|
|
if (_forceArrowOnTop)
|
|
{
|
|
_arrowView.frame = CGRectMake(_arrowView.frame.origin.x, _backgroundView.frame.origin.y - _arrowView.frame.size.height, _arrowView.frame.size.width, _arrowView.frame.size.height);
|
|
}
|
|
|
|
self.transform = transform;
|
|
}
|
|
|
|
- (void)showInView:(UIView *)view fromRect:(CGRect)rect
|
|
{
|
|
[self showInView:view fromRect:rect animated:true];
|
|
}
|
|
|
|
- (void)showInView:(UIView *)__unused view fromRect:(CGRect)rect animated:(bool)animated
|
|
{
|
|
CGAffineTransform transform = self.transform;
|
|
self.transform = CGAffineTransformIdentity;
|
|
|
|
CGRect frame = self.frame;
|
|
if (_forceArrowOnTop)
|
|
frame.origin.y = rect.origin.y + 24.0f;
|
|
else
|
|
frame.origin.y = rect.origin.y - frame.size.height - 14.0f;
|
|
|
|
_arrowLocation = CGFloor(rect.origin.x + rect.size.width / 2) - frame.origin.x;
|
|
|
|
self.frame = frame;
|
|
[self sizeToFit];
|
|
|
|
self.transform = transform;
|
|
|
|
self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
|
|
self.layer.shouldRasterize = true;
|
|
|
|
self.alpha = 1.0f;
|
|
|
|
if (animated)
|
|
{
|
|
[UIView animateWithDuration:0.142 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
self.transform = CGAffineTransformMakeScale(1.07f, 1.07f);
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if(finished)
|
|
{
|
|
[UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
self.transform = CGAffineTransformMakeScale(0.967f, 0.967f);
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
[UIView animateWithDuration:0.06 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
self.transform = CGAffineTransformIdentity;
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
self.layer.shouldRasterize = false;
|
|
}
|
|
}];
|
|
}
|
|
}];
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
self.transform = CGAffineTransformIdentity;
|
|
self.alpha = 0.0f;
|
|
[UIView animateWithDuration:0.3 animations:^
|
|
{
|
|
self.alpha = 1.0f;
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)hide:(dispatch_block_t)completion
|
|
{
|
|
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
self.alpha = 0.0f;
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
|
|
|
|
if (completion)
|
|
completion();
|
|
}
|
|
}];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@interface TGTooltipContainerView ()
|
|
{
|
|
bool _skipHitTest;
|
|
}
|
|
@end
|
|
|
|
@implementation TGTooltipContainerView
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
if (self != nil)
|
|
{
|
|
_tooltipView = [[TGTooltipView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frame.size.width, 41.0f)];
|
|
[self addSubview:_tooltipView];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
|
{
|
|
if (_skipHitTest)
|
|
return nil;
|
|
|
|
UIView *result = [super hitTest:point withEvent:event];
|
|
UIView *superViewResult = nil;
|
|
if (self.tooltipView.sourceView != nil)
|
|
{
|
|
_skipHitTest = true;
|
|
superViewResult = [self.superview hitTest:[self convertPoint:point toView:self.superview] withEvent:event];
|
|
_skipHitTest = false;
|
|
}
|
|
|
|
if (self.tooltipView.sourceView != nil && superViewResult == self.tooltipView.sourceView)
|
|
return nil;
|
|
|
|
if (result == self || result == nil)
|
|
{
|
|
[self hideTooltip];
|
|
return nil;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (void)showTooltipFromRect:(CGRect)rect
|
|
{
|
|
[self showTooltipFromRect:rect animated:true];
|
|
}
|
|
|
|
- (void)showTooltipFromRect:(CGRect)rect animated:(bool)animated
|
|
{
|
|
_isShowingTooltip = true;
|
|
_showingTooltipFromRect = rect;
|
|
[_tooltipView showInView:self fromRect:rect animated:animated];
|
|
}
|
|
|
|
- (void)setFrame:(CGRect)frame
|
|
{
|
|
if (!CGSizeEqualToSize(frame.size, self.frame.size))
|
|
[self hideTooltip];
|
|
|
|
[super setFrame:frame];
|
|
}
|
|
|
|
- (void)hideTooltip
|
|
{
|
|
if (_isShowingTooltip)
|
|
{
|
|
_isShowingTooltip = false;
|
|
_showingTooltipFromRect = CGRectZero;
|
|
|
|
[_tooltipView.watcherHandle requestAction:@"tooltipWillHide" options:nil];
|
|
|
|
[_tooltipView hide:^
|
|
{
|
|
[self removeFromSuperview];
|
|
}];
|
|
}
|
|
}
|
|
|
|
@end
|