Commit 5d6abfa4 cgx

完成音频播放UI

1 个父辈 f86335be
正在显示 75 个修改的文件 包含 1360 行增加14 行删除
...@@ -158,6 +158,8 @@ ...@@ -158,6 +158,8 @@
D0F80907280431100097899F /* UILabel+Extras.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F80906280431100097899F /* UILabel+Extras.m */; }; D0F80907280431100097899F /* UILabel+Extras.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F80906280431100097899F /* UILabel+Extras.m */; };
D0F82286280C44D10039F586 /* SetTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F82285280C44D10039F586 /* SetTableView.m */; }; D0F82286280C44D10039F586 /* SetTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F82285280C44D10039F586 /* SetTableView.m */; };
D0F9AC542826563400FD7A3B /* MusicPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F9AC532826563400FD7A3B /* MusicPlayerController.m */; }; D0F9AC542826563400FD7A3B /* MusicPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F9AC532826563400FD7A3B /* MusicPlayerController.m */; };
D0F9AC582826602400FD7A3B /* SPButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F9AC572826602400FD7A3B /* SPButton.m */; };
D0F9AC5E282660CC00FD7A3B /* MusicPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F9AC5D282660CC00FD7A3B /* MusicPlayerView.m */; };
D0FAC41C281B817D00D4B859 /* GKLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC406281B817D00D4B859 /* GKLoadingView.m */; }; D0FAC41C281B817D00D4B859 /* GKLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC406281B817D00D4B859 /* GKLoadingView.m */; };
D0FAC41D281B817D00D4B859 /* GKPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC40C281B817D00D4B859 /* GKPhotoBrowser.m */; }; D0FAC41D281B817D00D4B859 /* GKPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC40C281B817D00D4B859 /* GKPhotoBrowser.m */; };
D0FAC41E281B817D00D4B859 /* GKPhotoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC40F281B817D00D4B859 /* GKPhotoManager.m */; }; D0FAC41E281B817D00D4B859 /* GKPhotoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FAC40F281B817D00D4B859 /* GKPhotoManager.m */; };
...@@ -463,6 +465,10 @@ ...@@ -463,6 +465,10 @@
D0F82285280C44D10039F586 /* SetTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SetTableView.m; sourceTree = "<group>"; }; D0F82285280C44D10039F586 /* SetTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SetTableView.m; sourceTree = "<group>"; };
D0F9AC522826563400FD7A3B /* MusicPlayerController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicPlayerController.h; sourceTree = "<group>"; }; D0F9AC522826563400FD7A3B /* MusicPlayerController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicPlayerController.h; sourceTree = "<group>"; };
D0F9AC532826563400FD7A3B /* MusicPlayerController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicPlayerController.m; sourceTree = "<group>"; }; D0F9AC532826563400FD7A3B /* MusicPlayerController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicPlayerController.m; sourceTree = "<group>"; };
D0F9AC562826602400FD7A3B /* SPButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPButton.h; sourceTree = "<group>"; };
D0F9AC572826602400FD7A3B /* SPButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPButton.m; sourceTree = "<group>"; };
D0F9AC5C282660CC00FD7A3B /* MusicPlayerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicPlayerView.h; sourceTree = "<group>"; };
D0F9AC5D282660CC00FD7A3B /* MusicPlayerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicPlayerView.m; sourceTree = "<group>"; };
D0FAC406281B817D00D4B859 /* GKLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLoadingView.m; sourceTree = "<group>"; }; D0FAC406281B817D00D4B859 /* GKLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLoadingView.m; sourceTree = "<group>"; };
D0FAC407281B817D00D4B859 /* GKWebImageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKWebImageProtocol.h; sourceTree = "<group>"; }; D0FAC407281B817D00D4B859 /* GKWebImageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKWebImageProtocol.h; sourceTree = "<group>"; };
D0FAC408281B817D00D4B859 /* GKPhotoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKPhotoManager.h; sourceTree = "<group>"; }; D0FAC408281B817D00D4B859 /* GKPhotoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKPhotoManager.h; sourceTree = "<group>"; };
...@@ -1003,6 +1009,7 @@ ...@@ -1003,6 +1009,7 @@
D0E9408127FE961300D57495 /* Vendors */ = { D0E9408127FE961300D57495 /* Vendors */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D0F9AC552826602400FD7A3B /* SPButton */,
D01814D927FFD91100583D4E /* DataSource */, D01814D927FFD91100583D4E /* DataSource */,
D01814CA27FFCBAF00583D4E /* CWCarousel */, D01814CA27FFCBAF00583D4E /* CWCarousel */,
D046FDF528100342000295AC /* UMSocial_6.10.4 */, D046FDF528100342000295AC /* UMSocial_6.10.4 */,
...@@ -1054,6 +1061,8 @@ ...@@ -1054,6 +1061,8 @@
D055BECA28252E4000BC11A4 /* SubAudioModel.m */, D055BECA28252E4000BC11A4 /* SubAudioModel.m */,
D0F9AC522826563400FD7A3B /* MusicPlayerController.h */, D0F9AC522826563400FD7A3B /* MusicPlayerController.h */,
D0F9AC532826563400FD7A3B /* MusicPlayerController.m */, D0F9AC532826563400FD7A3B /* MusicPlayerController.m */,
D0F9AC5C282660CC00FD7A3B /* MusicPlayerView.h */,
D0F9AC5D282660CC00FD7A3B /* MusicPlayerView.m */,
); );
path = Home; path = Home;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -1115,6 +1124,15 @@ ...@@ -1115,6 +1124,15 @@
path = FallAsleep; path = FallAsleep;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D0F9AC552826602400FD7A3B /* SPButton */ = {
isa = PBXGroup;
children = (
D0F9AC562826602400FD7A3B /* SPButton.h */,
D0F9AC572826602400FD7A3B /* SPButton.m */,
);
path = SPButton;
sourceTree = "<group>";
};
D0FAC404281B817D00D4B859 /* GKPhotoBrowser */ = { D0FAC404281B817D00D4B859 /* GKPhotoBrowser */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
...@@ -1433,6 +1451,7 @@ ...@@ -1433,6 +1451,7 @@
D08F79DE281A1838000D99DD /* TZPhotoPickerController.m in Sources */, D08F79DE281A1838000D99DD /* TZPhotoPickerController.m in Sources */,
D04B3DC027F6F82D0022F8DF /* ProfileController.m in Sources */, D04B3DC027F6F82D0022F8DF /* ProfileController.m in Sources */,
D01C9D7028168BFC00163567 /* NSDate+Extension.m in Sources */, D01C9D7028168BFC00163567 /* NSDate+Extension.m in Sources */,
D0F9AC582826602400FD7A3B /* SPButton.m in Sources */,
D0DB33A528204E7C00E15914 /* FirstLeadAlertView.m in Sources */, D0DB33A528204E7C00E15914 /* FirstLeadAlertView.m in Sources */,
D0C50B3027FD1BEB00DC68F0 /* PrivacyView.m in Sources */, D0C50B3027FD1BEB00DC68F0 /* PrivacyView.m in Sources */,
D0B5ECD527F2F0B2003EDFE3 /* AdaptationUtil.m in Sources */, D0B5ECD527F2F0B2003EDFE3 /* AdaptationUtil.m in Sources */,
...@@ -1543,6 +1562,7 @@ ...@@ -1543,6 +1562,7 @@
D08F79DD281A1838000D99DD /* TZImageManager.m in Sources */, D08F79DD281A1838000D99DD /* TZImageManager.m in Sources */,
D0506B1828054ECD00229278 /* SafeHelperCollectionView.m in Sources */, D0506B1828054ECD00229278 /* SafeHelperCollectionView.m in Sources */,
D04B3DC327F6F9390022F8DF /* HomeViewController.m in Sources */, D04B3DC327F6F9390022F8DF /* HomeViewController.m in Sources */,
D0F9AC5E282660CC00FD7A3B /* MusicPlayerView.m in Sources */,
D08F79D7281A1838000D99DD /* TZAssetModel.m in Sources */, D08F79D7281A1838000D99DD /* TZAssetModel.m in Sources */,
D01C9D6F28168BFC00163567 /* WSDatePickerView.m in Sources */, D01C9D6F28168BFC00163567 /* WSDatePickerView.m in Sources */,
); );
......
...@@ -110,6 +110,7 @@ ...@@ -110,6 +110,7 @@
} else { } else {
// 跳转到播放页面 // 跳转到播放页面
MusicPlayerController *playerVC = [[MusicPlayerController alloc] init]; MusicPlayerController *playerVC = [[MusicPlayerController alloc] init];
playerVC.audioModel = model;
UINavigationController *naviVC = [[UINavigationController alloc] initWithRootViewController:playerVC]; UINavigationController *naviVC = [[UINavigationController alloc] initWithRootViewController:playerVC];
[self presentViewController:naviVC animated:YES completion:nil]; [self presentViewController:naviVC animated:YES completion:nil];
} }
......
...@@ -6,12 +6,13 @@ ...@@ -6,12 +6,13 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "SubAudioModel.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
/// 音频播放界面 /// 音频播放界面
@interface MusicPlayerController : UIViewController @interface MusicPlayerController : UIViewController
@property (nonatomic, strong) SubAudioModel *audioModel;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -6,18 +6,22 @@ ...@@ -6,18 +6,22 @@
// //
#import "MusicPlayerController.h" #import "MusicPlayerController.h"
#import "MusicPlayerView.h"
@interface MusicPlayerController () @interface MusicPlayerController ()
@property (nonatomic, strong) UIButton *dismissBtn; @property (nonatomic, strong) MusicPlayerView *playerView;
@end @end
@implementation MusicPlayerController @implementation MusicPlayerController
- (void)loadView {
self.view = self.playerView;
}
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.dk_backgroundColorPicker = DKColorPickerWithKey(VCViewBG); [self.playerView updatePlayerView:self.audioModel];
[self.view addSubview:self.dismissBtn];
} }
#pragma mark - 隐藏导航栏 #pragma mark - 隐藏导航栏
...@@ -30,18 +34,12 @@ ...@@ -30,18 +34,12 @@
return [self.dk_manager.themeVersion isEqualToString:DKThemeVersionNormal] ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent; return [self.dk_manager.themeVersion isEqualToString:DKThemeVersionNormal] ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent;
} }
- (void)dismiss {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - lazy #pragma mark - lazy
- (UIButton *)dismissBtn { - (MusicPlayerView *)playerView {
if (!_dismissBtn) { if (!_playerView) {
_dismissBtn = [[UIButton alloc] initWithFrame:CGRectMake(15, kStatusBarHeight + 19, 30, 30)]; _playerView = [MusicPlayerView new];
[_dismissBtn dk_setImage:DKImagePickerWithNames(@"home_close", @"dk_home_close", @"home_close") forState:UIControlStateNormal];
[_dismissBtn addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
} }
return _dismissBtn; return _playerView;
} }
@end @end
//
// MusicPlayerView.h
// DreamSleep
//
// Created by peter on 2022/5/7.
//
#import <UIKit/UIKit.h>
#import "SubAudioModel.h"
typedef NS_ENUM(NSInteger, SoundPlayMode) {
SoundPlayModeSingle, // 单节播放
SoundPlayModeCycle, // 单曲循环
SoundPlayModeOrder // 顺序播放
};
NS_ASSUME_NONNULL_BEGIN
/// 音频播放页面
@interface MusicPlayerView : UIView
- (void)updatePlayerView:(SubAudioModel *)model;
@end
NS_ASSUME_NONNULL_END
//
// MusicPlayerView.m
// DreamSleep
//
// Created by peter on 2022/5/7.
//
#import "MusicPlayerView.h"
#import "SPButton.h"
@interface MusicPlayerView ()
@property (nonatomic, strong) UIButton *dismissBtn;
@property (nonatomic, strong) UIImageView *audioPicIV;
@property (nonatomic, strong) UILabel *audioNameLab;
@property (nonatomic, strong) UISlider *progressV;
@property (nonatomic, strong) UILabel *proLeftLb;
@property (nonatomic, strong) UILabel *proRightLb;
@property (nonatomic, strong) UIButton *playerBtn;
@property (nonatomic, strong) UIButton *leftPlayBtn;
@property (nonatomic, strong) UIButton *rightPlayBtn;
@property (nonatomic,strong) SPButton *playerListBtn;
@property (nonatomic,strong) SPButton *circleBtn;
@property (nonatomic,strong) SPButton *closeBtn;
@end
@implementation MusicPlayerView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)]) {
self.dk_backgroundColorPicker = DKColorPickerWithKey(VCViewBG);
[self addSubview:self.dismissBtn];
[self addSubview:self.audioPicIV];
[self addSubview:self.audioNameLab];
[self addSubview:self.progressV];
[self addSubview:self.proLeftLb];
[self addSubview:self.proRightLb];
[self addSubview:self.playerBtn];
[self addSubview:self.leftPlayBtn];
[self addSubview:self.rightPlayBtn];
[self addSubview:self.playerListBtn];
[self addSubview:self.circleBtn];
[self addSubview:self.closeBtn];
[self.audioPicIV mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.mas_centerX);
make.width.height.equalTo(@144);
make.top.equalTo(self.mas_top).offset(160);
}];
[self.audioNameLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.audioPicIV.mas_bottom).offset(18);
make.centerX.equalTo(self.mas_centerX);
make.left.equalTo(self.mas_left);
make.right.equalTo(self.mas_right);
}];
[self.progressV mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(38);
make.right.equalTo(self.mas_right).offset(-37);
make.height.equalTo(@15);
make.bottom.equalTo(self.playerBtn.mas_top).offset(-40);
}];
[self.proLeftLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.progressV.mas_left);
make.top.equalTo(self.progressV.mas_bottom).offset(6);
make.height.equalTo(@17);
make.width.equalTo(@100);
}];
[self.proRightLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.progressV.mas_right);
make.top.equalTo(self.progressV.mas_bottom).offset(6);
make.height.equalTo(@17);
make.width.equalTo(@100);
}];
[self.playerBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.mas_centerX);
make.width.equalTo(@50);
make.height.equalTo(@50);
make.bottom.equalTo(self.playerListBtn.mas_top).offset(-25);
}];
[self.leftPlayBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.playerBtn.mas_centerY);
make.width.equalTo(@30);
make.height.equalTo(@30);
make.right.equalTo(self.playerBtn.mas_left).offset(-60);
}];
[self.rightPlayBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.playerBtn.mas_centerY);
make.width.equalTo(@30);
make.height.equalTo(@30);
make.left.equalTo(self.playerBtn.mas_right).offset(60);
}];
[self.playerListBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_bottom).offset(-36);
make.left.equalTo(self.mas_left).offset(23);
make.width.equalTo(@80);
make.height.equalTo(@60);
}];
[self.circleBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_bottom).offset(-36);
make.centerX.equalTo(self.mas_centerX);
make.width.equalTo(@60);
make.height.equalTo(@60);
}];
[self.closeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_bottom).offset(-36);
make.right.equalTo(self.mas_right).offset(-23);
make.width.equalTo(@80);
make.height.equalTo(@60);
}];
}
return self;
}
- (void)dismiss {
[self.ds_viewController dismissViewControllerAnimated:YES completion:nil];
}
- (void)updatePlayerView:(SubAudioModel *)model {
[self.audioPicIV yy_setImageWithURL:[NSURL URLWithString:model.audio_pic] placeholder:[UIImage imageNamed:@"basicPlaceholder"]];
self.audioNameLab.text = model.audio_name;
}
- (void)circelBtnClick:(UIButton *)sender {
SoundPlayMode mode = sender.tag;
NSString *title = sender.titleLabel.text;
NSString *normalImgName = @"single_play";
NSString *dkImgName = @"dk_single_play";
if (mode == SoundPlayModeSingle) {
mode = SoundPlayModeCycle;
title = @"单曲循环";
normalImgName = @"single_cycle";
dkImgName = @"dk_single_cycle";
} else if (mode == SoundPlayModeCycle) {
mode = SoundPlayModeOrder;
title = @"顺序播放";
normalImgName = @"order_play";
dkImgName = @"dk_order_play";
} else if (mode == SoundPlayModeOrder) {
mode = SoundPlayModeSingle;
title = @"单节播放";
normalImgName = @"single_play";
dkImgName = @"dk_single_play";
}
sender.tag = mode;
[sender setTitle:title forState:UIControlStateNormal];
[sender dk_setImage:DKImagePickerWithNames(normalImgName, dkImgName, normalImgName) forState:UIControlStateNormal];
}
#pragma mark - lazy
- (UIButton *)dismissBtn {
if (!_dismissBtn) {
_dismissBtn = [[UIButton alloc] initWithFrame:CGRectMake(15, kStatusBarHeight + 19, 30, 30)];
[_dismissBtn dk_setImage:DKImagePickerWithNames(@"home_close", @"dk_home_close", @"home_close") forState:UIControlStateNormal];
[_dismissBtn addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
}
return _dismissBtn;
}
- (UIImageView *)audioPicIV {
if (!_audioPicIV) {
_audioPicIV = [UIImageView new];
[_audioPicIV cornerRadius:72.0];
_audioPicIV.dk_alphaPicker = DKAlphaPickerWithAlphas(1.0, .5, .5);
}
return _audioPicIV;
}
- (UILabel *)audioNameLab {
if (!_audioNameLab) {
_audioNameLab = [UILabel labWithFont:BoldFont(16)];
_audioNameLab.textAlignment = NSTextAlignmentCenter;
_audioNameLab.dk_textColorPicker = DKColorPickerWithColors(MainTextColor, ColorFromHex(0xE8E9E9), DSWhite);
}
return _audioNameLab;
}
- (UISlider *)progressV {
if (!_progressV) {
_progressV = [UISlider new];
[_progressV cornerRadius:2.0];
_progressV.minimumTrackTintColor = BrandColor;
_progressV.dk_maximumTrackTintColorPicker = DKColorPickerWithColors(ColorFromHex(0xE3E1E1), ColorFromHex(0x131724), DSWhite);
[_progressV setThumbImage:[UIImage imageNamed:@"muse_slider_thumbImage"] forState:UIControlStateNormal];
[_progressV addTarget:self action:@selector(progresssBtnClick:) forControlEvents: UIControlEventValueChanged];
}
return _progressV;
}
- (UILabel *)proLeftLb {
if (!_proLeftLb) {
_proLeftLb = [UILabel labWithFont:SysFont(12)];
_proLeftLb.textAlignment = NSTextAlignmentLeft;
_proLeftLb.dk_textColorPicker = DKColorPickerWithColors(ColorFromHex(0xAAAAAA), ColorFromHex(0x5A6073), DSWhite);
}
return _proLeftLb;
}
- (UILabel *)proRightLb {
if (!_proRightLb) {
_proRightLb = [UILabel labWithFont:SysFont(12)];
_proRightLb.textAlignment = NSTextAlignmentRight;
_proRightLb.dk_textColorPicker = DKColorPickerWithColors(ColorFromHex(0xAAAAAA), ColorFromHex(0x5A6073), DSWhite);
}
return _proRightLb;
}
- (UIButton *)playerBtn {
if (!_playerBtn) {
_playerBtn = [UIButton new];
[_playerBtn addTarget:self action:@selector(playerBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_playerBtn dk_setBackgroundImage:DKImagePickerWithNames(@"audio_play_icon", @"dk_audio_play_icon", DSWhite) forState:UIControlStateNormal];
}
return _playerBtn;
}
- (UIButton *)leftPlayBtn {
if (!_leftPlayBtn) {
_leftPlayBtn = [UIButton new];
[_leftPlayBtn addTarget:self action:@selector(leftPlayBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_leftPlayBtn setBackgroundImage:[UIImage imageNamed:@"previous_icon"] forState:UIControlStateNormal];
}
return _leftPlayBtn;
}
- (UIButton *)rightPlayBtn {
if (!_rightPlayBtn) {
_rightPlayBtn = [UIButton new];
[_rightPlayBtn addTarget:self action:@selector(rightPlayBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_rightPlayBtn setBackgroundImage:[UIImage imageNamed:@"next_icon"] forState:UIControlStateNormal];
}
return _rightPlayBtn;
}
- (SPButton *)playerListBtn {
if (!_playerListBtn) {
_playerListBtn = [[SPButton alloc] initWithImagePosition:SPButtonImagePositionTop];
_playerListBtn.imageTitleSpace = 2;
[_playerListBtn addTarget:self action:@selector(playerListBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_playerListBtn setTitleColor:SmallTextColor forState:UIControlStateNormal];
_playerListBtn.titleLabel.font = SysFont(12);
[_playerListBtn dk_setImage:DKImagePickerWithNames(@"playlist_icon", @"dk_playlist_icon", @"playlist_icon") forState:UIControlStateNormal];
[_playerListBtn setTitle:@"播放列表" forState:UIControlStateNormal];
}
return _playerListBtn;
}
- (SPButton *)circleBtn {
if (!_circleBtn) {
_circleBtn = [[SPButton alloc] initWithImagePosition:SPButtonImagePositionTop];
_circleBtn.imageTitleSpace = 2;
[_circleBtn addTarget:self action:@selector(circelBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_circleBtn setTitleColor:SmallTextColor forState:UIControlStateNormal];
_circleBtn.titleLabel.font = SysFont(12);
[_circleBtn dk_setImage:DKImagePickerWithNames(@"single_play", @"dk_single_play", @"single_play") forState:UIControlStateNormal];
_circleBtn.tag = SoundPlayModeSingle;
[_circleBtn setTitle:@"单节播放" forState:UIControlStateNormal];
}
return _circleBtn;
}
- (SPButton *)closeBtn {
if (!_closeBtn) {
_closeBtn = [[SPButton alloc] initWithImagePosition:SPButtonImagePositionTop];
_closeBtn.imageTitleSpace = 2;
[_closeBtn addTarget:self action:@selector(timeDefineClick:) forControlEvents:UIControlEventTouchUpInside];
[_closeBtn setTitleColor:SmallTextColor forState:UIControlStateNormal];
_closeBtn.titleLabel.font = SysFont(12);
[_closeBtn dk_setImage:DKImagePickerWithNames(@"time_close_icon", @"dk_time_close_icon", @"time_close_icon") forState:UIControlStateNormal];
[_closeBtn setTitle:@"定时关闭" forState:UIControlStateNormal];
}
return _closeBtn;
}
@end
{
"images" : [
{
"filename" : "audio_pause.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "audio_pause@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "audio_pause@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "audio_play_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "audio_play_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_audio_pause.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_audio_pause@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_audio_pause@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_audio_play_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_audio_play_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_audio_play_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_order_play.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_order_play@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_order_play@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_playlist_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_playlist_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_playlist_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_single_cycle.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_single_cycle@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_single_cycle@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_single_play.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_single_play@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_single_play@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "dk_time_close_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dk_time_close_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dk_time_close_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "muse_slider_thumbImage.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "muse_slider_thumbImage@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "muse_slider_thumbImage@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "next_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "next_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "next_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "order_play.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "order_play@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "order_play@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "playlist_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "playlist_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "playlist_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "previous_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "previous_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "previous_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "single_cycle.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "single_cycle@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "single_cycle@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "single_play.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "single_play@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "single_play@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "time_close_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "time_close_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "time_close_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
//
// SPButton.h
// SPButton
//
// Created by 乐升平 on 2018/11/20.
// Copyright © 2018 乐升平. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, SPButtonImagePosition) {
SPButtonImagePositionLeft = 0, // 图片在文字左侧
SPButtonImagePositionRight = 1, // 图片在文字右侧
SPButtonImagePositionTop = 2, // 图片在文字上侧
SPButtonImagePositionBottom = 3 // 图片在文字下侧
};
IB_DESIGNABLE
@interface SPButton : UIButton
- (instancetype)initWithImagePosition:(SPButtonImagePosition)imagePosition;
#if TARGET_INTERFACE_BUILDER // storyBoard/xib中设置
@property (nonatomic,assign) IBInspectable NSInteger imagePosition; // 图片位置
@property (nonatomic, assign) IBInspectable CGFloat imageTitleSpace; // 图片和文字之间的间距
#else // 纯代码设置
@property (nonatomic) SPButtonImagePosition imagePosition; // 图片位置
@property (nonatomic, assign) CGFloat imageTitleSpace; // 图片和文字之间的间距
#endif
@end
NS_ASSUME_NONNULL_END
//
// SPButton.m
// SPButton
//
// Created by 乐升平 on 2018/11/20.
// Copyright © 2018 乐升平. All rights reserved.
//
#import "SPButton.h"
@implementation SPButton
- (instancetype)initWithImagePosition:(SPButtonImagePosition)imagePosition {
if (self = [super init]) {
self.imagePosition = imagePosition;
}
return self;
}
#pragma mark - system methods
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)initialize {
_imagePosition = SPButtonImagePositionLeft;
_imageTitleSpace = 0.0;
}
// 下面这2个方法,我所知道的:
// 在第一次调用titleLabel和imageView的getter方法(懒加载)时,alloc init之前会调用一次(无论有无图片文字都会直接调),因此,在重写这2个方法时,在方法里面不要使用self.imageView和self.titleLabel,因为这2个控件是懒加载,如果在重写的这2个方法里是第一调用imageView和titleLabel的getter方法, 则会造成死循环
// 在layoutsSubviews中如果文字或图片不为空时会调用, 测试方式:在重写的这两个方法里调用setNeedsLayout(layutSubviews),发现会造成死循环
// 设置文字图片、改动文字和图片、设置对齐方式,设置内容区域等时会调用,其实设置这些属性,系统是调用了layoutSubviews从而间接的去调用imageRectForContentRect:和titleRectForContentRect:
// ...
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
// 先获取系统为我们计算好的rect,这样大小图片在左右时我们就不要自己去计算,我门要改变的,仅仅是origin
CGRect imageRect = [super imageRectForContentRect:contentRect];
CGRect titleRect = [super titleRectForContentRect:contentRect];
if (!self.currentTitle) { // 如果没有文字,则图片占据整个button,空格算一个文字
return imageRect;
}
switch (self.imagePosition) {
case SPButtonImagePositionLeft: { // 图片在左
imageRect = [self imageRectImageAtLeftForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
}
break;
case SPButtonImagePositionRight: {
imageRect = [self imageRectImageAtRightForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
}
break;
case SPButtonImagePositionTop: {
imageRect = [self imageRectImageAtTopForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
}
break;
case SPButtonImagePositionBottom: {
imageRect = [self imageRectImageAtBottomForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
}
break;
}
return imageRect;
}
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
CGRect titleRect = [super titleRectForContentRect:contentRect];
CGRect imageRect = [super imageRectForContentRect:contentRect];
if (!self.currentImage) { // 如果没有图片
return titleRect;
}
switch (self.imagePosition) {
case SPButtonImagePositionLeft: {
titleRect = [self titleRectImageAtLeftForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
}
break;
case SPButtonImagePositionRight: {
titleRect = [self titleRectImageAtRightForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
}
break;
case SPButtonImagePositionTop: {
titleRect = [self titleRectImageAtTopForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
}
break;
case SPButtonImagePositionBottom: {
titleRect = [self titleRectImageAtBottomForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
}
break;
}
return titleRect;
}
- (void)sizeToFit {
// 这个super很重要,它能保证下面使用的self.frame的值是系统计算好的结果
[super sizeToFit];
CGRect myFrame = self.frame;
switch (self.imagePosition) {
case SPButtonImagePositionLeft:
case SPButtonImagePositionRight: // 图片在左右时,在系统计算好的基础上宽度再加间距
myFrame.size.width = self.frame.size.width + _imageTitleSpace;
break;
case SPButtonImagePositionTop:
case SPButtonImagePositionBottom: {// 图片在上下时,就不能再在系统计算的基础上增减值了,因为系统计算是基于图片在左文字在右时进行的,宽度依赖图片+文字之和,而图片在上下时,宽度应该依赖图片和文字较大的那个
CGFloat imageFitWidth = self.contentEdgeInsets.left + self.currentImage.size.width + self.contentEdgeInsets.right;
CGFloat titleFitWidth = self.contentEdgeInsets.left + [self calculateTitleSizeForSystemTitleSize:CGSizeMake(0, 0)].width + self.contentEdgeInsets.right;
myFrame.size.width = MAX(imageFitWidth, titleFitWidth);
myFrame.size.height = self.contentEdgeInsets.top + self.currentImage.size.height + [self calculateTitleSizeForSystemTitleSize:CGSizeMake(0, 0)].height + self.contentEdgeInsets.bottom + _imageTitleSpace;
}
break;
default:
break;
}
self.frame = myFrame;
}
#pragma - private
// ----------------------------------------------------- left -----------------------------------------------------
- (CGRect)imageRectImageAtLeftForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
CGPoint imageOrigin = imageRect.origin;
CGSize imageSize = imageRect.size;
//CGSize titleSize = titleRect.size;
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: // 中心对齐
// imageView的x值向左偏移间距的一半,另一半由titleLabe分担,不用管会不会超出contentRect,我定的规则是允许超出,如果对此作出限制,那么必须要对图片或者文字宽高有所压缩,压缩只能由imageEdgeInsets决定,当图片的内容区域容不下时才产生宽度压缩
imageOrigin.x = imageOrigin.x - _imageTitleSpace*0.5;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
imageOrigin.x = imageOrigin.x - _imageTitleSpace;
break;
case UIControlContentHorizontalAlignmentFill: // 填充整个按钮,水平填充模式有点怪异,填充的意思是将图片和文字整个水平填满,但是,事实上能够被填满,但是titleLabel的x值不会发生变化,即图片被拉伸,但是图片的右边会预留一个titleLabel的宽度,这个titleLabel的宽度由系统计算,我们不必关心计算过程。还有,填充模式下,设置图片的contentMode是不管用的,因为系统强制设置了图片的大小
imageOrigin.x = imageOrigin.x - _imageTitleSpace*0.5;
break;
default: // 剩下的就是左对齐,左对齐image不用做任何改变
break;
}
imageRect.size = imageSize;
imageRect.origin = imageOrigin;
return imageRect;
}
- (CGRect)titleRectImageAtLeftForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
CGPoint titleOrigin = titleRect.origin;
CGSize titleSize = titleRect.size;
//CGSize imageSize = imageRect.size;
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: { // 中心对齐
titleOrigin.x = titleOrigin.x + _imageTitleSpace * 0.5;
}
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: { // 左对齐
titleOrigin.x = titleOrigin.x + _imageTitleSpace;
}
break;
case UIControlContentHorizontalAlignmentFill: // 填充整个按钮
// 填充整个按钮,水平填充模式有点怪异,填充的意思是将图片和文字整个水平填满,但是,事实上能够被填满,但是titleLabel的x值不会发生变化,即图片被拉伸,但是图片的右边会预留一个titleLabel的宽度,这个titleLabel的宽度由系统计算,我们不必关心计算过程。还有,填充模式下,设置图片的contentMode是不管用的,因为系统强制设置了图片的大小
// 宽度减去间距的一半,另一半由imageView分担,x值保持系统值
titleOrigin.x = titleOrigin.x + _imageTitleSpace * 0.5;
break;
default: // 剩下的就是右对齐,右对齐titleLabel不用做任何改变
break;
}
titleRect.size = titleSize;
titleRect.origin = titleOrigin;
return titleRect;
}
// ----------------------------------------------------- right -----------------------------------------------------
- (CGRect)imageRectImageAtRightForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
if (imageRect.size.width >= imageSafeWidth) {
return imageRect;
}
CGPoint imageOrigin = imageRect.origin;
CGSize imageSize = imageRect.size;
CGSize titleSize = titleRect.size;
// 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
if (imageSize.width + titleSize.width > imageSafeWidth) {
imageSize.width = imageSize.width - (imageSize.width + titleSize.width - imageSafeWidth);
}
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
titleSize = [self calculateTitleSizeForSystemTitleSize:titleSize];
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: // 中心对齐
// (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - (imageSize.width + titleSize.width))/2.0+titleSize.width指的是imageView在其有效区域内联合titleLabel整体居中时的x值,有效区域指的是contentRect内缩imageEdgeInsets后的区域
imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - (imageSize.width + titleSize.width))/2.0 + titleSize.width + self.contentEdgeInsets.left + self.imageEdgeInsets.left + _imageTitleSpace * 0.5;
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left + titleSize.width + _imageTitleSpace;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
// 注意image的大小要使用系统计算的结果,这里不能使用self.currentImage.size.width,当imageEdgeInsets的left过大时可以进行测试
imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
break;
case UIControlContentHorizontalAlignmentFill: // 填充
imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right + _imageTitleSpace * 0.5;
break;
}
imageRect.size = imageSize;
imageRect.origin = imageOrigin;
return imageRect;
}
- (CGRect)titleRectImageAtRightForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
CGPoint titleOrigin = titleRect.origin;
CGSize titleSize = titleRect.size;
CGSize imageSize = imageRect.size;
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: // 中心对齐
// (contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right - (imageSize.width + titleSize.width))/2.0的意思是titleLabel在其有效区域内联合imageView整体居中时的x值,有效区域指的是contentRect内缩titleEdgeInsets后的区域
titleOrigin.x = (contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right - (imageSize.width + titleSize.width))/2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left - _imageTitleSpace * 0.5;
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
// 这里必须使用self.currentImage的宽度。不能使用imageSize.width,因为图片可能会被压缩或者拉伸,例如当图片的imageEdgeInsets的right设置过大,图片的宽度就会被压缩,这时的图片宽度不是我们要的
titleOrigin.x = buttonWidth - (titleSize.width + self.currentImage.size.width) - self.titleEdgeInsets.right - self.contentEdgeInsets.right - _imageTitleSpace;
break;
case UIControlContentHorizontalAlignmentFill:
titleOrigin.x = buttonWidth - (titleSize.width + self.currentImage.size.width) - self.titleEdgeInsets.right - self.contentEdgeInsets.right - _imageTitleSpace * 0.5;
break;
}
titleRect.size = titleSize;
titleRect.origin = titleOrigin;
return titleRect;
}
// ----------------------------------------------------- top -----------------------------------------------------
- (CGRect)imageRectImageAtTopForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
CGPoint imageOrigin = imageRect.origin;
CGSize imageSize = self.currentImage.size;
CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
CGFloat imageSafeHeight = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
// 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
if (imageSize.width > imageSafeWidth) {
imageSize.width = imageSafeWidth;
}
if (imageSize.height > imageSafeHeight) {
imageSize.height = imageSafeHeight;
}
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
// 水平方向
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - imageSize.width) / 2.0 + self.contentEdgeInsets.left + self.imageEdgeInsets.left;
}
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
break;
case UIControlContentHorizontalAlignmentFill: // 填充
imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
imageSize.width = imageSafeWidth; // 宽度填满
break;
}
// 给图片高度作最大限制,超出限制对高度进行压缩,这样还可以保证titeLabel不会超出其有效区域
CGFloat imageTitleLimitMaxH = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
if (imageSize.height < imageTitleLimitMaxH) {
if (titleSize.height + imageSize.height > imageTitleLimitMaxH) {
CGFloat beyondValue = titleSize.height + self.currentImage.size.height - imageTitleLimitMaxH;
imageSize.height = imageSize.height - beyondValue;
}
}
// 垂直方向
switch (self.contentVerticalAlignment) {
case UIControlContentVerticalAlignmentCenter: // 中心对齐
// (imageSize.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的insets,计算时都是以图片+文字这个整体作为考虑对象
imageOrigin.y = (contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentTop: // 顶部对齐
imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentBottom: // 底部对齐
imageOrigin.y = buttonHeight - (imageSize.height + titleSize.height) - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentFill: // 填充
imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
imageSize.height = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - [self calculateTitleSizeForSystemTitleSize:titleSize].height;
break;
}
imageRect.size = imageSize;
imageRect.origin = imageOrigin;
return imageRect;
}
- (CGRect)titleRectImageAtTopForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
CGPoint titleOrigin = titleRect.origin;
CGSize imageSize = self.currentImage.size;
CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
// 这个if语句的含义是:计算图片由于设置了contentEdgeInsets而被压缩的高度,设置imageEdgeInsets被压缩的高度不计算在内。这样做的目的是,当设置了contentEdgeInsets时,图片可能会被压缩,此时titleLabel的y值依赖于图片压缩后的高度,当设置了imageEdgeInsets时,图片也可能被压缩,此时titleLabel的y值依赖于图片压缩前的高度,这样以来,设置imageEdgeInsets就不会对titleLabel的y值产生影响
if (imageSize.height + titleSize.height > contentRect.size.height) {
imageSize.height = self.currentImage.size.height - (self.currentImage.size.height + titleSize.height - contentRect.size.height);
}
// titleLabel的安全宽度,这里一定要改变宽度值,因为当外界设置了titleEdgeInsets值时,系统计算出来的所有值都是在”左图右文“的基础上进行的,这个基础上可能会导致titleLabel的宽度被压缩,所以我们在此自己重新计算
CGFloat titleSafeWidth = contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right;
if (titleSize.width > titleSafeWidth) {
titleSize.width = titleSafeWidth;
}
// 水平方向
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
titleOrigin.x = (titleSafeWidth - titleSize.width) / 2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left;
}
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
titleOrigin.x = buttonWidth - titleSize.width - self.titleEdgeInsets.right - self.contentEdgeInsets.right;
break;
case UIControlContentHorizontalAlignmentFill: // 填充
titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
// titleLabel宽度上不填充,按系统一样,在有效区域内,自适应文字宽度
break;
}
if (titleSize.height > contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom) {
titleSize.height = contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom;
}
// 垂直方向
switch (self.contentVerticalAlignment) {
case UIControlContentVerticalAlignmentCenter: {// 中心对齐
// (imageSize.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的Insets,计算时都是以图片+文字这个整体作为考虑对象
titleOrigin.y = (contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + imageSize.height + self.contentEdgeInsets.top + self.titleEdgeInsets.top + _imageTitleSpace * 0.5;
}
break;
case UIControlContentVerticalAlignmentTop: // 顶部对齐
titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top + imageSize.height + _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentBottom: // 底部对齐
titleOrigin.y = buttonHeight - titleSize.height - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom+ _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentFill: // 填充
titleOrigin.y = buttonHeight - titleSize.height - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom + _imageTitleSpace * 0.5;
break;
}
titleRect.size = titleSize;
titleRect.origin = titleOrigin;
return titleRect;
}
// ----------------------------------------------------- bottom -----------------------------------------------------
- (CGRect)imageRectImageAtBottomForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
CGPoint imageOrigin = imageRect.origin;
CGSize imageSize = self.currentImage.size;
CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
CGFloat imageSafeHeight = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
// 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
if (imageSize.width > imageSafeWidth) {
imageSize.width = imageSafeWidth;
}
if (imageSize.height > imageSafeHeight) {
imageSize.height = imageSafeHeight;
}
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
// 水平方向
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - imageSize.width) / 2.0 + self.contentEdgeInsets.left + self.imageEdgeInsets.left;
}
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
break;
case UIControlContentHorizontalAlignmentFill: // 填充
imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
imageSize.width = imageSafeWidth; // 宽度填满
break;
}
// 给图片高度作最大限制,超出限制对高度进行压缩,这样还可以保证titeLabel不会超出其有效区域
CGFloat imageTitleLimitMaxH = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
if (imageSize.height < imageTitleLimitMaxH) {
if (titleSize.height + imageSize.height > imageTitleLimitMaxH) {
CGFloat beyondValue = titleSize.height + self.currentImage.size.height - imageTitleLimitMaxH;
imageSize.height = imageSize.height - beyondValue;
}
}
// 垂直方向
switch (self.contentVerticalAlignment) {
case UIControlContentVerticalAlignmentCenter: // 中心对齐
// (self.currentImage.size.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的insets,计算时都是以图片+文字这个整体作为考虑对象
imageOrigin.y = (contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + titleSize.height + self.contentEdgeInsets.top + self.imageEdgeInsets.top + _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentTop: // 顶部对齐
imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top + titleSize.height + _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentBottom: // 底部对齐
imageOrigin.y = buttonHeight - imageSize.height - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom + _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentFill: // 填充
// 这里不能使用titleSize.height,因为垂直填充模式下,系统计算出的titleSize就是contentRect的高度,我们需要的是titleLabel拉伸前的高度
imageSize.height = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - [self calculateTitleSizeForSystemTitleSize:titleSize].height;
imageOrigin.y = buttonHeight - imageSize.height - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom + _imageTitleSpace * 0.5;
break;
}
imageRect.size = imageSize;
imageRect.origin = imageOrigin;
return imageRect;
}
- (CGRect)titleRectImageAtBottomForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
CGPoint titleOrigin = titleRect.origin;
CGSize imageSize = self.currentImage.size;
CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
// 这个if语句的含义是:计算图片由于设置了contentEdgeInsets而被压缩的高度,设置imageEdgeInsets被压缩的高度不计算在内。这样做的目的是,当设置了contentEdgeInsets时,图片可能会被压缩,此时titleLabel的y值依赖于图片压缩后的高度,当设置了imageEdgeInsets时,图片也可能被压缩,此时titleLabel的y值依赖于图片压缩前的高度,这样一来,设置imageEdgeInsets就不会对titleLabel的y值产生影响
if (self.currentImage.size.height + titleSize.height > contentRect.size.height) {
imageSize.height = self.currentImage.size.height - (self.currentImage.size.height + titleSize.height - contentRect.size.height);
}
// titleLabel的安全宽度,因为当外界设置了titleEdgeInsets值时,系统计算出来的所有值都是在”左图右文“的基础上进行的,这个基础上可能会导致titleLabel的宽度被压缩,所以我们在此自己重新计算
CGFloat titleSafeWidth = contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right;
if (titleSize.width > titleSafeWidth) {
titleSize.width = titleSafeWidth;
}
CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
// 水平方向
switch (self.contentHorizontalAlignment) {
case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
titleOrigin.x = (titleSafeWidth - titleSize.width) / 2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left;
}
break;
case UIControlContentHorizontalAlignmentLeft:
case UIControlContentHorizontalAlignmentLeading: // 左对齐
titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
break;
case UIControlContentHorizontalAlignmentRight:
case UIControlContentHorizontalAlignmentTrailing: // 右对齐
titleOrigin.x = buttonWidth - titleSize.width - self.titleEdgeInsets.right - self.contentEdgeInsets.right;
break;
case UIControlContentHorizontalAlignmentFill: // 填充
titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
// titleLabel宽度上不填充,按系统一样,在有效区域内,自适应文字宽度
break;
}
if (titleSize.height > contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom) {
titleSize.height = contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom;
}
// 垂直方向
switch (self.contentVerticalAlignment) {
case UIControlContentVerticalAlignmentCenter: // 中心对齐
// (self.currentImage.size.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的Insets,计算时都是以图片+文字这个整体作为考虑对象
titleOrigin.y = (contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentTop: // 顶部对齐
titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentBottom: // 底部对齐
titleOrigin.y = buttonHeight - (titleSize.height + imageSize.height) - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom - _imageTitleSpace * 0.5;
break;
case UIControlContentVerticalAlignmentFill: // 填充
titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
break;
}
titleRect.size = titleSize;
titleRect.origin = titleOrigin;
return titleRect;
}
// 自己计算titleLabel的大小
- (CGSize)calculateTitleSizeForSystemTitleSize:(CGSize)titleSize {
CGSize myTitleSize = titleSize;
// 获取按钮里的titleLabel,之所以遍历获取而不直接调用self.titleLabel,是因为假如这里是第一次调用self.titleLabel,则会跟titleRectForContentRect: 方法造成死循环,titleLabel的getter方法中,alloc init之前调用了titleRectForContentRect:
UILabel *titleLabel = [self findTitleLabel];
if (!titleLabel) { // 此时还没有创建titleLabel,先通过系统button的字体进行文字宽度计算
CGFloat fontSize = [UIFont buttonFontSize]; // 按钮默认字体,18号
// 说明外界使用了被废弃的font属性,被废弃但是依然生效
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (self.font.pointSize != [UIFont buttonFontSize]) {
fontSize = self.font.pointSize;
}
#pragma clang diagnostic pop
myTitleSize.height = ceil([self.currentTitle boundingRectWithSize:CGSizeMake(titleSize.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil].size.height);
// 根据文字计算宽度,取上整,补齐误差,保证跟titleLabel.intrinsicContentSize.width一致
myTitleSize.width = ceil([self.currentTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, titleSize.height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil].size.width);
} else { // 说明此时titeLabel已经产生,直接取titleLabel的内容宽度
myTitleSize.width = titleLabel.intrinsicContentSize.width;
myTitleSize.height = titleLabel.intrinsicContentSize.height;
}
return myTitleSize;
}
// 遍历获取按钮里面的titleLabel
- (UILabel *)findTitleLabel {
for (UIView *subView in self.subviews) {
if ([subView isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
UILabel *titleLabel = (UILabel *)subView;
return titleLabel;
}
}
return nil;
}
#pragma mark - setter
// 以下所有setter方法中都调用了layoutSubviews, 其实是为了间接的调用imageRectForContentRect:和titleRectForContentRect:,不能直接调用imageRectForContentRect:和titleRectForContentRect:,因为按钮的子控件布局最终都是通过调用layoutSubviews而确定,如果直接调用这两个方法,那么只能保证我们能够获取的CGRect是对的,但并不会作用在titleLabel和imageView上
- (void)setImagePosition:(SPButtonImagePosition)imagePosition {
_imagePosition = imagePosition;
[self setNeedsLayout];
}
- (void)setImageTitleSpace:(CGFloat)imageTitleSpace {
_imageTitleSpace = imageTitleSpace;
[self setNeedsLayout];
}
- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
[super setContentHorizontalAlignment:contentHorizontalAlignment];
[self setNeedsLayout];
}
// 垂直方向的排列方式在设置之前如果调用了titleLabel或imageView的getter方法,则设置后不会生效,点击一下按钮之后就生效了,这应该属于按钮的一个小bug,我们只要重写它的setter方法重新布局一次就好
- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
[super setContentVerticalAlignment:contentVerticalAlignment];
[self setNeedsLayout];
}
@end
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!