增加换肤功能
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaAuthorizationPrompter : UIViewController
|
||||
+ (BOOL) verifyPermissionGranted:(UIViewController*)parentView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaAuthorizationPrompter.h"
|
||||
#import <SafariServices/SafariServices.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaSignatureChecker.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
|
||||
#define IM_MULTIMEDIA_PLUGIN_DOCUMENT_URL @"https://cloud.tencent.com/document/product/269/113290"
|
||||
|
||||
@interface TUIMultimediaAuthorizationPrompter () {
|
||||
UIButton *_confirmButton;
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) void (^dismissHandler)(void);
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaAuthorizationPrompter
|
||||
|
||||
+ (BOOL) verifyPermissionGranted:(UIViewController*)parentView {
|
||||
if ([[TUIMultimediaSignatureChecker shareInstance] isFunctionSupport]) {
|
||||
return YES;
|
||||
}
|
||||
NSLog(@"signature checker do not support function.");
|
||||
if (parentView != nil) {
|
||||
[TUIMultimediaAuthorizationPrompter showPrompterDialogInViewController:parentView];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (void)showPrompterDialogInViewController:(UIViewController *)presentingVC {
|
||||
TUIMultimediaAuthorizationPrompter *dialog = [[TUIMultimediaAuthorizationPrompter alloc] init];
|
||||
dialog.modalPresentationStyle = UIModalPresentationOverCurrentContext;
|
||||
dialog.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
|
||||
[presentingVC presentViewController:dialog animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self setupUI];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
|
||||
UIView *container = [[UIView alloc] init];
|
||||
container.backgroundColor = [UIColor tertiarySystemBackgroundColor];
|
||||
container.layer.cornerRadius = 16;
|
||||
container.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.view addSubview:container];
|
||||
|
||||
UIStackView *titleStack = [[UIStackView alloc] init];
|
||||
titleStack.axis = UILayoutConstraintAxisHorizontal;
|
||||
titleStack.spacing = 12;
|
||||
UILabel *titleLabel = [[UILabel alloc] init];
|
||||
titleLabel.text = [TUIMultimediaCommon localizedStringForKey:@"prompter"];
|
||||
titleLabel.font = [UIFont systemFontOfSize:20];
|
||||
titleLabel.textColor = [UIColor labelColor];
|
||||
[titleStack addArrangedSubview:titleLabel];
|
||||
|
||||
UILabel *prompter = [[UILabel alloc] init];
|
||||
prompter.numberOfLines = 0;
|
||||
prompter.text = [TUIMultimediaCommon localizedStringForKey:@"authorization_prompter"];
|
||||
prompter.font = [UIFont systemFontOfSize:14];
|
||||
prompter.textColor = [UIColor secondaryLabelColor];
|
||||
|
||||
UITextView *prompter_access_docments = [[UITextView alloc] init];
|
||||
prompter_access_docments.editable = NO;
|
||||
prompter_access_docments.scrollEnabled = NO;
|
||||
prompter_access_docments.backgroundColor = [UIColor clearColor];
|
||||
prompter_access_docments.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
|
||||
NSString* prompter_accessing_documents = [TUIMultimediaCommon localizedStringForKey:@"authorization_prompter_accessing_documents"];
|
||||
NSString* documents_title = [TUIMultimediaCommon localizedStringForKey:@"authorization_prompter_documents_title"];
|
||||
NSRange title_range = [prompter_accessing_documents rangeOfString:documents_title];
|
||||
|
||||
NSMutableAttributedString *linkText = [[NSMutableAttributedString alloc] initWithString:prompter_accessing_documents];
|
||||
[linkText addAttribute:NSLinkAttributeName
|
||||
value:IM_MULTIMEDIA_PLUGIN_DOCUMENT_URL
|
||||
range:title_range];
|
||||
prompter_access_docments.attributedText = linkText;
|
||||
prompter_access_docments.tintColor = [UIColor systemBlueColor];
|
||||
prompter_access_docments.font = [UIFont systemFontOfSize:14];
|
||||
prompter_access_docments.textColor = [UIColor secondaryLabelColor];
|
||||
|
||||
|
||||
UILabel *prompter_remove_module = [[UILabel alloc] init];
|
||||
prompter_remove_module.numberOfLines = 0;
|
||||
prompter_remove_module.text = [TUIMultimediaCommon localizedStringForKey:@"authorization_prompter_remove_module"];
|
||||
prompter_remove_module.font = [UIFont systemFontOfSize:14];
|
||||
prompter_remove_module.textColor = [UIColor secondaryLabelColor];
|
||||
|
||||
|
||||
_confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_confirmButton setTitle:[TUIMultimediaCommon localizedStringForKey:@"ok"] forState:UIControlStateNormal];
|
||||
[_confirmButton addTarget:self
|
||||
action:@selector(confirmAction)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
_confirmButton.titleLabel.font = [UIFont systemFontOfSize:16];
|
||||
|
||||
|
||||
UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||
titleStack, prompter, prompter_access_docments, prompter_remove_module, _confirmButton
|
||||
]];
|
||||
stack.axis = UILayoutConstraintAxisVertical;
|
||||
stack.spacing = 6;
|
||||
stack.alignment = UIStackViewAlignmentLeading;
|
||||
stack.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[container addSubview:stack];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[container.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
||||
[container.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
|
||||
[container.widthAnchor constraintEqualToAnchor:self.view.widthAnchor
|
||||
multiplier:0.8],
|
||||
|
||||
[stack.topAnchor constraintEqualToAnchor:container.topAnchor constant:20],
|
||||
[stack.leadingAnchor constraintEqualToAnchor:container.leadingAnchor constant:20],
|
||||
[stack.trailingAnchor constraintEqualToAnchor:container.trailingAnchor constant:-20],
|
||||
[stack.bottomAnchor constraintEqualToAnchor:container.bottomAnchor constant:-20],
|
||||
|
||||
[_confirmButton.leadingAnchor constraintEqualToAnchor:stack.leadingAnchor]
|
||||
]];
|
||||
}
|
||||
|
||||
- (void)confirmAction {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UITextViewDelegate
|
||||
- (BOOL)textView:(UITextView *)textView
|
||||
shouldInteractWithURL:(NSURL *)URL
|
||||
inRange:(NSRange)characterRange
|
||||
interaction:(UITextItemInteraction)interaction {
|
||||
SFSafariViewController *safari = [[SFSafariViewController alloc] initWithURL:URL];
|
||||
[self presentViewController:safari animated:YES completion:nil];
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaAutoScrollLabel : UIView
|
||||
@property(nonatomic) CGFloat scrollSpeed;
|
||||
@property(nonatomic) NSTimeInterval pauseInterval;
|
||||
@property(nonatomic) NSAttributedString *text;
|
||||
@property(nonatomic) CGFloat fadeInOutRate;
|
||||
@property(nonatomic) BOOL active;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaAutoScrollLabel.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaGeometry.h"
|
||||
|
||||
static NSString *const ScrollAnimeKey = @"ScrollAnimeKey";
|
||||
|
||||
@interface TUIMultimediaAutoScrollLabel () <CAAnimationDelegate> {
|
||||
UIScrollView *_scrollView;
|
||||
UILabel *_label;
|
||||
UILabel *_label2;
|
||||
CAGradientLayer *_fadeLayer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaAutoScrollLabel
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_scrollSpeed = 20;
|
||||
_pauseInterval = 2;
|
||||
_text = [[NSAttributedString alloc] initWithString:@""];
|
||||
_fadeInOutRate = 0.1;
|
||||
[self initUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
_scrollView = [[UIScrollView alloc] init];
|
||||
_scrollView.scrollEnabled = NO;
|
||||
_scrollView.userInteractionEnabled = NO;
|
||||
[self addSubview:_scrollView];
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
_label.numberOfLines = 1;
|
||||
[_scrollView addSubview:_label];
|
||||
|
||||
_label2 = [[UILabel alloc] init];
|
||||
_label2.numberOfLines = 1;
|
||||
[_scrollView addSubview:_label2];
|
||||
|
||||
NSArray *fadeColorList = @[
|
||||
(__bridge id)[UIColor.blackColor colorWithAlphaComponent:0].CGColor,
|
||||
(__bridge id)UIColor.blackColor.CGColor,
|
||||
(__bridge id)UIColor.blackColor.CGColor,
|
||||
(__bridge id)[UIColor.blackColor colorWithAlphaComponent:0].CGColor,
|
||||
];
|
||||
_fadeLayer = [[CAGradientLayer alloc] init];
|
||||
_fadeLayer.backgroundColor = UIColor.clearColor.CGColor;
|
||||
_fadeLayer.colors = fadeColorList;
|
||||
_fadeLayer.locations = @[ @0, @(_fadeInOutRate), @(1 - _fadeInOutRate), @1 ];
|
||||
_fadeLayer.startPoint = CGPointMake(0, 0.5);
|
||||
_fadeLayer.endPoint = CGPointMake(1, 0.5);
|
||||
|
||||
[_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.equalTo(_label.mas_height);
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.top.bottom.equalTo(_scrollView);
|
||||
}];
|
||||
[_label2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.bottom.equalTo(_scrollView);
|
||||
make.left.equalTo(_label.mas_right).offset(self.bounds.size.width);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
_fadeLayer.frame = self.bounds;
|
||||
if (_active) {
|
||||
[self startScroll];
|
||||
}
|
||||
[_label2 mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_label.mas_right).offset(self.bounds.size.width);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)startScroll {
|
||||
CGFloat scrollWidth = _scrollView.bounds.size.width;
|
||||
CGFloat labelWidth = _label.bounds.size.width;
|
||||
|
||||
[_scrollView.layer removeAnimationForKey:ScrollAnimeKey];
|
||||
|
||||
_scrollView.bounds = CGRectMake(0, 0, _scrollView.bounds.size.width, _scrollView.bounds.size.height);
|
||||
|
||||
CABasicAnimation *anime = [CABasicAnimation animationWithKeyPath:@"bounds.origin.x"];
|
||||
anime.fromValue = @(0);
|
||||
anime.toValue = @(labelWidth + scrollWidth);
|
||||
anime.duration = (labelWidth + scrollWidth) / _scrollSpeed;
|
||||
anime.removedOnCompletion = NO;
|
||||
anime.delegate = self;
|
||||
[_scrollView.layer addAnimation:anime forKey:ScrollAnimeKey];
|
||||
}
|
||||
|
||||
- (void)stopScroll {
|
||||
[_scrollView.layer removeAnimationForKey:ScrollAnimeKey];
|
||||
_scrollView.contentOffset = CGPointMake(0, 0);
|
||||
}
|
||||
|
||||
- (void)animationDidStop:(CAAnimation *)anime finished:(BOOL)finished {
|
||||
if (anime == [_scrollView.layer animationForKey:ScrollAnimeKey] && finished && _active) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_pauseInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (self->_active) {
|
||||
[self startScroll];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#pragma mark - Properties
|
||||
- (void)setActive:(BOOL)active {
|
||||
if (!_active && active) {
|
||||
[self startScroll];
|
||||
self.layer.mask = _fadeLayer;
|
||||
} else if (_active && !active) {
|
||||
[self stopScroll];
|
||||
self.layer.mask = nil;
|
||||
}
|
||||
_active = active;
|
||||
}
|
||||
- (void)setText:(NSAttributedString *)text {
|
||||
_label.attributedText = text;
|
||||
[_label sizeToFit];
|
||||
|
||||
_label2.attributedText = text;
|
||||
[_label2 sizeToFit];
|
||||
|
||||
_scrollView.contentSize = _label.bounds.size;
|
||||
_scrollView.contentOffset = CGPointMake(0, 0);
|
||||
if (_active) {
|
||||
[self startScroll];
|
||||
}
|
||||
}
|
||||
- (void)setFadeInOutRate:(CGFloat)fadeInOutRate {
|
||||
_fadeInOutRate = MAX(0, MIN(1, fadeInOutRate));
|
||||
_fadeLayer.locations = @[ @0, @(_fadeInOutRate), @(1 - _fadeInOutRate), @1 ];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaCheckBox : UIControl
|
||||
@property(nonatomic) BOOL on;
|
||||
@property(nonatomic) NSString *text;
|
||||
@property(nonatomic) UIColor *textColor;
|
||||
@property(nonatomic) CGSize iconSize;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaCheckBox.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaImageUtil.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
|
||||
|
||||
@interface TUIMultimediaCheckBox () {
|
||||
UILabel *_label;
|
||||
UIImageView *_imgView;
|
||||
UITapGestureRecognizer *_tapRec;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaCheckBox
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
_iconSize = CGSizeMake(18, 18);
|
||||
UIImage *imgOff = [TUIMultimediaImageUtil imageFromImage:TUIMultimediaPluginBundleThemeImage(@"checkbox_off_img", @"checkbox_off") withTintColor:[[TUIMultimediaConfig sharedInstance] getThemeColor]];;
|
||||
UIImage *imgOn = [TUIMultimediaImageUtil imageFromImage:TUIMultimediaPluginBundleThemeImage(@"checkbox_on_img", @"checkbox_on") withTintColor:[[TUIMultimediaConfig sharedInstance] getThemeColor]];
|
||||
_imgView = [[UIImageView alloc] initWithImage:imgOff highlightedImage:imgOn];
|
||||
[self addSubview:_imgView];
|
||||
_imgView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
[self addSubview:_label];
|
||||
_label.textColor = UIColor.whiteColor;
|
||||
|
||||
[_imgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.top.bottom.equalTo(self);
|
||||
make.size.mas_equalTo(self->_iconSize);
|
||||
}];
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self);
|
||||
make.left.equalTo(_imgView.mas_right).inset(5);
|
||||
make.centerY.equalTo(_imgView);
|
||||
}];
|
||||
|
||||
_tapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)];
|
||||
[self addGestureRecognizer:_tapRec];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onTap {
|
||||
[self setOn:!_on];
|
||||
[self sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
- (void)setOn:(BOOL)on {
|
||||
_on = on;
|
||||
_imgView.highlighted = on;
|
||||
}
|
||||
|
||||
- (void)setIconSize:(CGSize)iconSize {
|
||||
_iconSize = iconSize;
|
||||
[_imgView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(self->_iconSize);
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)text {
|
||||
return _label.text;
|
||||
}
|
||||
|
||||
- (void)setText:(NSString *)text {
|
||||
_label.text = text;
|
||||
}
|
||||
|
||||
- (UIColor *)textColor {
|
||||
return _label.textColor;
|
||||
}
|
||||
|
||||
- (void)setTextColor:(UIColor *)textColor {
|
||||
_label.textColor = textColor;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
环形进度条
|
||||
*/
|
||||
@interface TUIMultimediaCircleProgressView : UIView
|
||||
@property(nonatomic) CGFloat progress; // 0.0 ~ 1.0
|
||||
@property(nonatomic) UIColor *progressColor; // 进度条颜色
|
||||
@property(nonatomic) UIColor *progressBgColor; // 进度条背景颜色
|
||||
@property(nonatomic) CGFloat width; // 圆环宽度
|
||||
@property(nonatomic) BOOL clockwise;
|
||||
@property(nonatomic) CGFloat startAngle;
|
||||
@property(nonatomic) CAShapeLayerLineCap lineCap;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaCircleProgressView.h"
|
||||
|
||||
@interface TUIMultimediaCircleProgressView () {
|
||||
CAShapeLayer *_backLayer; // 背景图层
|
||||
CAShapeLayer *_frontLayer; // 用来填充的图层
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaCircleProgressView
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_clockwise = YES;
|
||||
_width = 5;
|
||||
_startAngle = -M_PI / 2;
|
||||
_progressBgColor = UIColor.grayColor;
|
||||
_progressColor = UIColor.greenColor;
|
||||
_lineCap = kCALineCapRound;
|
||||
[self initUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)initUI {
|
||||
_backLayer = [CAShapeLayer layer];
|
||||
[self.layer addSublayer:_backLayer];
|
||||
_backLayer.fillColor = nil;
|
||||
_backLayer.strokeColor = _progressBgColor.CGColor;
|
||||
|
||||
_frontLayer = [CAShapeLayer layer];
|
||||
[self.layer addSublayer:_frontLayer];
|
||||
_frontLayer.fillColor = nil;
|
||||
_frontLayer.lineCap = _lineCap;
|
||||
_frontLayer.strokeColor = _progressColor.CGColor;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat len = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
|
||||
CGPoint center = CGPointMake(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2);
|
||||
UIBezierPath *backgroundBezierPath = [UIBezierPath bezierPathWithArcCenter:center
|
||||
radius:(len - _width) / 2.0
|
||||
startAngle:0
|
||||
endAngle:M_PI * 2
|
||||
clockwise:_clockwise];
|
||||
UIBezierPath *frontFillBezierPath = [UIBezierPath bezierPathWithArcCenter:center
|
||||
radius:(len - _width) / 2.0
|
||||
startAngle:_startAngle
|
||||
endAngle:_startAngle + (_clockwise ? 2 * M_PI : -2 * M_PI)
|
||||
clockwise:_clockwise];
|
||||
_backLayer.path = backgroundBezierPath.CGPath;
|
||||
_frontLayer.path = frontFillBezierPath.CGPath;
|
||||
_frontLayer.lineWidth = _width;
|
||||
_backLayer.lineWidth = _width;
|
||||
_frontLayer.strokeEnd = 0;
|
||||
}
|
||||
|
||||
#pragma mark - setters
|
||||
- (void)setProgress:(CGFloat)progress {
|
||||
_progress = MAX(0, MIN(1, progress));
|
||||
}
|
||||
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
|
||||
_progress = MAX(0, MIN(1, progress));
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.25
|
||||
animations:^{
|
||||
self->_frontLayer.strokeEnd = progress;
|
||||
}];
|
||||
} else {
|
||||
self->_frontLayer.strokeEnd = progress;
|
||||
}
|
||||
}
|
||||
- (void)setClockwise:(BOOL)clockwise {
|
||||
_clockwise = clockwise;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
- (void)setStartAngle:(CGFloat)startAngle {
|
||||
_startAngle = startAngle;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
- (void)setWidth:(CGFloat)width {
|
||||
_width = width;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
- (void)setProgressColor:(UIColor *)progressColor {
|
||||
_progressColor = progressColor;
|
||||
_frontLayer.strokeColor = _progressColor.CGColor;
|
||||
}
|
||||
- (void)setProgressBgColor:(UIColor *)progressBgColor {
|
||||
_progressBgColor = progressBgColor;
|
||||
_backLayer.strokeColor = _progressBgColor.CGColor;
|
||||
}
|
||||
- (void)setLineCap:(CAShapeLayerLineCap)lineCap {
|
||||
_lineCap = lineCap;
|
||||
_frontLayer.lineCap = lineCap;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaIconLabelButton : UIButton
|
||||
@property(nonatomic) CGSize iconSize;
|
||||
@property(nonatomic) CGFloat iconLabelGap;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaIconLabelButton.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface TUIMultimediaIconLabelButton () {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaIconLabelButton
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
return self;
|
||||
}
|
||||
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
|
||||
CGFloat midX = CGRectGetMidX(contentRect);
|
||||
CGFloat minY = CGRectGetMinY(contentRect);
|
||||
return CGRectMake(midX - _iconSize.width / 2, minY, _iconSize.width, _iconSize.height);
|
||||
}
|
||||
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
|
||||
CGRect imageRect = [self imageRectForContentRect:contentRect];
|
||||
CGSize size = self.currentAttributedTitle.size;
|
||||
CGFloat midX = CGRectGetMidX(contentRect);
|
||||
return CGRectMake(midX - size.width / 2, CGRectGetMaxY(imageRect) + _iconLabelGap, size.width, size.height);
|
||||
}
|
||||
- (CGSize)intrinsicContentSize {
|
||||
CGSize titleSize = [self titleRectForContentRect:CGRectZero].size;
|
||||
return CGSizeMake(MAX(_iconSize.width, titleSize.width), _iconSize.height + _iconLabelGap + titleSize.height);
|
||||
}
|
||||
- (void)setIconSize:(CGSize)iconSize {
|
||||
_iconSize = iconSize;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
- (void)setIconLabelGap:(CGFloat)iconLabelGap {
|
||||
_iconLabelGap = iconLabelGap;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaLabelCell : UICollectionViewCell
|
||||
@property(nullable, nonatomic) NSAttributedString *attributedText;
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
|
||||
+ (NSString *)reuseIdentifier;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaLabelCell.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface TUIMultimediaLabelCell () {
|
||||
UILabel *_label;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaLabelCell
|
||||
@dynamic attributedText;
|
||||
|
||||
+ (NSString *)reuseIdentifier {
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_label = [[UILabel alloc] init];
|
||||
[self.contentView addSubview:_label];
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attrText {
|
||||
return _label.attributedText;
|
||||
}
|
||||
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText {
|
||||
_label.attributedText = attributedText;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaPopupController : UIViewController
|
||||
@property(nullable, nonatomic) UIView *mainView;
|
||||
@property(nonatomic) float animeDuration;
|
||||
|
||||
- (BOOL)popupControllerWillCancel;
|
||||
- (void)popupControllerDidCanceled;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaPopupController.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface TUIMultimediaPopupController () {
|
||||
UIView *_popupView;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaPopupController
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
_animeDuration = 0.15;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
_popupView = [[UIView alloc] init];
|
||||
[self.view addSubview:_popupView];
|
||||
|
||||
UIView *cancelView = [[UIView alloc] init];
|
||||
[self.view addSubview:cancelView];
|
||||
|
||||
[_popupView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.view);
|
||||
make.top.equalTo(self.view.mas_bottom);
|
||||
}];
|
||||
[cancelView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.left.right.equalTo(self.view);
|
||||
make.bottom.equalTo(_popupView.mas_top);
|
||||
}];
|
||||
|
||||
UITapGestureRecognizer *rec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onCancelViewTap:)];
|
||||
rec.cancelsTouchesInView = NO;
|
||||
[cancelView addGestureRecognizer:rec];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[UIView animateWithDuration:_animeDuration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveLinear
|
||||
animations:^{
|
||||
[self->_popupView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.view);
|
||||
make.bottom.equalTo(self.view.mas_bottom);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
- (BOOL)popupControllerWillCancel {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)popupControllerDidCanceled {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
- (void)onCancelViewTap:(UITapGestureRecognizer *)rec {
|
||||
BOOL b = [self popupControllerWillCancel];
|
||||
if (b) {
|
||||
[UIView animateWithDuration:_animeDuration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveLinear
|
||||
animations:^{
|
||||
[self->_popupView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.view);
|
||||
make.top.equalTo(self.view.mas_bottom);
|
||||
}];
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self popupControllerDidCanceled];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMainView:(UIView *)mainView {
|
||||
if (_mainView != nil) {
|
||||
[_mainView removeFromSuperview];
|
||||
}
|
||||
_mainView = mainView;
|
||||
[_popupView addSubview:_mainView];
|
||||
[mainView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self->_popupView);
|
||||
}];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaSplitter : UIView
|
||||
@property(nonatomic) UILayoutConstraintAxis axis;
|
||||
@property(nonatomic) UIColor *color;
|
||||
@property(nonatomic) CGFloat lineWidth;
|
||||
@property(nonatomic) CGLineCap lineCap;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaSplitter.h"
|
||||
|
||||
@interface TUIMultimediaSplitter () {
|
||||
CAShapeLayer *_shapeLayer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaSplitter
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
_color = UIColor.lightGrayColor;
|
||||
_lineWidth = 1;
|
||||
_lineCap = kCGLineCapRound;
|
||||
self.backgroundColor = UIColor.clearColor;
|
||||
|
||||
_shapeLayer = [[CAShapeLayer alloc] init];
|
||||
[self.layer addSublayer:_shapeLayer];
|
||||
|
||||
[self updateShapeLayer];
|
||||
return self;
|
||||
}
|
||||
- (void)updateShapeLayer {
|
||||
_shapeLayer.frame = self.bounds;
|
||||
CGPoint startPoint, endPoint;
|
||||
CGSize size = self.bounds.size;
|
||||
CGFloat inset = 0;
|
||||
if (_axis == UILayoutConstraintAxisVertical) {
|
||||
startPoint = CGPointMake(size.width / 2, inset);
|
||||
endPoint = CGPointMake(size.width / 2, size.height - inset);
|
||||
} else {
|
||||
startPoint = CGPointMake(inset, size.height / 2);
|
||||
endPoint = CGPointMake(size.width - inset, size.height / 2);
|
||||
}
|
||||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||||
[path moveToPoint:startPoint];
|
||||
[path addLineToPoint:endPoint];
|
||||
_shapeLayer.path = path.CGPath;
|
||||
_shapeLayer.strokeColor = _color.CGColor;
|
||||
_shapeLayer.lineWidth = _lineWidth;
|
||||
switch (_lineCap) {
|
||||
default:
|
||||
case kCGLineCapButt:
|
||||
_shapeLayer.lineCap = kCALineCapButt;
|
||||
break;
|
||||
case kCGLineCapRound:
|
||||
_shapeLayer.lineCap = kCALineCapRound;
|
||||
break;
|
||||
case kCGLineCapSquare:
|
||||
_shapeLayer.lineCap = kCALineCapSquare;
|
||||
break;
|
||||
}
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[self updateShapeLayer];
|
||||
}
|
||||
- (void)setAxis:(UILayoutConstraintAxis)axis {
|
||||
_axis = axis;
|
||||
[self updateShapeLayer];
|
||||
}
|
||||
- (void)setColor:(UIColor *)color {
|
||||
_color = color;
|
||||
[self updateShapeLayer];
|
||||
}
|
||||
- (void)setLineWidth:(CGFloat)lineWidth {
|
||||
_lineWidth = lineWidth;
|
||||
[self updateShapeLayer];
|
||||
}
|
||||
- (void)setLineCap:(CGLineCap)lineCap {
|
||||
_lineCap = lineCap;
|
||||
[self updateShapeLayer];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TUIMultimediaTabPanelTab;
|
||||
|
||||
@protocol TUIMultimediaTabPanelDelegate;
|
||||
|
||||
@interface TUIMultimediaTabPanel : UIView
|
||||
@property(nonatomic) NSArray<TUIMultimediaTabPanelTab *> *tabs;
|
||||
@property(nonatomic) NSInteger selectedIndex;
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaTabPanelDelegate> delegate;
|
||||
- (id)initWithFrame:(CGRect)frame;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaTabPanelDelegate <NSObject>
|
||||
- (void)tabPanel:(TUIMultimediaTabPanel *)panel selectedIndexChanged:(NSInteger)selectedIndex;
|
||||
@end
|
||||
|
||||
@interface TUIMultimediaTabPanelTab : NSObject
|
||||
@property(nonatomic) UIView *view;
|
||||
@property(nullable, nonatomic) NSString *name;
|
||||
@property(nullable, nonatomic) UIImage *icon;
|
||||
- (instancetype)initWithName:(nullable NSString *)name icon:(nullable UIImage *)icon view:(UIView *)view;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaTabBarDelegate;
|
||||
|
||||
@interface TUIMultimediaTabBar : UIView
|
||||
@property(nonatomic) NSArray<id> *tabs;
|
||||
@property(nonatomic) NSInteger selectedIndex;
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaTabBarDelegate> delegate;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaTabBarDelegate <NSObject>
|
||||
- (void)tabBar:(TUIMultimediaTabBar *)bar selectedIndexChanged:(NSInteger)index;
|
||||
@end
|
||||
|
||||
@interface TUIMultimediaTabBarCell : UICollectionViewCell
|
||||
@property(nullable, nonatomic) NSAttributedString *attributedText;
|
||||
@property(nullable, nonatomic) UIImage *icon;
|
||||
@property(nonatomic) CGFloat padding;
|
||||
@property(nonatomic) BOOL barCellSelected;
|
||||
+ (NSString *)reuseIdentifier;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
286
TUIKit/TUIMultimediaPlugin/Common/View/TUIMultimediaTabPanel.m
Normal file
286
TUIKit/TUIMultimediaPlugin/Common/View/TUIMultimediaTabPanel.m
Normal file
@@ -0,0 +1,286 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaTabPanel.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/NSArray+Functional.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaImageUtil.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaSplitter.h"
|
||||
|
||||
@interface TUIMultimediaTabPanel () <TUIMultimediaTabBarDelegate> {
|
||||
TUIMultimediaTabBar *_bar;
|
||||
TUIMultimediaSplitter *_splitter;
|
||||
NSArray<TUIMultimediaTabPanelTab *> *_tabs;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaTabPanel
|
||||
|
||||
@dynamic tabs;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
[self initUI];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
_bar = [[TUIMultimediaTabBar alloc] init];
|
||||
[self addSubview:_bar];
|
||||
_bar.delegate = self;
|
||||
|
||||
_splitter = [[TUIMultimediaSplitter alloc] init];
|
||||
[self addSubview:_splitter];
|
||||
_splitter.lineWidth = 1;
|
||||
_splitter.color = TUIMultimediaPluginDynamicColor(@"tabpanel_splitter_color", @"#FFFFFF1A");
|
||||
|
||||
[_bar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(self).inset(5);
|
||||
make.height.mas_equalTo(42);
|
||||
}];
|
||||
[_splitter mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self);
|
||||
make.top.equalTo(_bar.mas_bottom);
|
||||
make.height.mas_equalTo(5);
|
||||
}];
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
- (NSInteger)selectedIndex {
|
||||
return _bar.selectedIndex;
|
||||
}
|
||||
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex {
|
||||
_bar.selectedIndex = selectedIndex;
|
||||
for (int i = 0; i < _tabs.count; i++) {
|
||||
TUIMultimediaTabPanelTab *t = _tabs[i];
|
||||
t.view.hidden = i != selectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<TUIMultimediaTabPanelTab *> *)tabs {
|
||||
return _tabs;
|
||||
}
|
||||
|
||||
- (void)setTabs:(NSArray<TUIMultimediaTabPanelTab *> *)value {
|
||||
if (_tabs != nil) {
|
||||
for (TUIMultimediaTabPanelTab *t in _tabs) {
|
||||
[t.view removeFromSuperview];
|
||||
}
|
||||
}
|
||||
_tabs = value;
|
||||
_bar.selectedIndex = -1;
|
||||
_bar.tabs = [value tui_multimedia_map:^id(TUIMultimediaTabPanelTab *t) {
|
||||
return t.icon == nil ? t.name : t.icon;
|
||||
}];
|
||||
for (int i = 0; i < _tabs.count; i++) {
|
||||
TUIMultimediaTabPanelTab *t = _tabs[i];
|
||||
t.view.hidden = YES;
|
||||
[self addSubview:t.view];
|
||||
[t.view mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.bottom.equalTo(self);
|
||||
make.top.equalTo(_splitter.mas_bottom);
|
||||
}];
|
||||
}
|
||||
if (_tabs.count > 0) {
|
||||
TUIMultimediaTabPanelTab *t = _tabs[0];
|
||||
_bar.selectedIndex = 0;
|
||||
t.view.hidden = NO;
|
||||
}
|
||||
}
|
||||
#pragma mark - TUIMultimediaTabBarDelegate protocol
|
||||
- (void)tabBar:(TUIMultimediaTabBar *)bar selectedIndexChanged:(NSInteger)index {
|
||||
for (int i = 0; i < _tabs.count; i++) {
|
||||
TUIMultimediaTabPanelTab *t = _tabs[i];
|
||||
t.view.hidden = i != index;
|
||||
}
|
||||
[_delegate tabPanel:self selectedIndexChanged:index];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIMultimediaTabPanelTab
|
||||
@implementation TUIMultimediaTabPanelTab {
|
||||
}
|
||||
- (instancetype)initWithName:(NSString *)name icon:(UIImage *)icon view:(UIView *)view {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_name = name;
|
||||
_icon = icon;
|
||||
_view = view;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - TUIMultimediaTabBar
|
||||
|
||||
@interface TUIMultimediaTabBar () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout> {
|
||||
UICollectionView *_collectionView;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaTabBar
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
[self initUI];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.minimumInteritemSpacing = 10;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.backgroundColor = UIColor.clearColor;
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
[_collectionView registerClass:TUIMultimediaTabBarCell.class forCellWithReuseIdentifier:TUIMultimediaTabBarCell.reuseIdentifier];
|
||||
[self addSubview:_collectionView];
|
||||
|
||||
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex {
|
||||
_selectedIndex = selectedIndex;
|
||||
[_collectionView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout protocol
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
|
||||
_selectedIndex = indexPath.item;
|
||||
[collectionView reloadData];
|
||||
|
||||
[_delegate tabBar:self selectedIndexChanged:_selectedIndex];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource protocol
|
||||
- (NSAttributedString *)getAttributedString:(NSString *)str selected:(BOOL)selected {
|
||||
UIColor *color;
|
||||
UIFont *font;
|
||||
if (selected) {
|
||||
color = UIColor.whiteColor;
|
||||
font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
|
||||
} else {
|
||||
color = [UIColor colorWithWhite:1 alpha:0.6];
|
||||
font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
|
||||
}
|
||||
NSAttributedString *text = [[NSAttributedString alloc] initWithString:str
|
||||
attributes:@{
|
||||
NSForegroundColorAttributeName : color,
|
||||
NSFontAttributeName : font,
|
||||
}];
|
||||
return text;
|
||||
}
|
||||
- (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
TUIMultimediaTabBarCell *cell = (TUIMultimediaTabBarCell *)[collectionView dequeueReusableCellWithReuseIdentifier:TUIMultimediaTabBarCell.reuseIdentifier
|
||||
forIndexPath:indexPath];
|
||||
cell.barCellSelected = indexPath.item == _selectedIndex;
|
||||
BOOL cellSelected = indexPath.item == _selectedIndex;
|
||||
id item = _tabs[indexPath.item];
|
||||
if ([item isKindOfClass:NSString.class]) {
|
||||
cell.attributedText = [self getAttributedString:item selected:cellSelected];
|
||||
} else if ([item isKindOfClass:UIImage.class]) {
|
||||
cell.contentView.backgroundColor = cellSelected ? [UIColor colorWithWhite:1 alpha:0.1] : UIColor.clearColor;
|
||||
cell.icon = item;
|
||||
cell.padding = 8;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView
|
||||
layout:(UICollectionViewLayout *)collectionViewLayout
|
||||
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
CGFloat h = _collectionView.bounds.size.height;
|
||||
CGSize size = CGSizeMake(h, h);
|
||||
id item = _tabs[indexPath.item];
|
||||
if ([item isKindOfClass:NSString.class]) {
|
||||
NSAttributedString *text = [self getAttributedString:_tabs[indexPath.item] selected:YES];
|
||||
CGSize textSize = [text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, _collectionView.bounds.size.height)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
context:nil]
|
||||
.size;
|
||||
size.width = MAX(size.width, textSize.width + 10);
|
||||
size.height = MAX(size.height, textSize.height + 8);
|
||||
return size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return _tabs.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIMultimediaTabBarCell
|
||||
@interface TUIMultimediaTabBarCell () {
|
||||
UILabel *_label;
|
||||
UIImageView *_imgView;
|
||||
}
|
||||
@end
|
||||
@implementation TUIMultimediaTabBarCell
|
||||
+ (NSString *)reuseIdentifier {
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
self.contentView.layer.cornerRadius = 5;
|
||||
self.contentView.clipsToBounds = YES;
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
[self.contentView addSubview:_label];
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
|
||||
_imgView = [[UIImageView alloc] init];
|
||||
[self.contentView addSubview:_imgView];
|
||||
_imgView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[_imgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
self.attributedText = nil;
|
||||
self.icon = nil;
|
||||
self.barCellSelected = NO;
|
||||
self.padding = 0;
|
||||
}
|
||||
- (NSAttributedString *)attributedText {
|
||||
return _label.attributedText;
|
||||
}
|
||||
- (UIImage *)icon {
|
||||
return _imgView.image;
|
||||
}
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText {
|
||||
_label.attributedText = attributedText;
|
||||
}
|
||||
- (void)setIcon:(UIImage *)icon {
|
||||
_imgView.image = icon;
|
||||
}
|
||||
- (void)setPadding:(CGFloat)padding {
|
||||
_padding = padding;
|
||||
[_label mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self).inset(_padding);
|
||||
}];
|
||||
[_imgView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self).inset(_padding);
|
||||
}];
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user