原創(chuàng):知識(shí)點(diǎn)總結(jié)性文章
創(chuàng)作不易,請(qǐng)珍惜,之后會(huì)持續(xù)更新脸侥,不斷完善
個(gè)人比較喜歡做筆記和寫總結(jié),畢竟好記性不如爛筆頭哈哈盈厘,這些文章記錄了我的IOS成長歷程睁枕,希望能與大家一起進(jìn)步
溫馨提示:由于簡書不支持目錄跳轉(zhuǎn),大家可通過command + F 輸入目錄標(biāo)題后迅速尋找到你所需要的內(nèi)容
目錄
- 一沸手、YYModel
- 二外遇、UICountingLabel
- 三、SDWebImage
- 四契吉、SDCycleScrollView
- 五跳仿、MBProgressHUD
- 六、EmptyDataSet
- 七捐晶、MGSwipeTableCell
- 八菲语、FSCalendar
- 九、Toast
- 十惑灵、zhPopupController
一山上、YYModel
在iOS開發(fā)中總會(huì)用到各種JSON
與模型相互轉(zhuǎn)換的需求,之前的項(xiàng)目中一直使用MJExtension
英支,但是最近發(fā)現(xiàn)一個(gè)輕量級(jí)的庫YYModel
佩憾,使用簡單,性能也很不錯(cuò),接下來就說說YYModel
的一些簡單的用法及注意事項(xiàng)妄帘。
1楞黄、JSON轉(zhuǎn)換為模型,或者模型轉(zhuǎn)換為JSON
JSON
{
accountId = "<null>";
avatarUrl = "http://thirdwx.qlogo.cn/mmopen/vi_32/sqicFCgiaheqCFbjrYgTmwXUQOB5l5Iyo47cVVp2cLlHARck6XgXscqicJ2ZVibicCbGH4iaVcQz8ptXqbV6n9ic5iaL9g/132";
unionId = o2t87wKAR1pNRZR0cnReBT608mok;
userid = 11703346;
wxNickName = "\U90a3\U5496";
}
Model
@property (nonatomic, strong) NSString *avatarUrl;
@property (nonatomic, strong) NSString *wxNickName;
@property (nonatomic, strong) NSString *accountId;
@property (nonatomic, strong) NSString *unionId;
@property (nonatomic, strong) NSString *userid;
JSON轉(zhuǎn)換為模型
FansModel *fansModel = [FansModel yy_modelWithJSON:dic];
FansModel *fansModel = [FansModel yy_modelWithDictionary:dic];
模型轉(zhuǎn)換為JSON
NSDictionary *json = [fansModel yy_modelToJSONObject];
2寄摆、手動(dòng)創(chuàng)建的模型和服務(wù)端返回的模型屬性名稱不一致時(shí)
"userName" = "謝佳培";
"avatar" = "http://thirdwx.qlogo.cn/mmopen/vi_32/sqicFCgiaheqCFbjrYgTmwXUQOB5l5Iyo47cVVp2cLlHARck6XgXscqicJ2ZVibicCbGH4iaVcQz8ptXqbV6n9ic5iaL9g/132";
@property (nonatomic, strong) NSString *avatarUrl;
@property (nonatomic, strong) NSString *accountId;
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{@"avatarUrl" : @"avatar",
@"wxNickName" : @"userName",
};
}
3谅辣、模型套模型
+ (NSDictionary *)modelContainerPropertyGenericClass
{
return @{@"areas" : [AreaModel class]};
}
ProvinceModel *provinceModel = [ProvinceModel yy_modelWithJSON:dict];
CityModel *cityModel = provinceModel.citys[0];
4、數(shù)組里面存放字典類型轉(zhuǎn)換為模型
@implementation RabbitModel
@end
@implementation RabbitViewModel
// 轉(zhuǎn)換為模型
- (void)manyRabbit
{
NSArray *array;
NSArray<RabbitModel *> *rabbitModelArray = [NSArray yy_modelArrayWithClass:[RabbitModel class] json:array];
}
@end
5婶恼、黑名單桑阶,即加入黑名單的字段會(huì)被忽略不會(huì)轉(zhuǎn)換
將JSON
轉(zhuǎn)換為模型,轉(zhuǎn)換出來的模型中的avatarUrl
和accountId
的值為nil
勾邦。
@property (nonatomic, strong) NSString *avatarUrl;
@property (nonatomic, strong) NSString *accountId;
+ (NSArray *)modelPropertyBlacklist
{
return @[@"avatarUrl", @"accountId"];
}
6蚣录、白名單,即只處理加入白名單的字段眷篇,其余字段忽略掉
+ (NSArray *)modelPropertyWhitelist
{
return @[@"avatarUrl", @"accountId"];
}
二萎河、UICountingLabel
1、做一個(gè)算數(shù)的
myLabel.method = UILabelCountingMethodLinear;// 線性變化
myLabel.format = @"%d";
[myLabel countFrom:1 to:10 withDuration:3.0];
2蕉饼、使用ease-in-out(默認(rèn)設(shè)置)將計(jì)數(shù)從5%增加到10%
countPercentageLabel.format = @"%.1f%%";
[countPercentageLabel countFrom:5 to:10];
3虐杯、使用使用數(shù)字格式化的字符串進(jìn)行計(jì)數(shù)
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = kCFNumberFormatterDecimalStyle;
// 可以對(duì)顯示的文本格式進(jìn)行自定義
scoreLabel.formatBlock = ^NSString *(CGFloat value)
{
NSString *formatted = [formatter stringFromNumber:@((int)value)];
return [NSString stringWithFormat:@"Score: %@",formatted];
};
scoreLabel.method = UILabelCountingMethodEaseOut;// 開始速度很快,快結(jié)束時(shí)變得緩慢
[scoreLabel countFrom:0 to:10000 withDuration:2.5];// 可以指定動(dòng)畫的時(shí)長昧港,默認(rèn)時(shí)長是2.0秒
4擎椰、使用屬性字符串計(jì)數(shù)
NSInteger toValue = 100;
// 用于設(shè)置屬性字符串的格式,如果指定了formatBlock创肥,則將會(huì)覆蓋掉format屬性达舒,因?yàn)閎lock的優(yōu)先級(jí)更高
attributedLabel.attributedFormatBlock = ^NSAttributedString* (CGFloat value)
{
NSDictionary *normal = @{ NSFontAttributeName: [UIFont fontWithName: @"HelveticaNeue-UltraLight" size: 20] };
NSDictionary *highlight = @{ NSFontAttributeName: [UIFont fontWithName: @"HelveticaNeue" size: 20] };
NSString *prefix = [NSString stringWithFormat:@"%d", (int)value];
NSString *postfix = [NSString stringWithFormat:@"/%d", (int)toValue];
NSMutableAttributedString *prefixAttr = [[NSMutableAttributedString alloc] initWithString: prefix attributes: highlight];
NSAttributedString *postfixAttr = [[NSAttributedString alloc] initWithString: postfix attributes: normal];
[prefixAttr appendAttributedString: postfixAttr];
return prefixAttr;
};
[attributedLabel countFrom:0 to:toValue withDuration:2.5];
5、獲得動(dòng)畫結(jié)束的事件
self.completionBlockLabel.method = UILabelCountingMethodEaseInOut;
self.completionBlockLabel.format = @"%d%%";
__weak UICountingLabelViewController *weakSelf = self;
self.completionBlockLabel.completionBlock = ^{
weakSelf.completionBlockLabel.textColor = [UIColor colorWithRed:0 green:0.5 blue:0 alpha:1];
};
[self.completionBlockLabel countFrom:0 to:100];
三叹侄、SDWebImage
多數(shù)情況下是使用UIImageView+WebCache
為UIImageView
異步加載圖片:
#import <SDWebImage/UIImageView+WebCache.h>
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
它還支持block
語法巩搏,用于在加載完成時(shí)做一些操作:
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
... completion code here ...
}];
SDWebImage
并不局限于UIImageView
,使用SDWebImageManager
可完成更多的操作:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL options:0 progress:^(NSUInteger receivedSize, long long expectedSize) {
// 下載進(jìn)度
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if (image)
{
// 下載完成
}
}];
或者使用Image Downloader
也是一樣的效果:
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:imageURL options:0 progress:^(NSUInteger receivedSize, long long expectedSize) {
// 進(jìn)度
} completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if (image && finished)
{
// 下載完成
}
}];
四趾代、SDCycleScrollView
1贯底、帶標(biāo)題的網(wǎng)絡(luò)圖片
SDCycleScrollView *cycleScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(0, 100, SCREEN_WIDTH, 200) delegate:self placeholderImage:[UIImage imageNamed:@"placeholder"]];
// page位置,默認(rèn)居中
cycleScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentRight;
// 自定義分頁控件小圓標(biāo)顏色
cycleScrollView.currentPageDotColor = [UIColor whiteColor];
// 添加標(biāo)題
cycleScrollView.titlesGroup = _titles;
[_ContainerView addSubview:cycleScrollView];
// 模擬加載延遲
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
cycleScrollView.imageURLStringsGroup = self->_imagesURLStrings;
});
// block監(jiān)聽點(diǎn)擊方式
cycleScrollView.clickItemOperationBlock = ^(NSInteger currentIndex) {
NSLog(@"block監(jiān)聽點(diǎn)擊方式撒强,位置為:%ld", (long)currentIndex);
};
2丈甸、自定義分頁控件
cycleScrollView.currentPageDotImage = [UIImage imageNamed:@"pageControlCurrentDot"];
cycleScrollView.pageDotImage = [UIImage imageNamed:@"pageControlDot"];
3、本地圖片
SDCycleScrollView *cycleScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(0, 650, SCREEN_WIDTH, 300) shouldInfiniteLoop:YES imageNamesGroup:_imageNames];
cycleScrollView.scrollDirection = UICollectionViewScrollDirectionVertical;
// 僅顯示文字
NSMutableArray *titlesArray = [NSMutableArray new];
[titlesArray addObject:@"純文字"];
[titlesArray addObjectsFromArray:_titles];
cycleScrollView.titlesGroup = [titlesArray copy];
[cycleScrollView disableScrollGesture];
[_ContainerView addSubview:cycleScrollView];
4尿褪、自定義cell的輪播圖
a、如果要實(shí)現(xiàn)自定義cell的輪播圖得湘,必須先實(shí)現(xiàn)代理方法
_customCellScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(0, 1000, SCREEN_WIDTH, 200) delegate:self placeholderImage:[UIImage imageNamed:@"placeholder"]];
_customCellScrollView.imageURLStringsGroup = _imagesURLStrings;
[_ContainerView addSubview:_customCellScrollView];
b杖玲、點(diǎn)擊圖片回調(diào)
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
NSLog(@"點(diǎn)擊了第%ld張圖片", (long)index);
[self.navigationController pushViewController:[NSClassFromString(@"DemoVC") new] animated:YES];
}
c、滾動(dòng)到第幾張圖回調(diào)
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didScrollToIndex:(NSInteger)index
{
NSLog(@"滾動(dòng)到第%ld張圖", (long)index);
}
五淘正、MBProgressHUD
實(shí)現(xiàn)MBProgressHUDDelegate
協(xié)議摆马,并聲明HUD
變量:
@interface ViewController () <MBProgressHUDDelegate>
{
MBProgressHUD *HUD;
}
#pragma mark - MBProgressHUDDelegate
- (void)hudWasHidden:(MBProgressHUD *)hud
{
[HUD removeFromSuperview];
HUD = nil;
}
在執(zhí)行某個(gè)異步請(qǐng)求時(shí)開始調(diào)用:
HUD = [MBProgressHUD showHUDAddedTo:self.webView animated:YES];
HUD.labelText = @"正在請(qǐng)求...";
HUD.mode = MBProgressHUDModeText;// mode參數(shù)可以控制顯示的模式
HUD.delegate = self;
請(qǐng)求完成時(shí)隱藏提示效果:
[HUD hide:YES];
對(duì)于同步方法一般都是用showWhileExecuting
方法臼闻,方法執(zhí)行完成之后會(huì)自動(dòng)隱藏:
[HUD showWhileExecuting:@selector(myTask) onTarget:self withObject:nil animated:YES];
配置進(jìn)度條的屬性
// 只能設(shè)置菊花的顏色 全局設(shè)置
[UIActivityIndicatorView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]].color = [UIColor redColor];
// 提示框格式 Determinate-圓形餅圖 HorizontalBar- 水平進(jìn)度條
// AnnularDeterminate-圓環(huán) CustomView-自定義視圖 Text-文本
self.progressHUD.mode = MBProgressHUDModeIndeterminate;
// 設(shè)置進(jìn)度框中的提示文字
self.progressHUD.label.text = @"加載中...";
// 信息詳情
_progressHUD.detailsLabel.text = @"人善如菊,夜涼如水...";
// 進(jìn)度指示器 模式是0囤采,取值從0.0————1.0
_progressHUD.progress = 0.5;
// 設(shè)置背景框的透明度述呐,默認(rèn)0.8
_progressHUD.bezelView.opaque = 1;
// 設(shè)置背景顏色之后opacity屬性的設(shè)置將會(huì)失效
_progressHUD.bezelView.color = [[UIColor redColor] colorWithAlphaComponent:1];
// 背景框的圓角值,默認(rèn)是10
_progressHUD.bezelView.layer.cornerRadius = 20;
// 置提示框的相對(duì)于父視圖中心點(diǎn)位置蕉毯,正值 向右下偏移乓搬,負(fù)值左上
[_progressHUD setOffset:CGPointMake(-80, -100)];
// 設(shè)置各個(gè)元素距離矩形邊框的距離
[_progressHUD setMargin:5];
// 背景框的最小尺寸
_progressHUD.minSize = CGSizeMake(50, 50);
// 是否強(qiáng)制背景框?qū)捀呦嗟?_progressHUD.square = YES;
// ZoomOut:逐漸的后退消失 ZoomIn:前進(jìn)淡化消失
// 默認(rèn)類型的,漸變
_progressHUD.animationType = MBProgressHUDAnimationFade;
// 設(shè)置最短顯示時(shí)間代虾,為了避免顯示后立刻被隱藏 默認(rèn)是0
_progressHUD.minShowTime = 5;
// 被調(diào)用方法在寬限期內(nèi)執(zhí)行完进肯,則HUD不會(huì)被顯示
// 為了避免在執(zhí)行很短的任務(wù)時(shí),去顯示一個(gè)HUD窗口
// _progressHUD.graceTime
// 設(shè)置隱藏的時(shí)候是否從父視圖中移除棉磨,默認(rèn)是NO
_progressHUD.removeFromSuperViewOnHide = NO;
// 顯示進(jìn)度框
[self.progressHUD showAnimated:YES];
// 兩種隱藏的方法
// [_progressHUD hideAnimated:YES];
[_progressHUD hideAnimated:YES afterDelay:5];
// 隱藏時(shí)候的回調(diào) 隱藏動(dòng)畫結(jié)束之后
_progressHUD.completionBlock = ^{
NSLog(@"哈哈哈哈哈哈哈哈哈");
};
六江掩、EmptyDataSet
#import <UIScrollView+EmptyDataSet.h>
@interface EmptyDetailViewController ()<DZNEmptyDataSetSource, DZNEmptyDataSetDelegate>
self.tableView.emptyDataSetSource = self;
self.tableView.emptyDataSetDelegate = self;
1、DZNEmptyDataSetSource
根據(jù)APP類型來設(shè)置空?qǐng)D的帶屬性標(biāo)題
- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView
{
NSString *text = nil;
UIFont *font = nil;
UIColor *textColor = nil;
NSMutableDictionary *attributes = [NSMutableDictionary new];
switch (self.application.type)
{
case ApplicationType500px:
{
text = @"No Photos";
font = [UIFont boldSystemFontOfSize:17.0];
textColor = [UIColor colorWithHex:@"545454"];
break;
}
......
if (!text)
{
return nil;
}
if (font)
{
[attributes setObject:font forKey:NSFontAttributeName];
}
if (textColor)
{
[attributes setObject:textColor forKey:NSForegroundColorAttributeName];
}
return [[NSAttributedString alloc] initWithString:text attributes:attributes];
}
根據(jù)APP類型來設(shè)置空?qǐng)D的帶屬性描述
- (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView
{
NSString *text = nil;
UIFont *font = nil;
UIColor *textColor = nil;
NSMutableDictionary *attributes = [NSMutableDictionary new];
NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
paragraph.alignment = NSTextAlignmentCenter;
switch (self.application.type)
{
case ApplicationType500px:
{
text = @"Get started by uploading a photo.";
font = [UIFont boldSystemFontOfSize:15.0];
textColor = [UIColor colorWithHex:@"545454"];
break;
}
......
if (!text)
{
return nil;
}
if (font) [attributes setObject:font forKey:NSFontAttributeName];
if (textColor) [attributes setObject:textColor forKey:NSForegroundColorAttributeName];
if (paragraph) [attributes setObject:paragraph forKey:NSParagraphStyleAttributeName];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
switch (self.application.type)
{
case ApplicationTypeSkype:
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithHex:@"00adf1"] range:[attributedString.string rangeOfString:@"add favorites"]];
break;
default:
break;
}
return attributedString;
}
獲取到占位圖
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView
{
if (self.isLoading)
{
return [UIImage imageNamed:@"loading_imgBlue_78x78" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
}
else
{
NSString *imageName = [[[NSString stringWithFormat:@"placeholder_%@", self.application.displayName] lowercaseString] stringByReplacingOccurrencesOfString:@" " withString:@"_"];
UIImage *image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
return image;
}
}
生成占位動(dòng)畫
- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 0.0)];
animation.duration = 0.25;
animation.cumulative = YES;
animation.repeatCount = MAXFLOAT;
return animation;
}
根據(jù)APP類型配置空?qǐng)D的按鈕屬性文本
- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
{
NSString *text = nil;
UIFont *font = nil;
UIColor *textColor = nil;
switch (self.application.type)
{
case ApplicationTypeAirbnb:
{
text = @"Start Browsing";
font = [UIFont boldSystemFontOfSize:16.0];
textColor = [UIColor colorWithHex:(state == UIControlStateNormal) ? @"05adff" : @"6bceff"];
break;
}
.....
if (!text)
{
return nil;
}
NSMutableDictionary *attributes = [NSMutableDictionary new];
if (font) [attributes setObject:font forKey:NSFontAttributeName];
if (textColor) [attributes setObject:textColor forKey:NSForegroundColorAttributeName];
return [[NSAttributedString alloc] initWithString:text attributes:attributes];
}
根據(jù)APP類型配置空?qǐng)D的按鈕屬性文本
- (UIImage *)buttonBackgroundImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
{
NSString *imageName = [[NSString stringWithFormat:@"button_background_%@", self.application.displayName] lowercaseString];
UIImage *image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
if (state == UIControlStateNormal) imageName = [imageName stringByAppendingString:@"_normal"];
if (state == UIControlStateHighlighted) imageName = [imageName stringByAppendingString:@"_highlight"];
// Insets
UIEdgeInsets capInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
UIEdgeInsets rectInsets = UIEdgeInsetsZero;
switch (self.application.type)
{
case ApplicationTypeFoursquare:
capInsets = UIEdgeInsetsMake(25.0, 25.0, 25.0, 25.0);
rectInsets = UIEdgeInsetsMake(0.0, 10, 0.0, 10);
break;
.....
return [[image resizableImageWithCapInsets:capInsets resizingMode:UIImageResizingModeStretch] imageWithAlignmentRectInsets:rectInsets];
}
背景顏色
- (UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView
{
switch (self.application.type)
{
case ApplicationType500px: return [UIColor blackColor];
case ApplicationTypeAirbnb: return [UIColor whiteColor];
.....
}
垂直偏移量
- (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView
{
if (self.application.type == ApplicationTypeKickstarter)
{
CGFloat offset = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
offset += CGRectGetHeight(self.navigationController.navigationBar.frame);
return -offset;
}
if (self.application.type == ApplicationTypeTwitter)
{
return -roundf(self.tableView.frame.size.height/2.5);
}
return 0.0;
}
空白高度
- (CGFloat)spaceHeightForEmptyDataSet:(UIScrollView *)scrollView
{
switch (self.application.type)
{
case ApplicationType500px: return 9.0;
case ApplicationTypeAirbnb: return 24.0;
......
}
2乘瓤、DZNEmptyDataSetDelegate
允許展示
- (BOOL)emptyDataSetShouldDisplay:(UIScrollView *)scrollView
{
return YES;
}
允許觸摸
- (BOOL)emptyDataSetShouldAllowTouch:(UIScrollView *)scrollView
{
return YES;
}
允許滾動(dòng)
- (BOOL)emptyDataSetShouldAllowScroll:(UIScrollView *)scrollView
{
return YES;
}
是否允許展示加載動(dòng)畫
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView
{
return self.isLoading;
}
點(diǎn)擊View的事件
- (void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view
{
self.loading = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.loading = NO;
});
}
點(diǎn)擊Button的事件
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button
{
self.loading = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.loading = NO;
});
}
七环形、MGSwipeTableCell
#import <MGSwipeTableCell.h>
@interface MailViewController ()<MGSwipeTableCellDelegate>
1、MGSwipeTableCellDelegate
配置按鈕
- (NSArray *)swipeTableCell:(MGSwipeTableCell*)cell swipeButtonsForDirection:(MGSwipeDirection)direction swipeSettings:(MGSwipeSettings*)swipeSettings expansionSettings:(MGSwipeExpansionSettings *)expansionSettings
{
swipeSettings.transition = MGSwipeTransitionBorder;
expansionSettings.buttonIndex = 0;
__weak MailViewController *weakSelf = self;
MailData *mail = [weakSelf mailForIndexPath:[self.tableView indexPathForCell:cell]];
if (direction == MGSwipeDirectionLeftToRight)// 從左向右滑{}
else{}// 從右向左滑
return nil;
}
從左向右滑
expansionSettings.fillOnTrigger = NO;
expansionSettings.threshold = 2;
return @[[MGSwipeButton buttonWithTitle:[weakSelf readButtonText:mail.read] backgroundColor:[UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0] padding:5 callback:^BOOL(MGSwipeTableCell *sender) {
MailData *mail = [weakSelf mailForIndexPath:[weakSelf.tableView indexPathForCell:sender]];
mail.read = !mail.read;
// 刷新單元格內(nèi)容時(shí)需要刷新
[weakSelf updateCellIndicactor:mail cell:(MailTableCell*)sender];
[cell refreshContentView];
[(UIButton *)[cell.leftButtons objectAtIndex:0] setTitle:[weakSelf readButtonText:mail.read] forState:UIControlStateNormal];
return YES;
}]];
從右向左滑
expansionSettings.fillOnTrigger = YES;
expansionSettings.threshold = 1.1;
CGFloat padding = 15;
MGSwipeButton *trash = [MGSwipeButton buttonWithTitle:@"Trash" backgroundColor:[UIColor colorWithRed:1.0 green:59/255.0 blue:50/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
NSIndexPath *indexPath = [weakSelf.tableView indexPathForCell:sender];
[weakSelf deleteMail:indexPath];
// 不自動(dòng)隱藏以改進(jìn)刪除動(dòng)畫
return NO;
}];
MGSwipeButton *flag = [MGSwipeButton buttonWithTitle:@"Flag" backgroundColor:[UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
MailData *mail = [weakSelf mailForIndexPath:[weakSelf.tableView indexPathForCell:sender]];
mail.flag = !mail.flag;
// 刷新單元格內(nèi)容時(shí)需要刷新
[weakSelf updateCellIndicactor:mail cell:(MailTableCell*)sender];
[cell refreshContentView];
return YES;
}];
MGSwipeButton *more = [MGSwipeButton buttonWithTitle:@"More" backgroundColor:[UIColor colorWithRed:200/255.0 green:200/255.0 blue:205/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
return NO;
}];
return @[trash, flag, more];
監(jiān)聽滑動(dòng)方向和按鈕狀態(tài)
- (void)swipeTableCell:(MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState)state gestureIsActive:(BOOL)gestureIsActive
{
NSString *string;
switch (state)
{
case MGSwipeStateNone: string = @"None"; break;
case MGSwipeStateSwippingLeftToRight: string = @"SwippingLeftToRight"; break;
case MGSwipeStateSwippingRightToLeft: string = @"SwippingRightToLeft"; break;
case MGSwipeStateExpandingLeftToRight: string = @"ExpandingLeftToRight"; break;
case MGSwipeStateExpandingRightToLeft: string = @"ExpandingRightToLeft"; break;
}
NSLog(@"Swipe state: %@ ::: Gesture: %@", string, gestureIsActive ? @"Active" : @"Ended");
}
輔助方法
- (NSString *)readButtonText:(BOOL) read
{
return read ? @"Mark as\nunread" :@"Mark as\nread";
}
- (MailData *)mailForIndexPath:(NSIndexPath*) path
{
return [self.demoData objectAtIndex:path.row];
}
- (void)deleteMail:(NSIndexPath *)indexPath
{
[self.demoData removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
更新指示器的顏色
- (void)updateCellIndicactor:(MailData *)mail cell:(MailTableCell *)cell
{
UIColor *color;
UIColor *innerColor;
if (!mail.read && mail.flag)
{
color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
innerColor = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
}
else if (mail.flag)
{
color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
}
else if (mail.read)
{
color = [UIColor clearColor];
}
else
{
color = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
}
cell.indicatorView.indicatorColor = color;
cell.indicatorView.innerColor = innerColor;
}
八衙傀、FSCalendar
1抬吟、Range Picker
導(dǎo)入頭文件
#import <FSCalendar/FSCalendar.h>
@interface RangePickerCell : FSCalendarCell
// 范圍的開始/結(jié)束
@property (weak, nonatomic) CALayer *selectionLayer;
// 范圍的中間
@property (weak, nonatomic) CALayer *middleLayer;
@end
@interface RangePickerViewController ()<FSCalendarDataSource,FSCalendarDelegate,FSCalendarDelegateAppearance>
@end
創(chuàng)建日歷視圖
- (void)createSubview
{
// 初始化屬性
self.gregorian = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
self.dateFormatter = [[NSDateFormatter alloc] init];
self.dateFormatter.dateFormat = @"yyyy-MM-dd";
// 創(chuàng)建calendar
FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), self.view.frame.size.width, self.view.frame.size.height - CGRectGetMaxY(self.navigationController.navigationBar.frame))];
calendar.dataSource = self;
calendar.delegate = self;
calendar.pagingEnabled = NO;
calendar.allowsMultipleSelection = YES;
calendar.rowHeight = 60;
calendar.placeholderType = FSCalendarPlaceholderTypeNone;
[self.view addSubview:calendar];
self.calendar = calendar;
calendar.appearance.titleDefaultColor = [UIColor blackColor];
calendar.appearance.headerTitleColor = [UIColor blackColor];
calendar.appearance.titleFont = [UIFont systemFontOfSize:16];
calendar.scope = FSCalendarScopeWeek;
calendar.weekdayHeight = 20;
calendar.swipeToChooseGesture.enabled = YES;
// Hide the today circle
// calendar.today = nil;
[calendar registerClass:[RangePickerCell class] forCellReuseIdentifier:@"RangePickerCell"];
}
FSCalendarDataSource
最小日期
- (NSDate *)minimumDateForCalendar:(FSCalendar *)calendar
{
return [self.dateFormatter dateFromString:@"2020-06-08"];
}
最大日期
- (NSDate *)maximumDateForCalendar:(FSCalendar *)calendar
{
return [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:10 toDate:[NSDate date] options:0];
}
今日的標(biāo)題
- (NSString *)calendar:(FSCalendar *)calendar titleForDate:(NSDate *)date
{
if ([self.gregorian isDateInToday:date])
{
return @"今";
}
return nil;
}
創(chuàng)建Cell
- (FSCalendarCell *)calendar:(FSCalendar *)calendar cellForDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
RangePickerCell *cell = [calendar dequeueReusableCellWithIdentifier:@"RangePickerCell" forDate:date atMonthPosition:monthPosition];
return cell;
}
配置Cell
- (void)calendar:(FSCalendar *)calendar willDisplayCell:(FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition: (FSCalendarMonthPosition)monthPosition
{
[self configureCell:cell forDate:date atMonthPosition:monthPosition];
}
FSCalendarDelegate
是否可以選中日期
- (BOOL)calendar:(FSCalendar *)calendar shouldSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
return monthPosition == FSCalendarMonthPositionCurrent;
}
是否支持反選日期
- (BOOL)calendar:(FSCalendar *)calendar shouldDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
return NO;
}
選中日期
- (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
// 如果選擇是由滑動(dòng)手勢(shì)引起的
if (calendar.swipeToChooseGesture.state == UIGestureRecognizerStateChanged)
{
if (!self.startDate)
{
self.startDate = date;
}
else
{
if (self.endDate)
{
[calendar deselectDate:self.endDate];
}
self.endDate = date;
}
}
else
{
if (self.endDate)
{
[calendar deselectDate:self.startDate];
[calendar deselectDate:self.endDate];
self.startDate = date;
self.endDate = nil;
}
else if (!self.startDate)
{
self.startDate = date;
}
else
{
self.endDate = date;
}
}
[self configureVisibleCells];
}
取消選中
- (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
NSLog(@"取消選中的日期為:%@",[self.dateFormatter stringFromDate:date]);
[self configureVisibleCells];
}
日期事件顏色
- (NSArray<UIColor *> *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
{
if ([self.gregorian isDateInToday:date])
{
return @[[UIColor orangeColor]];
}
return @[appearance.eventDefaultColor];
}
輔助方法
配置可見日期的選中狀態(tài)
- (void)configureVisibleCells
{
[self.calendar.visibleCells enumerateObjectsUsingBlock:^(__kindof FSCalendarCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDate *date = [self.calendar dateForCell:obj];
FSCalendarMonthPosition position = [self.calendar monthPositionForCell:obj];
[self configureCell:obj forDate:date atMonthPosition:position];
}];
}
配置每一個(gè)日期的選中狀態(tài)
- (void)configureCell:(__kindof FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)position
{
RangePickerCell *rangeCell = cell;
if (position != FSCalendarMonthPositionCurrent)
{
rangeCell.middleLayer.hidden = YES;
rangeCell.selectionLayer.hidden = YES;
return;
}
if (self.startDate && self.endDate)
{
BOOL isMiddle = [date compare:self.startDate] != [date compare:self.endDate];
rangeCell.middleLayer.hidden = !isMiddle;
}
else
{
rangeCell.middleLayer.hidden = YES;
}
BOOL isSelected = NO;
isSelected |= self.startDate && [self.gregorian isDate:date inSameDayAsDate:self.startDate];
isSelected |= self.endDate && [self.gregorian isDate:date inSameDayAsDate:self.endDate];
rangeCell.selectionLayer.hidden = !isSelected;
}
2、DIY
選中的是17號(hào)差油,但是打印結(jié)果顯示選中的是16日拗军,默認(rèn)選中的3天也各自少了一天,說明這個(gè)框架有Bug呀蓄喇。
2020-11-05 11:39:11.250332+0800 UseUIControlFramework[22930:4990809] did select date: 2020-11-17
2020-11-05 11:39:17.708906+0800 UseUIControlFramework[22930:4990809] 不是當(dāng)前處理的日期月份頁面(比如下一個(gè)月)則直接隱藏圓圈和選中圖層
2020-11-05 11:39:23.939118+0800 UseUIControlFramework[22930:4990809] 選中的日期包括:(
"2020-11-03 16:00:00 +0000",
"2020-11-04 16:00:00 +0000",
"2020-11-05 16:00:00 +0000",
"2020-11-16 16:00:00 +0000"
)
2020-11-05 11:40:15.690340+0800 UseUIControlFramework[22930:4990809] 選中則顯示并更新選中圖層
2020-11-05 13:37:58.433376+0800 UseUIControlFramework[22930:4990809] 未選中
2020-11-05 13:38:02.752246+0800 UseUIControlFramework[22930:4990809] 未選中則隱藏選中圖層
創(chuàng)建日歷視圖
- (void)createSubview
{
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
view.backgroundColor = [UIColor systemGroupedBackgroundColor];
self.view = view;
CGFloat height = [[UIDevice currentDevice].model hasPrefix:@"iPad"] ? 450 : 300;
FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame) + 44, view.frame.size.width, height)];
calendar.dataSource = self;
calendar.delegate = self;
calendar.swipeToChooseGesture.enabled = YES;// 支持滑動(dòng)選中手勢(shì)
calendar.allowsMultipleSelection = YES;// 支持多選
[view addSubview:calendar];
self.calendar = calendar;
// 頭部視圖
calendar.calendarHeaderView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.1];
// 周視圖
calendar.calendarWeekdayView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.1];
// 事件選中的顏色
calendar.appearance.eventSelectionColor = [UIColor whiteColor];
// 事件偏移量
calendar.appearance.eventOffset = CGPointMake(0, -7);
// 隱藏今天的圓圈
calendar.today = nil;
// 注冊(cè)Cell
[calendar registerClass:[DIYCalendarCell class] forCellReuseIdentifier:@"cell"];
// 扇動(dòng)的手勢(shì)
UIPanGestureRecognizer *scopeGesture = [[UIPanGestureRecognizer alloc] initWithTarget:calendar action:@selector(handleScopeGesture:)];
[calendar addGestureRecognizer:scopeGesture];
// 創(chuàng)建事件Label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(calendar.frame)+10, self.view.frame.size.width, 50)];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
[self.view addSubview:label];
self.eventLabel = label;
// 配置事件Label的文本屬性
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@""];
NSTextAttachment *attatchment = [[NSTextAttachment alloc] init];
attatchment.image = [UIImage imageNamed:@"icon_cat"];
attatchment.bounds = CGRectMake(0, -3, attatchment.image.size.width, attatchment.image.size.height);
[attributedText appendAttributedString:[NSAttributedString attributedStringWithAttachment:attatchment]];
[attributedText appendAttributedString:[[NSAttributedString alloc] initWithString:@" Hey Daily Event "]];
[attributedText appendAttributedString:[NSAttributedString attributedStringWithAttachment:attatchment]];
self.eventLabel.attributedText = attributedText.copy;
}
FSCalendarDataSource
事件數(shù)量
- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
{
return 2;
}
FSCalendarDelegate
調(diào)整事件Label的位置
- (void)calendar:(FSCalendar *)calendar boundingRectWillChange:(CGRect)bounds animated:(BOOL)animated
{
calendar.frame = (CGRect){calendar.frame.origin,bounds.size};
self.eventLabel.frame = CGRectMake(0, CGRectGetMaxY(calendar.frame)+10, self.view.frame.size.width, 50);
}
是否支持反選
- (BOOL)calendar:(FSCalendar *)calendar shouldDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
return monthPosition == FSCalendarMonthPositionCurrent;
}
選中日期
- (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
NSLog(@"did select date: %@",[self.dateFormatter stringFromDate:date]);
[self configureVisibleCells];
}
反選日期
- (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
NSLog(@"did deselect date: %@",[self.dateFormatter stringFromDate:date]);
[self configureVisibleCells];
}
輔助方法
配置cell
- (void)configureCell:(FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
DIYCalendarCell *diyCell = (DIYCalendarCell *)cell;
// 自定義今日?qǐng)A圈发侵,如果是今日則顯示紅色圓圈
diyCell.circleImageView.hidden = ![self.gregorian isDateInToday:date];
// 配置選擇圖層即邊框位置
if (monthPosition == FSCalendarMonthPositionCurrent)
{
SelectionType selectionType = SelectionTypeNone;
NSLog(@"選中的日期包括:%@",self.calendar.selectedDates);
if ([self.calendar.selectedDates containsObject:date])
{
NSDate *previousDate = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-1 toDate:date options:0];
NSDate *nextDate = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:1 toDate:date options:0];
if ([self.calendar.selectedDates containsObject:date])
{
if ([self.calendar.selectedDates containsObject:previousDate] && [self.calendar.selectedDates containsObject:nextDate])
{
// 選中日期包含昨天和明天則居中
selectionType = SelectionTypeMiddle;
}
else if ([self.calendar.selectedDates containsObject:previousDate] && [self.calendar.selectedDates containsObject:date])
{
// 選中日期包含昨天和今天則邊框居于右邊
selectionType = SelectionTypeRightBorder;
}
else if ([self.calendar.selectedDates containsObject:nextDate])
{
// 選中日期包含明天和今天則邊框居于左邊
selectionType = SelectionTypeLeftBorder;
}
else
{
// 只包含今天則只有一個(gè)邊框
selectionType = SelectionTypeSingle;
}
}
}
else
{
// 未選中
selectionType = SelectionTypeNone;
NSLog(@"未選中");
}
// 未選中則隱藏選中圖層直接返回
if (selectionType == SelectionTypeNone)
{
diyCell.selectionLayer.hidden = YES;
NSLog(@"未選中則隱藏選中圖層");
return;
}
// 選中則顯示并更新選中圖層
diyCell.selectionLayer.hidden = NO;
diyCell.selectionType = selectionType;
NSLog(@"選中則顯示并更新選中圖層");
}
else
{
// 不是當(dāng)前處理的日期月份頁面(比如下一個(gè)月)則直接隱藏圓圈和選中圖層
diyCell.circleImageView.hidden = YES;
diyCell.selectionLayer.hidden = YES;
NSLog(@"不是當(dāng)前處理的日期月份頁面(比如下一個(gè)月)則直接隱藏圓圈和選中圖層");
}
}
3、Prev-Next-Buttons
翻到上一頁
- (void)previousClicked:(id)sender
{
NSDate *currentMonth = self.calendar.currentPage;
NSDate *previousMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:-1 toDate:currentMonth options:0];
[self.calendar setCurrentPage:previousMonth animated:YES];
}
翻到下一頁
- (void)nextClicked:(id)sender
{
NSDate *currentMonth = self.calendar.currentPage;
NSDate *nextMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:currentMonth options:0];
[self.calendar setCurrentPage:nextMonth animated:YES];
}
4妆偏、Hide Placeholder
配置日歷屬性
calendar.placeholderType = FSCalendarPlaceholderTypeNone;// 隱藏占位日期
calendar.adjustsBoundingRectWhenChangingMonths = YES;// 當(dāng)月份改變的時(shí)候自動(dòng)調(diào)整矩形寬度
calendar.currentPage = [self.dateFormatter dateFromString:@"2020-06-01"];
calendar.firstWeekday = 2;// 以周一開始
calendar.scrollDirection = FSCalendarScrollDirectionVertical;// 垂直翻轉(zhuǎn)月份
5酣倾、Delegate Appearance
初始化顏色
// 默認(rèn)顏色
self.fillDefaultColors = @{@"2020/10/08":[UIColor purpleColor],// 紫色
@"2020/10/06":[UIColor greenColor],// 綠色
// 選中的顏色
self.fillSelectionColors = @{@"2020/10/08":[UIColor greenColor],// 選中后變?yōu)榫G色
@"2020/10/06":[UIColor purpleColor],// 選中后變?yōu)樽仙?// 邊框的顏色
self.borderDefaultColors = @{@"2020/10/08":[UIColor brownColor],// 棕色
// 邊框選中的顏色
self.borderSelectionColors = @{@"2020/10/08":[UIColor redColor],// 紅色
// 帶有事件的Date
self.datesWithEvent = @[@"2020-10-03",// 一個(gè)點(diǎn)
// 帶有多個(gè)事件的Date
self.datesWithMultipleEvents = @[@"2020-10-08",// 多個(gè)點(diǎn)
FSCalendarDelegateAppearance
日期事件的顏色組
- (NSArray *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
{
NSString *dateString = [self.dateFormatter2 stringFromDate:date];
if ([_datesWithMultipleEvents containsObject:dateString])
{
return @[[UIColor magentaColor],appearance.eventDefaultColor,[UIColor blackColor]];
}
return nil;
}
選中的顏色
- (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance fillSelectionColorForDate:(NSDate *)date
{
NSString *key = [self.dateFormatter1 stringFromDate:date];
if ([_fillSelectionColors.allKeys containsObject:key])
{
return _fillSelectionColors[key];
}
return appearance.selectionColor;
}
默認(rèn)的顏色
- (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance fillDefaultColorForDate:(NSDate *)date
{
NSString *key = [self.dateFormatter1 stringFromDate:date];
if ([_fillDefaultColors.allKeys containsObject:key])
{
return _fillDefaultColors[key];
}
return nil;
}
邊框的顏色
- (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderDefaultColorForDate:(NSDate *)date
{
NSString *key = [self.dateFormatter1 stringFromDate:date];
if ([_borderDefaultColors.allKeys containsObject:key])
{
return _borderDefaultColors[key];
}
return appearance.borderDefaultColor;
}
邊框選中的顏色
- (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderSelectionColorForDate:(NSDate *)date
{
NSString *key = [self.dateFormatter1 stringFromDate:date];
if ([_borderSelectionColors.allKeys containsObject:key])
{
return _borderSelectionColors[key];
}
return appearance.borderSelectionColor;
}
邊框的圓角大小
- (CGFloat)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderRadiusForDate:(nonnull NSDate *)date
{
if ([@[@8,@17,@21,@25] containsObject:@([self.gregorian component:NSCalendarUnitDay fromDate:date])])
{
return 0.0;// 矩形
}
return 1.0;// 圓形
}
FSCalendarDataSource
日期包含的事件個(gè)數(shù)
- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
{
NSString *dateString = [self.dateFormatter2 stringFromDate:date];
if ([_datesWithEvent containsObject:dateString])
{
return 1;
}
if ([_datesWithMultipleEvents containsObject:dateString])
{
return 3;
}
return 0;
}
6、Full Screen
#import <EventKit/EventKit.h>// 事件
@property (strong, nonatomic) NSArray<EKEvent *> *events;
Privacy - Calendars Usage Description 需要使用日歷權(quán)限
根據(jù)國歷日期獲得對(duì)應(yīng)農(nóng)歷日期
創(chuàng)建中國日歷
- (instancetype)init
{
self = [super init];
if (self)
{
self.chineseCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
self.formatter = [[NSDateFormatter alloc] init];
self.formatter.calendar = self.chineseCalendar;
self.formatter.dateFormat = @"M";
self.lunarDays = @[@"初二",@"初三",@"初四",@"初五",@"初六",@"初七",@"初八",@"初九",@"初十",@"十一",@"十二",@"十三",@"十四",@"十五",@"十六",@"十七",@"十八",@"十九",@"二十",@"二一",@"二二",@"二三",@"二四",@"二五",@"二六",@"二七",@"二八",@"二九",@"三十"];
self.lunarMonths = @[@"正月",@"二月",@"三月",@"四月",@"五月",@"六月",@"七月",@"八月",@"九月",@"十月",@"冬月",@"臘月"];
}
return self;
}
根據(jù)國歷日期獲得對(duì)應(yīng)農(nóng)歷日期
- (NSString *)stringFromDate:(NSDate *)date
{
NSInteger day = [self.chineseCalendar component:NSCalendarUnitDay fromDate:date];
if (day != 1)
{
return self.lunarDays[day-2];// 不是第一天則返回對(duì)應(yīng)農(nóng)歷Day
}
// First day of month
NSString *monthString = [self.formatter stringFromDate:date];
if ([self.chineseCalendar.veryShortMonthSymbols containsObject:monthString])
{
return self.lunarMonths[monthString.integerValue-1];
}
// 閏月
NSInteger month = [self.chineseCalendar component:NSCalendarUnitMonth fromDate:date];
monthString = [NSString stringWithFormat:@"閏%@", self.lunarMonths[month-1]];
return monthString;
}
從系統(tǒng)日歷中獲取限定日期范圍內(nèi)的日歷事件
- (void)loadCalendarEvents
{
__weak typeof(self) weakSelf = self;
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if(granted)
{
NSDate *startDate = self.minimumDate;
NSDate *endDate = self.maximumDate;
NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
NSArray<EKEvent *> *eventList = [store eventsMatchingPredicate:fetchCalendarEvents];
NSArray<EKEvent *> *events = [eventList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable event, NSDictionary<NSString *,id> * _Nullable bindings) {
return event.calendar.subscribed;
}]];
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf) return;
weakSelf.events = events;
[weakSelf.calendar reloadData];
});
}
else
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"權(quán)限錯(cuò)誤" message:@"獲取事件需要日歷權(quán)限" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
}];
}
從日期獲取對(duì)應(yīng)事件并加入緩存
- (NSArray<EKEvent *> *)eventsForDate:(NSDate *)date
{
NSArray<EKEvent *> *events = [self.cache objectForKey:date];
if ([events isKindOfClass:[NSNull class]])
{
return nil;
}
// 過濾事件
NSArray<EKEvent *> *filteredEvents = [self.events filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
// 判斷條件是發(fā)生的日期相等
return [evaluatedObject.occurrenceDate isEqualToDate:date];
}]];
// 將事件加入緩存
if (filteredEvents.count)
{
[self.cache setObject:filteredEvents forKey:date];
}
else
{
[self.cache setObject:[NSNull null] forKey:date];
}
return filteredEvents;
}
FSCalendarDelegate
每個(gè)日期的事件個(gè)數(shù)
- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
{
if (!self.showsEvents) return 0;
if (!self.events) return 0;
NSArray<EKEvent *> *events = [self eventsForDate:date];
return events.count;
}
每個(gè)日期的事件顏色
- (NSArray<UIColor *> *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
{
if (!self.showsEvents) return nil;
if (!self.events) return nil;
NSArray<EKEvent *> *events = [self eventsForDate:date];
NSMutableArray<UIColor *> *colors = [NSMutableArray arrayWithCapacity:events.count];
[events enumerateObjectsUsingBlock:^(EKEvent * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[colors addObject:[UIColor colorWithCGColor:obj.calendar.CGColor]];
}];
return colors.copy;
}
FSCalendarDataSource
每個(gè)日期的副標(biāo)題
- (NSString *)calendar:(FSCalendar *)calendar subtitleForDate:(NSDate *)date
{
// 顯示事件
if (self.showsEvents)
{
EKEvent *event = [self eventsForDate:date].firstObject;
if (event)
{
return event.title;
}
}
// 顯示農(nóng)歷
if (self.showsLunar)
{
return [self.lunarFormatter stringFromDate:date];
}
return nil;
}
九璧帝、Toast
1黄痪、最簡單的Toast
[self.navigationController.view makeToast:@"Toast"];
2、持續(xù)指定時(shí)間的Toast
[self.navigationController.view makeToast:@"持續(xù)3秒的Toast" duration:3.0 position:CSToastPositionTop];
3见秽、所有Toast共享的風(fēng)格
CSToastStyle *style = [[CSToastStyle alloc] initWithDefaultStyle];
style.messageFont = [UIFont fontWithName:@"Zapfino" size:14.0];
style.messageColor = [UIColor redColor];
style.messageAlignment = NSTextAlignmentCenter;
style.backgroundColor = [UIColor yellowColor];
style.titleColor = [UIColor blackColor];
[CSToastManager setSharedStyle:style];
[self.navigationController.view makeToast:@"This is a piece of toast with a title" duration:2.0 position:CSToastPositionTop title:@"文藝復(fù)興運(yùn)動(dòng)" image:[UIImage imageNamed:@"luckcoffee.JPG"] style:style completion:^(BOOL didTap) {
if (didTap)
{
NSLog(@"completion from tap");
}
else
{
NSLog(@"completion without tap");
}
}];
4愉烙、顯示加載中的指示器
if (!self.isShowingActivity)
{
[self.navigationController.view makeToastActivity:CSToastPositionCenter];
}
else
{
[self.navigationController.view hideToastActivity];
}
_showingActivity = !self.isShowingActivity;
[tableView reloadData];
5、隱藏Toast
[self.navigationController.view hideToast];
[self.navigationController.view hideAllToasts];
6解取、Toast是否可消失/可退出
[_tapToDismissSwitch setOn:[CSToastManager isTapToDismissEnabled]];// !!!Dimiss Toast
[_queueSwitch setOn:[CSToastManager isQueueEnabled]];// !!!Queue Toast
- (void)handleTapToDismissToggled
{
[CSToastManager setTapToDismissEnabled:![CSToastManager isTapToDismissEnabled]];
}
- (void)handleQueueToggled
{
[CSToastManager setQueueEnabled:![CSToastManager isQueueEnabled]];
}
十步责、zhPopupController
1、提示框
2020-11-09 16:16:43.370131+0800 UseUIControlFramework[92556:7149086] 城市切換的提示框
2020-11-09 16:59:09.136253+0800 UseUIControlFramework[92556:7149086] 點(diǎn)擊了取消按鈕:取消
2020-11-09 16:59:09.812307+0800 UseUIControlFramework[92556:7149086] 點(diǎn)擊了提交按鈕:提交
創(chuàng)建提示框
- (zhPopupController *)switchCitiesStyle
{
if (!_switchCitiesStyle)
{
CustomAlertView *alertView = [self createHorizontalAlertView];
// 展示方式為提示框
_switchCitiesStyle = [[zhPopupController alloc] initWithView:alertView size:alertView.bounds.size];
_switchCitiesStyle.presentationStyle = zhPopupSlideStyleTransform;
_switchCitiesStyle.presentationTransformScale = 1.25;
_switchCitiesStyle.dismissonTransformScale = 0.85;
}
return _switchCitiesStyle;
}
點(diǎn)擊按鈕呈現(xiàn)提示框
- (void)test1
{
[self.switchCitiesStyle showInView:self.view.window completion:^{
NSLog(@"城市切換的提示框");
}];
}
2、Toast
2020-11-11 11:38:04.418462+0800 UseUIControlFramework[36230:8555649] 詢問喜好的Toast
創(chuàng)建Toast
- (zhPopupController *)toastStyle
{
if (!_toastStyle)
{
CustomAlertView *alertView = [self createFavouriteToastView];
// 展示方式為Toast
_toastStyle = [[zhPopupController alloc] initWithView:alertView size:alertView.bounds.size];
_toastStyle.presentationStyle = zhPopupSlideStyleTransform;
_toastStyle.maskType = zhPopupMaskTypeDarkBlur;// 黑色模糊遮罩
_toastStyle.dismissOnMaskTouched = NO;// 點(diǎn)擊黑色模糊遮罩則Toast消失
}
return _toastStyle;
}
點(diǎn)擊按鈕呈現(xiàn)Toast
- (void)test2
{
// 0.75秒后自動(dòng)消失
[self.toastStyle showInView:self.view.window duration:0.75 bounced:YES completion:^{
NSLog(@"詢問喜好的Toast");
}];
}
3蔓肯、帶圖片的提示框
2020-11-11 15:14:44.412847+0800 UseUIControlFramework[39522:8695494] 展示火箭視圖
2020-11-11 15:14:45.804308+0800 UseUIControlFramework[39522:8695494] 點(diǎn)擊了查看詳情
創(chuàng)建火箭彈出視圖
- (zhPopupController *)overflyStyle
{
if (!_overflyStyle)
{
OverflyView *overflyView = [self createOverflyView];
_overflyStyle = [[zhPopupController alloc] initWithView:overflyView size:overflyView.bounds.size];
_overflyStyle.dismissOnMaskTouched = NO;
// 從底部滑出
_overflyStyle.presentationStyle = zhPopupSlideStyleFromBottom;
// 從頂部消失
_overflyStyle.dismissonStyle = zhPopupSlideStyleFromTop;
// 控制彈出視圖偏離的位置
_overflyStyle.offsetSpacing = 20;
}
return _overflyStyle;
}
點(diǎn)擊展示火箭視圖
- (void)test3
{
[self.overflyStyle showInView:self.view.window completion:^{
NSLog(@"展示火箭視圖");
}];
}
4遂鹊、窗簾
創(chuàng)建窗簾彈出視圖
- (zhPopupController *)qzoneStyle
{
if (!_qzoneStyle)
{
CurtainView *curtainView = [self createCurtainView];
_qzoneStyle = [[zhPopupController alloc] initWithView:curtainView size:curtainView.bounds.size];
_qzoneStyle.layoutType = zhPopupLayoutTypeTop;// 位置在頂部
_qzoneStyle.presentationStyle = zhPopupSlideStyleFromTop;// 從頂部滑入呈現(xiàn)
_qzoneStyle.offsetSpacing = -30;// 偏移量
__weak typeof(self) weakSelf = self;
// 窗簾即將呈現(xiàn)的時(shí)候狀態(tài)欄文字變暗
_qzoneStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
weakSelf.isLightStatusBar = NO;
};
// 窗簾即將消失的時(shí)候狀態(tài)欄文字變亮
_qzoneStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
weakSelf.isLightStatusBar = YES;
};
}
return _qzoneStyle;
}
點(diǎn)擊后彈出窗簾視圖
- (void)test4
{
[self.qzoneStyle showInView:self.view.window duration:0.75 bounced:YES completion:^{
NSLog(@"點(diǎn)擊后彈出窗簾視圖");
}];
}
提供窗簾視圖按鈕的點(diǎn)擊事件
- (CurtainView *)createCurtainView
{
CurtainView *curtainView = [self curtainView];
__weak typeof(self) weakSelf = self;
// 點(diǎn)擊后窗簾消失
curtainView.closeClicked = ^(UIButton *closeButton) {
[weakSelf.qzoneStyle dismiss];
};
// 點(diǎn)擊后彈出提示框
curtainView.didClickItems = ^(CurtainView *curtainView, NSInteger index) {
[self showAlert:curtainView.items[index].titleLabel.text];
};
return curtainView;
}
彈出提示框
- (void)showAlert:(NSString *)text
{
UILabel *label = [UILabel new];
label.backgroundColor = [UIColor whiteColor];
label.frame = CGRectMake(0, 0, 270, 70);
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
label.layer.cornerRadius = 3;
label.layer.masksToBounds = YES;
label.text = text;
label.font = [UIFont fontWithName:@"palatino-boldItalic" size:20];
zhPopupController *popupController = [[zhPopupController alloc] initWithView:label size:label.bounds.size];
popupController.dismissAfterDelay = 1;// 1秒后消失
popupController.maskType = zhPopupMaskTypeBlackOpacity;// 黑色遮罩
popupController.presentationStyle = zhPopupSlideStyleTransform;
popupController.layoutType = zhPopupLayoutTypeTop;// 位置在頂部
popupController.offsetSpacing = 90;// 偏移量
UIView *window = UIApplication.sharedApplication.keyWindow;
[popupController showInView:window duration:0.55 delay:0 options:UIViewAnimationOptionCurveLinear bounced:YES completion:nil];
}
5、側(cè)邊欄
創(chuàng)建側(cè)邊欄視圖
- (zhPopupController *)sidebarStyle
{
if (!_sidebarStyle)
{
SidebarView *sidebar = [self createSidebarView];
_sidebarStyle = [[zhPopupController alloc] initWithView:sidebar size:sidebar.bounds.size];
_sidebarStyle.layoutType = zhPopupLayoutTypeLeft;// 布局在左邊
_sidebarStyle.presentationStyle = zhPopupSlideStyleFromLeft;// 從左邊出現(xiàn)
_sidebarStyle.panGestureEnabled = YES;// 支持扇動(dòng)手勢(shì)
_sidebarStyle.panDismissRatio = 0.5;// 到Sidebar出現(xiàn)的比例少于自身一半的時(shí)候則隱藏
}
return _sidebarStyle;
}
點(diǎn)擊后彈出側(cè)邊欄
- (void)test5
{
[self.sidebarStyle showInView:self.view.window completion:^{
NSLog(@"點(diǎn)擊后彈出側(cè)邊欄");
}];
}
實(shí)現(xiàn)側(cè)邊欄按鈕的點(diǎn)擊事件
- (SidebarView *)createSidebarView
{
SidebarView *sidebar = [self sidebarView];
__weak typeof(self) weakSelf = self;
sidebar.didClickItems = ^(SidebarView *sidebarView, NSInteger index) {
[weakSelf.sidebarStyle dismiss];
[self showAlert:sidebarView.items[index].titleLabel.text];
};
return sidebar;
}
6蔗包、全屏視圖
創(chuàng)建全屏視圖
- (zhPopupController *)fullStyle
{
if (!_fullStyle)
{
FullView *fullView = [self createFullView];
_fullStyle = [[zhPopupController alloc] initWithView:fullView size:fullView.bounds.size];
_fullStyle.maskType = zhPopupMaskTypeExtraLightBlur;
_fullStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
[fullView startAnimationsWithCompletion:^(BOOL finished) {
NSLog(@"彈出全屏視圖完成");
}];
};
}
return _fullStyle;
}
點(diǎn)擊彈出全屏視圖
- (void)test6
{
[self.fullStyle showInView:self.view.window completion:^{
NSLog(@"點(diǎn)擊彈出全屏視圖");
}];
}
7秉扑、分享視圖
創(chuàng)建分享視圖
- (zhPopupController *)shareStyle
{
if (!_shareStyle)
{
WallView *wallView = [self createShareView];
_shareStyle = [[zhPopupController alloc] initWithView:wallView size:wallView.bounds.size];
_shareStyle.layoutType = zhPopupLayoutTypeBottom;
_shareStyle.presentationStyle = zhPopupSlideStyleFromBottom;
}
return _shareStyle;
}
點(diǎn)擊彈出分享視圖
- (void)test7
{
[self.shareStyle showInView:self.view.window duration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseInOut bounced:NO completion:nil];
}
8、鍵盤視圖
創(chuàng)建登陸注冊(cè)視圖
- (zhPopupController *)centerKeyboardStyle
{
if (!_centerKeyboardStyle)
{
UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 236)];
[backView addSubview:self.centerKeyboardView];
_centerKeyboardStyle = [[zhPopupController alloc] initWithView:backView size:backView.bounds.size];
_centerKeyboardStyle.maskType = zhPopupMaskTypeBlackOpacity;
_centerKeyboardStyle.layoutType = zhPopupLayoutTypeCenter;
_centerKeyboardStyle.presentationStyle = zhPopupSlideStyleFromBottom;
_centerKeyboardStyle.keyboardOffsetSpacing = 50;// 調(diào)整鍵盤間距
_centerKeyboardStyle.keyboardChangeFollowed = YES;// YES將在鍵盤更改時(shí)調(diào)整視圖位置
_centerKeyboardStyle.becomeFirstResponded = YES;
__weak typeof(self) weakSelf = self;
_centerKeyboardStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
[weakSelf.centerKeyboardView.phoneNumberField becomeFirstResponder];
};
_centerKeyboardStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
if (weakSelf.centerKeyboardView.phoneNumberField.isFirstResponder)
{
[weakSelf.centerKeyboardView.phoneNumberField resignFirstResponder];
}
if (weakSelf.registerKeyboardView.phoneNumberField.isFirstResponder)
{
[weakSelf.registerKeyboardView.phoneNumberField resignFirstResponder];
}
};
}
return _centerKeyboardStyle;
}
創(chuàng)建評(píng)論視圖
- (zhPopupController *)commentKeyboardStyle
{
if (!_commentKeyboardStyle)
{
CGRect rect = CGRectMake(0, 0, self.view.width, 60);
CommentKeyboardView *commentKeyboardView = [[CommentKeyboardView alloc] initWithFrame:rect];
__weak typeof(self) weakSelf = self;
commentKeyboardView.senderClickedBlock = ^(CommentKeyboardView *keyboardView, UIButton *button) {
[weakSelf.commentKeyboardStyle dismiss];
};
_commentKeyboardStyle = [[zhPopupController alloc] initWithView:commentKeyboardView size:commentKeyboardView.bounds.size];
_commentKeyboardStyle.maskType = zhPopupMaskTypeDarkBlur;
_commentKeyboardStyle.layoutType = zhPopupLayoutTypeBottom;
_commentKeyboardStyle.presentationStyle = zhPopupSlideStyleFromBottom;
_commentKeyboardStyle.becomeFirstResponded = YES;
_commentKeyboardStyle.keyboardChangeFollowed = YES;
_commentKeyboardStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
[commentKeyboardView.commentTextField becomeFirstResponder];
};
_commentKeyboardStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
[commentKeyboardView.commentTextField resignFirstResponder];
};
}
return _commentKeyboardStyle;
}
Demo
Demo在我的Github上调限,歡迎下載舟陆。
UseFrameworkDemo