New file |
| | |
| | | // |
| | | // YYTextContainerView.m |
| | | // YYText <https://github.com/ibireme/YYText> |
| | | // |
| | | // Created by ibireme on 15/4/21. |
| | | // Copyright (c) 2015 ibireme. |
| | | // |
| | | // This source code is licensed under the MIT-style license found in the |
| | | // LICENSE file in the root directory of this source tree. |
| | | // |
| | | |
| | | #import "YYTextContainerView.h" |
| | | |
| | | @implementation YYTextContainerView { |
| | | BOOL _attachmentChanged; |
| | | NSMutableArray *_attachmentViews; |
| | | NSMutableArray *_attachmentLayers; |
| | | } |
| | | |
| | | - (instancetype)initWithFrame:(CGRect)frame { |
| | | self = [super initWithFrame:frame]; |
| | | if (!self) return nil; |
| | | self.backgroundColor = [UIColor clearColor]; |
| | | _attachmentViews = [NSMutableArray array]; |
| | | _attachmentLayers = [NSMutableArray array]; |
| | | return self; |
| | | } |
| | | |
| | | - (void)setDebugOption:(YYTextDebugOption *)debugOption { |
| | | BOOL needDraw = _debugOption.needDrawDebug; |
| | | _debugOption = debugOption.copy; |
| | | if (_debugOption.needDrawDebug != needDraw) { |
| | | [self setNeedsDisplay]; |
| | | } |
| | | } |
| | | |
| | | - (void)setTextVerticalAlignment:(YYTextVerticalAlignment)textVerticalAlignment { |
| | | if (_textVerticalAlignment == textVerticalAlignment) return; |
| | | _textVerticalAlignment = textVerticalAlignment; |
| | | [self setNeedsDisplay]; |
| | | } |
| | | |
| | | - (void)setContentsFadeDuration:(NSTimeInterval)contentsFadeDuration { |
| | | if (_contentsFadeDuration == contentsFadeDuration) return; |
| | | _contentsFadeDuration = contentsFadeDuration; |
| | | if (contentsFadeDuration <= 0) { |
| | | [self.layer removeAnimationForKey:@"contents"]; |
| | | } |
| | | } |
| | | |
| | | - (void)setLayout:(YYTextLayout *)layout { |
| | | if (_layout == layout) return; |
| | | _layout = layout; |
| | | _attachmentChanged = YES; |
| | | [self setNeedsDisplay]; |
| | | } |
| | | |
| | | - (void)setLayout:(YYTextLayout *)layout withFadeDuration:(NSTimeInterval)fadeDuration { |
| | | self.contentsFadeDuration = fadeDuration; |
| | | self.layout = layout; |
| | | } |
| | | |
| | | - (void)drawRect:(CGRect)rect { |
| | | // fade content |
| | | [self.layer removeAnimationForKey:@"contents"]; |
| | | if (_contentsFadeDuration > 0) { |
| | | CATransition *transition = [CATransition animation]; |
| | | transition.duration = _contentsFadeDuration; |
| | | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; |
| | | transition.type = kCATransitionFade; |
| | | [self.layer addAnimation:transition forKey:@"contents"]; |
| | | } |
| | | |
| | | // update attachment |
| | | if (_attachmentChanged) { |
| | | for (UIView *view in _attachmentViews) { |
| | | if (view.superview == self) [view removeFromSuperview]; |
| | | } |
| | | for (CALayer *layer in _attachmentLayers) { |
| | | if (layer.superlayer == self.layer) [layer removeFromSuperlayer]; |
| | | } |
| | | [_attachmentViews removeAllObjects]; |
| | | [_attachmentLayers removeAllObjects]; |
| | | } |
| | | |
| | | // draw layout |
| | | CGSize boundingSize = _layout.textBoundingSize; |
| | | CGPoint point = CGPointZero; |
| | | if (_textVerticalAlignment == YYTextVerticalAlignmentCenter) { |
| | | if (_layout.container.isVerticalForm) { |
| | | point.x = -(self.bounds.size.width - boundingSize.width) * 0.5; |
| | | } else { |
| | | point.y = (self.bounds.size.height - boundingSize.height) * 0.5; |
| | | } |
| | | } else if (_textVerticalAlignment == YYTextVerticalAlignmentBottom) { |
| | | if (_layout.container.isVerticalForm) { |
| | | point.x = -(self.bounds.size.width - boundingSize.width); |
| | | } else { |
| | | point.y = (self.bounds.size.height - boundingSize.height); |
| | | } |
| | | } |
| | | [_layout drawInContext:UIGraphicsGetCurrentContext() size:self.bounds.size point:point view:self layer:self.layer debug:_debugOption cancel:nil]; |
| | | |
| | | // update attachment |
| | | if (_attachmentChanged) { |
| | | _attachmentChanged = NO; |
| | | for (YYTextAttachment *a in _layout.attachments) { |
| | | if ([a.content isKindOfClass:[UIView class]]) [_attachmentViews addObject:a.content]; |
| | | if ([a.content isKindOfClass:[CALayer class]]) [_attachmentLayers addObject:a.content]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)setFrame:(CGRect)frame { |
| | | CGSize oldSize = self.bounds.size; |
| | | [super setFrame:frame]; |
| | | if (!CGSizeEqualToSize(oldSize, self.bounds.size)) { |
| | | [self setNeedsLayout]; |
| | | } |
| | | } |
| | | |
| | | - (void)setBounds:(CGRect)bounds { |
| | | CGSize oldSize = self.bounds.size; |
| | | [super setBounds:bounds]; |
| | | if (!CGSizeEqualToSize(oldSize, self.bounds.size)) { |
| | | [self setNeedsLayout]; |
| | | } |
| | | } |
| | | |
| | | #pragma mark - UIResponder forward |
| | | |
| | | - (BOOL)canBecomeFirstResponder { |
| | | return YES; |
| | | } |
| | | |
| | | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { |
| | | return [self.hostView canPerformAction:action withSender:sender]; |
| | | } |
| | | |
| | | - (id)forwardingTargetForSelector:(SEL)aSelector { |
| | | return self.hostView; |
| | | } |
| | | |
| | | @end |