增加换肤功能
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIMultimediaEffectCell : UICollectionViewCell
|
||||
@property(nonatomic) UIImage *image;
|
||||
@property(nonatomic) NSString *text;
|
||||
@property(nonatomic) BOOL effectSelected;
|
||||
@property(nonatomic) CGSize iconSize;
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
|
||||
+ (NSString *)reuseIdentifier;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaEffectCell.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
|
||||
|
||||
const CGFloat MaskBorderWidth = 2;
|
||||
const CGFloat EffectCellRadius = 10;
|
||||
const CGFloat EffectCellWidth = 60;
|
||||
|
||||
const CGFloat LabelFontSize = 12;
|
||||
const CGFloat LabelHeight = 18;
|
||||
const CGFloat LabelInsectToBottom = 5;
|
||||
|
||||
@interface TUIMultimediaEffectCell () {
|
||||
UIView *_imgContainerView;
|
||||
UIView *_highlightView;
|
||||
UIImageView *_imgView;
|
||||
UILabel *_label;
|
||||
NSString *_text;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaEffectCell
|
||||
|
||||
@dynamic image;
|
||||
@dynamic text;
|
||||
|
||||
+ (NSString *)reuseIdentifier {
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
[self initUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
_imgContainerView = [[UIView alloc] init];
|
||||
[self.contentView addSubview:_imgContainerView];
|
||||
_imgContainerView.layer.cornerRadius = EffectCellRadius;
|
||||
_imgContainerView.clipsToBounds = YES;
|
||||
_imgView = [[UIImageView alloc] init];
|
||||
[_imgContainerView addSubview:_imgView];
|
||||
_imgView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[_imgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(_iconSize);
|
||||
make.center.equalTo(_imgContainerView);
|
||||
}];
|
||||
|
||||
_highlightView = [[UIView alloc] init];
|
||||
[self.contentView addSubview:_highlightView];
|
||||
_highlightView.hidden = YES;
|
||||
_highlightView.backgroundColor = [[TUIMultimediaConfig sharedInstance] getThemeColor];
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
_label.font = [UIFont systemFontOfSize:LabelFontSize];
|
||||
_label.textColor = UIColor.whiteColor;
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
[self.contentView addSubview:_label];
|
||||
|
||||
[_highlightView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
[_imgContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(self.contentView).inset(MaskBorderWidth);
|
||||
make.height.equalTo(_imgContainerView.mas_width);
|
||||
}];
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.contentView);
|
||||
make.bottom.equalTo(self.contentView);
|
||||
make.top.equalTo(_imgContainerView.mas_bottom);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self addMaskToHighlightView];
|
||||
}
|
||||
|
||||
- (void)addMaskToHighlightView {
|
||||
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_highlightView.bounds cornerRadius:EffectCellRadius];
|
||||
[maskPath appendPath:[UIBezierPath bezierPathWithRoundedRect:_imgContainerView.frame cornerRadius:EffectCellRadius].bezierPathByReversingPath];
|
||||
CAShapeLayer *layer = [[CAShapeLayer alloc] init];
|
||||
layer.path = maskPath.CGPath;
|
||||
_highlightView.layer.mask = layer;
|
||||
}
|
||||
|
||||
- (void)setIconSize:(CGSize)iconSize {
|
||||
_iconSize = iconSize;
|
||||
[_imgView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(_iconSize);
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIImage *)image {
|
||||
return _imgView.image;
|
||||
}
|
||||
- (void)setImage:(UIImage *)image {
|
||||
_imgView.image = image;
|
||||
}
|
||||
- (NSString *)text {
|
||||
return _text;
|
||||
}
|
||||
- (void)setText:(NSString *)text {
|
||||
_text = text;
|
||||
_label.text = text;
|
||||
}
|
||||
- (void)setEffectSelected:(BOOL)effectSelected {
|
||||
_effectSelected = effectSelected;
|
||||
_highlightView.hidden = !effectSelected;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUIMultimediaEffectCell.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaEffectItem.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TUIMultimediaEffectPanelDelegate;
|
||||
|
||||
/**
|
||||
美颜和滤镜设置界面
|
||||
*/
|
||||
@interface TUIMultimediaEffectPanel : UIView
|
||||
@property(nonatomic) NSArray<TUIMultimediaEffectItem *> *items;
|
||||
@property(nonatomic) NSInteger selectedIndex;
|
||||
@property(nonatomic) CGSize iconSize;
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaEffectPanelDelegate> delegate;
|
||||
- (id)initWithFrame:(CGRect)frame;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaEffectPanelDelegate <NSObject>
|
||||
- (void)effectPanelSelectionChanged:(TUIMultimediaEffectPanel *)panel;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaEffectPanel.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import "TUIMultimediaEffectCell.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaBeautifySettings.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
|
||||
static const CGSize EffectItemSize = TUIMultimediaConstCGSize(60, 86);
|
||||
|
||||
@interface TUIMultimediaEffectPanel () <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout> {
|
||||
NSArray<TUIMultimediaEffectItem *> *_items;
|
||||
UICollectionView *_collectionView;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaEffectPanel
|
||||
@dynamic items;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_selectedIndex = -1;
|
||||
_items = @[];
|
||||
[self initUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.minimumInteritemSpacing = 10;
|
||||
layout.itemSize = EffectItemSize;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.backgroundColor = UIColor.clearColor;
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
[_collectionView registerClass:TUIMultimediaEffectCell.class forCellWithReuseIdentifier:TUIMultimediaEffectCell.reuseIdentifier];
|
||||
[self addSubview:_collectionView];
|
||||
|
||||
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
}
|
||||
|
||||
- (CGSize)intrinsicContentSize {
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, EffectItemSize.height /* + self.safeAreaInsets.bottom*/);
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
- (NSArray<TUIMultimediaEffectItem *> *)items {
|
||||
return _items;
|
||||
}
|
||||
- (void)setItems:(NSArray<TUIMultimediaEffectItem *> *)value {
|
||||
_items = value;
|
||||
_selectedIndex = -1;
|
||||
[_collectionView reloadData];
|
||||
}
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex {
|
||||
_selectedIndex = selectedIndex;
|
||||
[_collectionView reloadData];
|
||||
}
|
||||
- (void)setIconSize:(CGSize)iconSize {
|
||||
_iconSize = iconSize;
|
||||
[_collectionView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout protocol
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TUIMultimediaEffectCell *cell = (TUIMultimediaEffectCell *)[collectionView dequeueReusableCellWithReuseIdentifier:TUIMultimediaEffectCell.reuseIdentifier
|
||||
forIndexPath:indexPath];
|
||||
cell.image = _items[indexPath.item].iconImage;
|
||||
cell.text = _items[indexPath.item].name;
|
||||
cell.effectSelected = (indexPath.item == _selectedIndex);
|
||||
cell.iconSize = _iconSize;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return _items.count;
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// 立刻反选此cell,不使用CollectionView自带的选中逻辑
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
|
||||
_selectedIndex = indexPath.item;
|
||||
[collectionView reloadData];
|
||||
|
||||
[_delegate effectPanelSelectionChanged:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaBeautifySettings.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TUIMultimediaBeautifyViewDelegate;
|
||||
|
||||
@interface TUIMultimediaBeautifyView : UIView
|
||||
@property(nonatomic) TUIMultimediaBeautifySettings *settings;
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaBeautifyViewDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
- (instancetype)initWithFrame:(CGRect)frame settings:(nullable TUIMultimediaBeautifySettings *)settings;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaBeautifyViewDelegate <NSObject>
|
||||
- (void)beautifyView:(TUIMultimediaBeautifyView *)beautifyView onSettingsChange:(TUIMultimediaBeautifySettings *)settings;
|
||||
@end
|
||||
|
||||
@interface TUIMultimediaMarker : UIView
|
||||
@property(nonatomic) NSString *text;
|
||||
- (void)showForDuration:(CGFloat)showSeconds withHideAnimeDuration:(CGFloat)hideAnimeSeconds;
|
||||
- (void)hide;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,259 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaBeautifyView.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <ReactiveObjC/RACEXTScope.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaEffectCell.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaEffectPanel.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaImageUtil.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaTabPanel.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
|
||||
|
||||
#pragma mark - TUIMultimediaBeautifyView
|
||||
@interface TUIMultimediaBeautifyView () <TUIMultimediaEffectPanelDelegate, TUIMultimediaTabPanelDelegate> {
|
||||
UIView *_topPanel;
|
||||
UILabel *_lbStrength;
|
||||
UIImageView *_imgViewCompare;
|
||||
UISlider *_slider;
|
||||
TUIMultimediaTabPanel *_tabPanel;
|
||||
TUIMultimediaEffectPanel *_effectPanelBeauty;
|
||||
TUIMultimediaEffectPanel *_effectPanelFilter;
|
||||
TUIMultimediaEffectItem *_selectedItem;
|
||||
TUIMultimediaMarker *_marker;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaBeautifyView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
return [self initWithFrame:frame settings:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame settings:(TUIMultimediaBeautifySettings *)settings {
|
||||
self = [super initWithFrame:frame];
|
||||
_settings = settings;
|
||||
if (_settings == nil) {
|
||||
_settings = [[TUIMultimediaBeautifySettings alloc] init];
|
||||
}
|
||||
[self initUI];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
self.opaque = NO;
|
||||
self.backgroundColor = UIColor.clearColor;
|
||||
|
||||
_topPanel = [[UIView alloc] init];
|
||||
_topPanel.hidden = YES;
|
||||
[self addSubview:_topPanel];
|
||||
[_topPanel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(self);
|
||||
make.height.mas_equalTo(52);
|
||||
}];
|
||||
|
||||
_marker = [[TUIMultimediaMarker alloc] init];
|
||||
[_topPanel addSubview:_marker];
|
||||
|
||||
_lbStrength = [[UILabel alloc] init];
|
||||
[_topPanel addSubview:_lbStrength];
|
||||
_lbStrength.text = [TUIMultimediaCommon localizedStringForKey:@"strength"];
|
||||
_lbStrength.textColor = UIColor.whiteColor;
|
||||
_lbStrength.font = [UIFont systemFontOfSize:16];
|
||||
|
||||
_imgViewCompare = [[UIImageView alloc] init];
|
||||
[_topPanel addSubview:_imgViewCompare];
|
||||
_imgViewCompare.image = TUIMultimediaPluginBundleThemeImage(@"beautify_effect_compare_img", @"effect_compare");
|
||||
|
||||
UIColor* themeColor = [[TUIMultimediaConfig sharedInstance] getThemeColor];
|
||||
_slider = [[UISlider alloc] init];
|
||||
[_topPanel addSubview:_slider];
|
||||
//_slider.thumbTintColor = TUIMultimediaPluginDynamicColor(@"theme_accent_dark_color", @"#006CFF");
|
||||
_slider.minimumValue = TUIMultimediaEffectSliderMin;
|
||||
_slider.maximumValue = TUIMultimediaEffectSliderMax;
|
||||
_slider.minimumTrackTintColor = themeColor;//TUIMultimediaPluginDynamicColor(@"theme_accent_dark_color", @"#006CFF");
|
||||
_slider.maximumTrackTintColor = TUIMultimediaPluginDynamicColor(@"beautify_slider_track_bg_color", @"#F4F5F9");
|
||||
UIImage *thumbImg = [TUIMultimediaImageUtil createBlueCircleWithWhiteBorder:CGSizeMake(24, 24) withColor:themeColor];
|
||||
[_slider setThumbImage:thumbImg forState:UIControlStateNormal];
|
||||
[_slider setThumbImage:thumbImg forState:UIControlStateHighlighted];
|
||||
[_slider addTarget:self action:@selector(onSliderValueChange) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
[_lbStrength mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_topPanel).inset(16);
|
||||
make.centerY.equalTo(_topPanel);
|
||||
}];
|
||||
[_imgViewCompare mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(_topPanel).inset(16);
|
||||
make.centerY.equalTo(_topPanel);
|
||||
make.width.height.mas_equalTo(30);
|
||||
}];
|
||||
[_slider mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_lbStrength.mas_right).inset(8);
|
||||
make.right.equalTo(_imgViewCompare.mas_left).inset(8);
|
||||
make.centerY.equalTo(_topPanel);
|
||||
make.height.mas_equalTo(30);
|
||||
}];
|
||||
|
||||
_effectPanelBeauty = [[TUIMultimediaEffectPanel alloc] init];
|
||||
_effectPanelBeauty.iconSize = CGSizeMake(32, 32);
|
||||
_effectPanelBeauty.delegate = self;
|
||||
_effectPanelBeauty.items = _settings.beautifyItems;
|
||||
|
||||
_effectPanelFilter = [[TUIMultimediaEffectPanel alloc] init];
|
||||
_effectPanelFilter.iconSize = CGSizeMake(56, 56);
|
||||
_effectPanelFilter.delegate = self;
|
||||
_effectPanelFilter.items = _settings.filterItems;
|
||||
_effectPanelFilter.selectedIndex = 0;
|
||||
|
||||
UIView *bottomPanel = [[UIView alloc] init];
|
||||
[self addSubview:bottomPanel];
|
||||
bottomPanel.backgroundColor = UIColor.blackColor;
|
||||
|
||||
_tabPanel = [[TUIMultimediaTabPanel alloc] initWithFrame:self.bounds];
|
||||
_tabPanel.delegate = self;
|
||||
_tabPanel.backgroundColor = UIColor.blackColor;
|
||||
_tabPanel.tabs = @[
|
||||
[[TUIMultimediaTabPanelTab alloc] initWithName:[TUIMultimediaCommon localizedStringForKey:@"beautify"] icon:nil view:_effectPanelBeauty],
|
||||
[[TUIMultimediaTabPanelTab alloc] initWithName:[TUIMultimediaCommon localizedStringForKey:@"filter"] icon:nil view:_effectPanelFilter],
|
||||
];
|
||||
[bottomPanel addSubview:_tabPanel];
|
||||
|
||||
[bottomPanel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(_topPanel.mas_bottom);
|
||||
make.left.right.bottom.equalTo(self);
|
||||
}];
|
||||
[_tabPanel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(bottomPanel);
|
||||
make.bottom.equalTo(bottomPanel.mas_safeAreaLayoutGuideBottom);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)effectPanelSelectionChanged:(TUIMultimediaEffectPanel *)panel {
|
||||
[_marker hide];
|
||||
if (panel.selectedIndex == -1 || panel.items[panel.selectedIndex].tag == TUIMultimediaEffectItemTagNone) {
|
||||
panel.selectedIndex = -1;
|
||||
_selectedItem = nil;
|
||||
_topPanel.hidden = YES;
|
||||
if (panel == _effectPanelFilter) {
|
||||
_settings.activeFilterIndex = -1;
|
||||
} else {
|
||||
for (TUIMultimediaEffectItem *item in _settings.beautifyItems) {
|
||||
item.strength = 0;
|
||||
}
|
||||
}
|
||||
[_delegate beautifyView:self onSettingsChange:_settings];
|
||||
return;
|
||||
}
|
||||
_selectedItem = panel.items[panel.selectedIndex];
|
||||
if (panel == _effectPanelFilter) {
|
||||
_settings.activeFilterIndex = panel.selectedIndex;
|
||||
_topPanel.hidden = NO;
|
||||
_slider.value = _selectedItem.strength;
|
||||
[_delegate beautifyView:self onSettingsChange:_settings];
|
||||
} else {
|
||||
_topPanel.hidden = NO;
|
||||
_slider.value = _selectedItem.strength;
|
||||
if ([@[ @(TUIMultimediaEffectItemTagSmooth), @(TUIMultimediaEffectItemTagNatural), @(TUIMultimediaEffectItemTagPitu) ] containsObject:@(_selectedItem.tag)]) {
|
||||
_settings.activeBeautifyTag = _selectedItem.tag;
|
||||
[_delegate beautifyView:self onSettingsChange:_settings];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tabPanel:(TUIMultimediaTabPanel *)panel selectedIndexChanged:(NSInteger)selectedIndex {
|
||||
TUIMultimediaEffectPanel *effectPanel = (TUIMultimediaEffectPanel *)panel.tabs[selectedIndex].view;
|
||||
[self effectPanelSelectionChanged:effectPanel];
|
||||
}
|
||||
|
||||
- (void)onSliderValueChange {
|
||||
_selectedItem.strength = _slider.value;
|
||||
|
||||
_marker.text = [NSString stringWithFormat:@"%d", (int)_slider.value];
|
||||
CGRect trackRect = [_slider trackRectForBounds:_slider.bounds];
|
||||
CGRect thumbRect = [_slider thumbRectForBounds:_slider.bounds trackRect:trackRect value:_slider.value];
|
||||
CGRect rect = [_topPanel convertRect:thumbRect fromView:_slider];
|
||||
[_marker mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(34);
|
||||
make.centerX.equalTo(_topPanel.mas_left).offset(CGRectGetMidX(rect));
|
||||
make.bottom.equalTo(_topPanel.mas_top).offset(rect.origin.y - 4);
|
||||
}];
|
||||
[_marker showForDuration:0.5 withHideAnimeDuration:0.5];
|
||||
|
||||
[_delegate beautifyView:self onSettingsChange:_settings];
|
||||
}
|
||||
|
||||
- (void)setSettings:(TUIMultimediaBeautifySettings *)settings {
|
||||
_effectPanelBeauty.items = _settings.beautifyItems;
|
||||
_effectPanelFilter.items = _settings.filterItems;
|
||||
_effectPanelFilter.selectedIndex = 0;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - TUIMultimediaMarker
|
||||
@interface TUIMultimediaMarker () {
|
||||
UIImageView *_imgView;
|
||||
UILabel *_label;
|
||||
dispatch_block_t hideBlock;
|
||||
}
|
||||
@end
|
||||
@implementation TUIMultimediaMarker
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
[self initUI];
|
||||
return self;
|
||||
}
|
||||
- (void)initUI {
|
||||
_imgView = [[UIImageView alloc] init];
|
||||
[self addSubview:_imgView];
|
||||
_imgView.image = TUIMultimediaPluginBundleThemeImage(@"beautify_marker_img", @"marker");
|
||||
[_imgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
[self addSubview:_label];
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
_label.textColor = UIColor.blackColor;
|
||||
_label.font = [UIFont systemFontOfSize:12];
|
||||
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self);
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
}
|
||||
- (NSString *)text {
|
||||
return _label.text;
|
||||
}
|
||||
- (void)setText:(NSString *)text {
|
||||
_label.text = text;
|
||||
}
|
||||
- (void)showForDuration:(CGFloat)showSeconds withHideAnimeDuration:(CGFloat)hideAnimeSeconds {
|
||||
self.alpha = 1;
|
||||
self.hidden = NO;
|
||||
if (hideBlock != nil) {
|
||||
dispatch_block_cancel(hideBlock);
|
||||
}
|
||||
@weakify(self);
|
||||
hideBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
|
||||
@strongify(self);
|
||||
[UIView animateWithDuration:hideAnimeSeconds
|
||||
animations:^{
|
||||
self.alpha = 0;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
self.alpha = 1;
|
||||
self.hidden = YES;
|
||||
}];
|
||||
});
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(showSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), hideBlock);
|
||||
}
|
||||
- (void)hide {
|
||||
if (hideBlock != nil) {
|
||||
dispatch_block_cancel(hideBlock);
|
||||
}
|
||||
self.alpha = 1;
|
||||
self.hidden = YES;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TUIMultimediaRecordButtonDelegate;
|
||||
|
||||
/**
|
||||
视频录制按钮
|
||||
*/
|
||||
@interface TUIMultimediaRecordButton : UIView
|
||||
@property(nonatomic) float progress;
|
||||
@property(nonatomic) float dotSizeNormal;
|
||||
@property(nonatomic) float progressSizeNormal;
|
||||
@property(nonatomic) float dotSizePressed;
|
||||
@property(nonatomic) float progressSizePressed;
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaRecordButtonDelegate> delegate;
|
||||
@property(nonatomic) BOOL isOnlySupportTakePhoto;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
@end
|
||||
|
||||
@protocol TUIMultimediaRecordButtonDelegate <NSObject>
|
||||
- (void)onRecordButtonTap:(TUIMultimediaRecordButton *)btn;
|
||||
- (void)onRecordButtonLongPressBegan:(TUIMultimediaRecordButton *)btn;
|
||||
- (void)onRecordButtonLongPressEnded:(TUIMultimediaRecordButton *)btn;
|
||||
- (void)onRecordButtonLongPressCancelled:(TUIMultimediaRecordButton *)btn;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaRecordButton.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCircleProgressView.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
|
||||
|
||||
static const CGFloat RecordAnimeDuration = 0.3;
|
||||
|
||||
#pragma mark - TUIMultimediaRecordButton
|
||||
@interface TUIMultimediaRecordButton () {
|
||||
TUIMultimediaCircleProgressView *_progressView;
|
||||
UIView *_dotView;
|
||||
BOOL _pressed;
|
||||
UILongPressGestureRecognizer *_longPressRec;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaRecordButton
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
[self initUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initUI {
|
||||
_progressView = [[TUIMultimediaCircleProgressView alloc] init];
|
||||
_progressView.lineCap = kCALineCapButt;
|
||||
_progressView.progressBgColor = TUIMultimediaPluginDynamicColor(@"record_btn_progress_bg_color", @"#FFFFFF");
|
||||
_progressView.progressColor = [[TUIMultimediaConfig sharedInstance] getThemeColor];
|
||||
_progressView.width = 2;
|
||||
[self addSubview:_progressView];
|
||||
|
||||
_dotView = [[UIView alloc] init];
|
||||
_dotView.backgroundColor = TUIMultimediaPluginDynamicColor(@"record_btn_dot_color", @"#FFFFFF");
|
||||
[self addSubview:_dotView];
|
||||
|
||||
UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
|
||||
tapRec.cancelsTouchesInView = NO;
|
||||
[self addGestureRecognizer:tapRec];
|
||||
|
||||
_longPressRec = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)];
|
||||
_longPressRec.cancelsTouchesInView = NO;
|
||||
_longPressRec.minimumPressDuration = RecordAnimeDuration;
|
||||
[self addGestureRecognizer:_longPressRec];
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
CGFloat dotSize = _pressed ? _dotSizePressed : _dotSizeNormal;
|
||||
|
||||
CGFloat progressSize = _pressed ? _progressSizePressed : _progressSizeNormal;
|
||||
if (_isOnlySupportTakePhoto) {
|
||||
progressSize = _progressSizeNormal;
|
||||
}
|
||||
|
||||
CGPoint center = CGPointMake(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2);
|
||||
CGFloat len = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
|
||||
_progressView.center = center;
|
||||
_progressView.bounds = CGRectMake(0, 0, len, len);
|
||||
_progressView.transform = CGAffineTransformMakeScale(progressSize / len, progressSize / len);
|
||||
|
||||
_dotView.center = center;
|
||||
_dotView.bounds = CGRectMake(0, 0, dotSize, dotSize);
|
||||
_dotView.layer.cornerRadius = dotSize / 2;
|
||||
}
|
||||
|
||||
- (void)animeStartRecord {
|
||||
_progressView.width = 4;
|
||||
[UIView animateWithDuration:RecordAnimeDuration
|
||||
animations:^{
|
||||
self->_pressed = YES;
|
||||
[self layoutSubviews];
|
||||
}];
|
||||
}
|
||||
- (void)animeStopRecord {
|
||||
_progressView.width = 2;
|
||||
[UIView animateWithDuration:RecordAnimeDuration
|
||||
animations:^{
|
||||
self->_pressed = NO;
|
||||
[self layoutSubviews];
|
||||
}];
|
||||
}
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
[self animeStartRecord];
|
||||
}
|
||||
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
|
||||
[super touchesCancelled:touches withEvent:event];
|
||||
[self animeStopRecord];
|
||||
}
|
||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
[super touchesEnded:touches withEvent:event];
|
||||
[self animeStopRecord];
|
||||
}
|
||||
- (void)onTap:(UITapGestureRecognizer *)rec {
|
||||
[_delegate onRecordButtonTap:self];
|
||||
}
|
||||
- (void)onLongPress:(UILongPressGestureRecognizer *)rec {
|
||||
switch (rec.state) {
|
||||
case UIGestureRecognizerStateBegan: {
|
||||
[_delegate onRecordButtonLongPressBegan:self];
|
||||
break;
|
||||
}
|
||||
case UIGestureRecognizerStateEnded: {
|
||||
[_delegate onRecordButtonLongPressEnded:self];
|
||||
break;
|
||||
}
|
||||
case UIGestureRecognizerStateCancelled: {
|
||||
[self animeStopRecord];
|
||||
[_delegate onRecordButtonLongPressCancelled:self];
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProgress:(float)progress {
|
||||
[_progressView setProgress:progress animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaBeautifySettings.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TUIMultimediaRecordControlView;
|
||||
|
||||
typedef NS_ENUM(NSInteger, TUIMultimediaRecordAspectRatio) {
|
||||
TUIMultimediaRecordAspectRatio1_1,
|
||||
TUIMultimediaRecordAspectRatio3_4,
|
||||
TUIMultimediaRecordAspectRatio4_3,
|
||||
TUIMultimediaRecordAspectRatio9_16,
|
||||
TUIMultimediaRecordAspectRatio16_9,
|
||||
};
|
||||
typedef void (^TUIMultimediaRecordControlCallback)(TUIMultimediaRecordControlView *);
|
||||
|
||||
@protocol TUIMultimediaRecordControlViewDelegate <NSObject>
|
||||
- (void)recordControlViewOnRecordStart;
|
||||
- (void)recordControlViewOnRecordFinish;
|
||||
- (void)recordControlViewPhoto;
|
||||
- (void)recordControlViewOnFlashStateChange:(BOOL)flashState;
|
||||
- (void)recordControlViewOnAspectChange:(TUIMultimediaRecordAspectRatio)aspect;
|
||||
- (void)recordControlViewOnExit;
|
||||
- (void)recordControlViewOnCameraSwicth:(BOOL)isUsingFrontCamera;
|
||||
- (void)recordControlViewOnBeautify;
|
||||
@end
|
||||
|
||||
/**
|
||||
包含视频录制页面的各种控制按钮
|
||||
*/
|
||||
@interface TUIMultimediaRecordControlView : UIView
|
||||
@property(nonatomic) BOOL flashState;
|
||||
@property(nonatomic) TUIMultimediaRecordAspectRatio aspectRatio;
|
||||
@property(nonatomic) BOOL isUsingFrontCamera;
|
||||
@property(readonly, nonatomic) UIView *previewView;
|
||||
@property(nonatomic) TUIMultimediaBeautifySettings *beautifySettings;
|
||||
@property(nonatomic) BOOL recordTipHidden;
|
||||
|
||||
@property(weak, nullable, nonatomic) id<TUIMultimediaRecordControlViewDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame isOnlySupportTakePhoto:(BOOL)isOnlySupportTakePhoto;
|
||||
- (instancetype)initWithFrame:(CGRect)frame isOnlySupportTakePhoto:(BOOL)isOnlySupportTakePhoto beautifySettings:(TUIMultimediaBeautifySettings *)beautifySettings;
|
||||
|
||||
- (void)setProgress:(float)progress duration:(float)duration;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,408 @@
|
||||
// Copyright (c) 2024 Tencent. All rights reserved.
|
||||
// Author: eddardliu
|
||||
|
||||
#import "TUIMultimediaRecordControlView.h"
|
||||
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <TUICore/NSDictionary+TUISafe.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaIconLabelButton.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaRecordButton.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
|
||||
#import "TUIMultimediaPlugin/TUIMultimediaAuthorizationPrompter.h"
|
||||
|
||||
#pragma mark - UI relative constants
|
||||
const static CGFloat BtnStartRecordSize = 72;
|
||||
const static CGFloat BtnStartRecordGapBottom = 15;
|
||||
const static CGFloat BtnStartRecordDotSizeNormal = 56;
|
||||
const static CGFloat BtnStartRecordDotSizePressed = 20;
|
||||
const static CGFloat BtnStartRecordProgressSizeNormal = 72;
|
||||
const static CGFloat BtnStartRecordProgressSizePressed = 80;
|
||||
|
||||
const static CGSize BtnExitRecordSize = TUIMultimediaConstCGSize(28, 28);
|
||||
const static CGFloat BtnExitRecordGapToStartRecord = 55;
|
||||
|
||||
const static CGSize BtnCameraSwitch = TUIMultimediaConstCGSize(28, 28);
|
||||
const static CGFloat BtnCameraSwitchGapToStartRecord = 55;
|
||||
|
||||
const static CGFloat FunctionBtnToToTop = 64;
|
||||
const static CGFloat FunctionBtnToRight = 16;
|
||||
|
||||
const static CGSize BtnExtendFunctionIconSize = TUIMultimediaConstCGSize(28, 28);
|
||||
const static CGFloat BtnExtendFunctionIconTextGap = 4;
|
||||
const static CGFloat BtnExtendFunctionGap = 24;
|
||||
|
||||
const static BOOL ShowDurationLabel = YES;
|
||||
|
||||
#pragma mark - TUIMultimediaRecordControlView
|
||||
|
||||
@interface TUIMultimediaRecordControlView () <TUIMultimediaRecordButtonDelegate> {
|
||||
TUIMultimediaRecordButton *_btnRecord;
|
||||
UIButton *_btnExitRecord;
|
||||
UIButton *_btnCameraSwitch;
|
||||
UIButton *_btnFlash;
|
||||
UIButton *_btnBeautify;
|
||||
UIButton *_btnAspect;
|
||||
UIButton *_lastFuncitonBtn;
|
||||
UILabel *_lbDuration;
|
||||
UILabel *_lbTip;
|
||||
BOOL _isOnlySupportTakePhoto;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIMultimediaRecordControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame isOnlySupportTakePhoto:(BOOL)isOnlySupportTakePhoto {
|
||||
return [self initWithFrame:frame isOnlySupportTakePhoto:isOnlySupportTakePhoto beautifySettings:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame isOnlySupportTakePhoto:(BOOL) isOnlySupportTakePhoto beautifySettings:(TUIMultimediaBeautifySettings *)beautifySettings {
|
||||
self = [super initWithFrame:frame];
|
||||
_isUsingFrontCamera = NO;
|
||||
_flashState = NO;
|
||||
_aspectRatio = TUIMultimediaRecordAspectRatio9_16;
|
||||
_beautifySettings = beautifySettings;
|
||||
_isOnlySupportTakePhoto = isOnlySupportTakePhoto;
|
||||
if (_beautifySettings == nil) {
|
||||
_beautifySettings = [[TUIMultimediaBeautifySettings alloc] init];
|
||||
}
|
||||
[self initUI];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setProgress:(float)progress duration:(float)duration {
|
||||
[_btnRecord setProgress:progress];
|
||||
int m = floor(duration / 60);
|
||||
int s = floor(duration - m * 60);
|
||||
_lbDuration.text = [NSString stringWithFormat:@"%02d:%02d", m, s];
|
||||
}
|
||||
#pragma mark - UI Init
|
||||
|
||||
- (void)initUI {
|
||||
_previewView = [[UIView alloc] init];
|
||||
[self addSubview:_previewView];
|
||||
[_previewView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self);
|
||||
make.width.equalTo(self);
|
||||
make.height.equalTo(_previewView.mas_width).multipliedBy(16.0 / 9.0);
|
||||
}];
|
||||
|
||||
// 防止 _lbDuration 直接与 _previewView 部分重叠
|
||||
UIView *_bottomMaskView = [[UIView alloc] init];
|
||||
[self addSubview:_bottomMaskView];
|
||||
_bottomMaskView.backgroundColor = UIColor.blackColor;
|
||||
|
||||
[self initControlButtons];
|
||||
[self initFunctionButtons];
|
||||
|
||||
_lbDuration = [[UILabel alloc] init];
|
||||
[self addSubview:_lbDuration];
|
||||
_lbDuration.hidden = YES;
|
||||
_lbDuration.text = @"00:00";
|
||||
_lbDuration.font = [UIFont monospacedSystemFontOfSize:18 weight:UIFontWeightMedium];
|
||||
_lbDuration.textColor = UIColor.whiteColor;
|
||||
[_lbDuration mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.equalTo(_btnRecord.mas_top).inset(8);
|
||||
make.centerX.equalTo(_btnRecord);
|
||||
}];
|
||||
|
||||
[_bottomMaskView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.bottom.equalTo(self);
|
||||
make.top.equalTo(_lbDuration.mas_top).offset(-8);
|
||||
}];
|
||||
|
||||
_lbTip = [[UILabel alloc] init];
|
||||
[self addSubview:_lbTip];
|
||||
if (_isOnlySupportTakePhoto) {
|
||||
_lbTip.text = [TUIMultimediaCommon localizedStringForKey:@"record_photo_tip"];
|
||||
} else {
|
||||
_lbTip.text = [TUIMultimediaCommon localizedStringForKey:@"record_tip"];
|
||||
}
|
||||
|
||||
_lbTip.font = [UIFont systemFontOfSize:16];
|
||||
_lbTip.textColor = UIColor.whiteColor;
|
||||
[_lbTip mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.lessThanOrEqualTo(_previewView).inset(16);
|
||||
make.bottom.lessThanOrEqualTo(_bottomMaskView.mas_top).offset(-16);
|
||||
make.centerX.equalTo(self);
|
||||
}];
|
||||
}
|
||||
|
||||
// 下方的控制按钮
|
||||
- (void)initControlButtons {
|
||||
_btnRecord = [[TUIMultimediaRecordButton alloc] init];
|
||||
[self addSubview:_btnRecord];
|
||||
_btnRecord.dotSizeNormal = BtnStartRecordDotSizeNormal;
|
||||
_btnRecord.dotSizePressed = BtnStartRecordDotSizePressed;
|
||||
_btnRecord.progressSizeNormal = BtnStartRecordProgressSizeNormal;
|
||||
_btnRecord.progressSizePressed = BtnStartRecordProgressSizePressed;
|
||||
_btnRecord.isOnlySupportTakePhoto = _isOnlySupportTakePhoto;
|
||||
_btnRecord.delegate = self;
|
||||
_btnExitRecord = [self newCustomButtonWithImage:TUIMultimediaPluginBundleThemeImage(@"record_exit_img", @"cross") onTouchUpInside:@selector(onBtnExitClick)];
|
||||
_btnCameraSwitch = [self newCustomButtonWithImage:TUIMultimediaPluginBundleThemeImage(@"record_camera_switch_img", @"camera_switch")
|
||||
onTouchUpInside:@selector(onBtnCameraSwitchClick)];
|
||||
|
||||
[_btnRecord mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(BtnStartRecordSize);
|
||||
make.centerX.equalTo(self);
|
||||
make.bottom.equalTo(self.mas_safeAreaLayoutGuideBottom).inset(BtnStartRecordGapBottom);
|
||||
}];
|
||||
[_btnExitRecord mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(BtnExitRecordSize);
|
||||
make.centerY.equalTo(_btnRecord);
|
||||
make.right.equalTo(_btnRecord.mas_left).inset(BtnExitRecordGapToStartRecord);
|
||||
}];
|
||||
[_btnCameraSwitch mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(BtnCameraSwitch);
|
||||
make.centerY.equalTo(_btnRecord);
|
||||
make.left.equalTo(_btnRecord.mas_right).inset(BtnCameraSwitchGapToStartRecord);
|
||||
}];
|
||||
}
|
||||
|
||||
// 右上角的功能按钮
|
||||
- (void)initFunctionButtons {
|
||||
[self initTorchView];
|
||||
[self initBeautyView];
|
||||
[self initAspectView];
|
||||
}
|
||||
|
||||
- (void) initTorchView {
|
||||
if (![[TUIMultimediaConfig sharedInstance] isSupportRecordTorch]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_btnFlash = [self newFunctionButtonWithImage:TUIMultimediaPluginBundleThemeImage(@"record_flash_close_img", @"flash_close")
|
||||
title:[TUIMultimediaCommon localizedStringForKey:@"flash"]
|
||||
onTouchUpInside:@selector(onBtnFlashClick)];
|
||||
|
||||
[_btnFlash mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self).inset(FunctionBtnToRight);
|
||||
make.top.equalTo(self).inset(FunctionBtnToToTop);
|
||||
}];
|
||||
|
||||
_lastFuncitonBtn = _btnFlash;
|
||||
}
|
||||
|
||||
- (void) initBeautyView {
|
||||
if (![[TUIMultimediaConfig sharedInstance] isSupportRecordBeauty]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_btnBeautify = [self newFunctionButtonWithImage:TUIMultimediaPluginBundleThemeImage(@"record_beautify_img", @"beauty_record")
|
||||
title:[TUIMultimediaCommon localizedStringForKey:@"beautify"]
|
||||
onTouchUpInside:@selector(onBtnBeautifyClick)];
|
||||
|
||||
[_btnBeautify mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
if (_lastFuncitonBtn == nil) {
|
||||
make.top.equalTo(self).inset(FunctionBtnToToTop);
|
||||
make.right.equalTo(self).inset(FunctionBtnToRight);
|
||||
} else {
|
||||
make.centerX.equalTo(_lastFuncitonBtn);
|
||||
make.top.equalTo(_lastFuncitonBtn.mas_bottom).inset(BtnExtendFunctionGap);
|
||||
}
|
||||
_lastFuncitonBtn = _btnBeautify;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) initAspectView {
|
||||
if (![[TUIMultimediaConfig sharedInstance] isSupportRecordAspect]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_btnAspect = [self newFunctionButtonWithImage:TUIMultimediaPluginBundleThemeImage(@"record_aspect_9_16_img", @"record_aspect_9_16")
|
||||
title:[TUIMultimediaCommon localizedStringForKey:@"aspect"]
|
||||
onTouchUpInside:@selector(onBtnAspectClick)];
|
||||
|
||||
[_btnAspect mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
if (_lastFuncitonBtn == nil) {
|
||||
make.top.equalTo(self).inset(FunctionBtnToToTop);
|
||||
make.right.equalTo(self).inset(FunctionBtnToRight);
|
||||
} else {
|
||||
make.centerX.equalTo(_lastFuncitonBtn);
|
||||
make.top.equalTo(_lastFuncitonBtn.mas_bottom).inset(BtnExtendFunctionGap);
|
||||
}
|
||||
_lastFuncitonBtn = _btnBeautify;
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIButton *)newFunctionButtonWithImage:(UIImage *)img title:(NSString *)title onTouchUpInside:(SEL)sel {
|
||||
TUIMultimediaIconLabelButton *btn = [TUIMultimediaIconLabelButton buttonWithType:UIButtonTypeCustom];
|
||||
[btn setImage:img forState:UIControlStateNormal];
|
||||
[btn setAttributedTitle:[[NSAttributedString alloc]
|
||||
initWithString:title
|
||||
attributes:@{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:12],
|
||||
NSForegroundColorAttributeName : TUIMultimediaPluginDynamicColor(@"record_func_btn_text_color", @"#FFFFFF"),
|
||||
}]
|
||||
forState:UIControlStateNormal];
|
||||
[btn addTarget:self action:sel forControlEvents:UIControlEventTouchUpInside];
|
||||
btn.iconSize = BtnExtendFunctionIconSize;
|
||||
btn.iconLabelGap = BtnExtendFunctionIconTextGap;
|
||||
[self addSubview:btn];
|
||||
return btn;
|
||||
}
|
||||
- (UIButton *)newCustomButtonWithImage:(nullable UIImage *)image onTouchUpInside:(nullable SEL)sel {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[btn setImage:image forState:UIControlStateNormal];
|
||||
if (sel != nil) {
|
||||
[btn addTarget:self action:sel forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
[self addSubview:btn];
|
||||
return btn;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
- (void)onBtnExitClick {
|
||||
[_delegate recordControlViewOnExit];
|
||||
}
|
||||
|
||||
- (void)onBtnCameraSwitchClick {
|
||||
if (_isUsingFrontCamera) {
|
||||
_isUsingFrontCamera = NO;
|
||||
_btnFlash.enabled = YES;
|
||||
} else {
|
||||
_isUsingFrontCamera = YES;
|
||||
_btnFlash.enabled = NO;
|
||||
[self setFlashState:NO];
|
||||
}
|
||||
[_delegate recordControlViewOnCameraSwicth:_isUsingFrontCamera];
|
||||
}
|
||||
|
||||
- (void)onBtnFlashClick {
|
||||
if (_isUsingFrontCamera) {
|
||||
return;
|
||||
}
|
||||
[self setFlashState:!_flashState];
|
||||
[_delegate recordControlViewOnFlashStateChange:_flashState];
|
||||
}
|
||||
|
||||
- (void)onBtnAspectClick {
|
||||
if (_aspectRatio == TUIMultimediaRecordAspectRatio9_16) {
|
||||
_aspectRatio = TUIMultimediaRecordAspectRatio3_4;
|
||||
[_btnAspect setImage:TUIMultimediaPluginBundleThemeImage(@"record_aspect_3_4_img", @"record_aspect_3_4") forState:UIControlStateNormal];
|
||||
[_previewView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(self);
|
||||
make.width.equalTo(self);
|
||||
make.height.equalTo(_previewView.mas_width).multipliedBy(4.0 / 3.0);
|
||||
}];
|
||||
} else {
|
||||
_aspectRatio = TUIMultimediaRecordAspectRatio9_16;
|
||||
[_btnAspect setImage:TUIMultimediaPluginBundleThemeImage(@"record_aspect_9_16_img", @"record_aspect_9_16") forState:UIControlStateNormal];
|
||||
[_previewView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self);
|
||||
make.width.equalTo(self);
|
||||
make.height.equalTo(_previewView.mas_width).multipliedBy(16.0 / 9.0);
|
||||
}];
|
||||
}
|
||||
[_delegate recordControlViewOnAspectChange:_aspectRatio];
|
||||
}
|
||||
|
||||
- (void)onBtnBeautifyClick {
|
||||
[_delegate recordControlViewOnBeautify];
|
||||
}
|
||||
|
||||
#pragma mark - TUIMultimediaRecordButtonDelegate protocol
|
||||
- (void)onRecordButtonLongPressBegan:(TUIMultimediaRecordButton *)btn {
|
||||
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:self.delegate]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isOnlySupportTakePhoto) {
|
||||
[_delegate recordControlViewOnRecordStart];
|
||||
_lbDuration.hidden = !ShowDurationLabel;
|
||||
} else {
|
||||
_lbDuration.hidden = YES;
|
||||
}
|
||||
|
||||
_lbTip.hidden = YES;
|
||||
_btnExitRecord.hidden = YES;
|
||||
_btnCameraSwitch.hidden = YES;
|
||||
|
||||
if (_btnFlash != nil) {
|
||||
_btnFlash.hidden = YES;
|
||||
}
|
||||
if (_btnBeautify != nil) {
|
||||
_btnBeautify.hidden = YES;
|
||||
}
|
||||
if (_btnAspect != nil) {
|
||||
_btnAspect.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onRecordButtonLongPressEnded:(TUIMultimediaRecordButton *)btn {
|
||||
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:nil]) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_isOnlySupportTakePhoto) {
|
||||
[_delegate recordControlViewOnRecordFinish];
|
||||
} else {
|
||||
[_delegate recordControlViewPhoto];
|
||||
}
|
||||
|
||||
_lbDuration.hidden = YES;
|
||||
|
||||
_lbTip.hidden = NO;
|
||||
_btnExitRecord.hidden = NO;
|
||||
_btnCameraSwitch.hidden = NO;
|
||||
if (_btnFlash != nil) {
|
||||
_btnFlash.hidden = NO;
|
||||
}
|
||||
if (_btnBeautify != nil) {
|
||||
_btnBeautify.hidden = NO;
|
||||
}
|
||||
if (_btnAspect != nil) {
|
||||
_btnAspect.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onRecordButtonLongPressCancelled:(TUIMultimediaRecordButton *)btn {
|
||||
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:nil]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isOnlySupportTakePhoto) {
|
||||
[_delegate recordControlViewOnRecordFinish];
|
||||
}
|
||||
|
||||
_lbDuration.hidden = YES;
|
||||
|
||||
_lbTip.hidden = NO;
|
||||
_btnExitRecord.hidden = NO;
|
||||
_btnCameraSwitch.hidden = NO;
|
||||
if (_btnFlash != nil) {
|
||||
_btnFlash.hidden = NO;
|
||||
}
|
||||
if (_btnBeautify != nil) {
|
||||
_btnBeautify.hidden = NO;
|
||||
}
|
||||
if (_btnAspect != nil) {
|
||||
_btnAspect.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onRecordButtonTap:(TUIMultimediaRecordButton *)btn {
|
||||
[_delegate recordControlViewPhoto];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
- (void)setFlashState:(BOOL)flashState {
|
||||
_flashState = flashState;
|
||||
if (_flashState) {
|
||||
[_btnFlash setImage:TUIMultimediaPluginBundleThemeImage(@"record_flash_open_img", @"flash_open") forState:UIControlStateNormal];
|
||||
} else {
|
||||
[_btnFlash setImage:TUIMultimediaPluginBundleThemeImage(@"record_flash_close_img", @"flash_close") forState:UIControlStateNormal];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)recordTipHidden {
|
||||
return _lbTip.hidden;
|
||||
}
|
||||
|
||||
- (void)setRecordTipHidden:(BOOL)recordTipHidden {
|
||||
_lbTip.hidden = recordTipHidden;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user