把自己以往做的項目中的一些小功能摳出來寫在這里陕见,供大家使用,會一直持續(xù)更新
UITextView自適應(yīng)高度
1.KVO
//靜態(tài)變量的地址可以保證context的獨(dú)一無二
static void * abc = &abc;
- (void)viewDidLoad {
[super viewDidLoad];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 20, 200, 35)];
[self.view addSubview:textView];
textView.layer.borderColor = [UIColor lightGrayColor].CGColor;
textView.layer.borderWidth = 1;
textView.layer.cornerRadius = 5;
textView.font = [UIFont systemFontOfSize:20];
//為textView添加一個觀察者,來觀察他的contentSize屬性的變化
//context:上下文. 對某一個屬性或者方法之類的 跨方法使用時的唯一標(biāo)識
[textView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:abc];
}
//當(dāng)前對象 如果觀察到了 某些變化時就會觸發(fā)下方的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//使用context作為判斷依據(jù) 盡量不要使用keyPath
if (context == abc) {
NSLog(@"%@", change);
CGSize size = [change[@"new"] CGSizeValue];
UITextView *textView = (UITextView *)object;
CGRect frame = textView.frame;
//限制高度 根據(jù)打印局雄,5行時 高度136 高度未變化也不更新布局
if (size.height > 140 || size.height == frame.size.height) {
return;
}
frame.size.height = size.height;
textView.frame = frame;
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
2.sizeThatFits:
//文本更改時觸發(fā)高度自適應(yīng)
- (void)textViewDidChange:(UITextView *)textView {
//根據(jù)文本調(diào)整textView的高度
CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(textView.frame.size.width-16, MAXFLOAT)];
//判斷高度是否變化,未變化不重新布局
if (sizeToFit.height != textView.frame.size.height) {
textView.frame = CGRectMake(textView.frame.origin.x, textView.frame.origin.y, textView.frame.size.width, sizeToFit.height);
}
}
實現(xiàn)二維碼掃描的空心遮罩
cropRect為掃描二維碼框的Rect
1.CoreGraphics -> CGPath
- (void)setCropRect:(CGRect)cropRect{
CAShapeLayer *cropLayer = [[CAShapeLayer alloc] init];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, nil, cropRect);
CGPathAddRect(path, nil, self.view.bounds);
[cropLayer setFillRule:kCAFillRuleEvenOdd];//生成空心遮罩
[cropLayer setPath:path];
CFRelease(path);//CF對象記得手動釋放
[cropLayer setFillColor:[UIColor blackColor].CGColor];
[cropLayer setOpacity:0.3];
[cropLayer setNeedsDisplay];
[self.view.layer addSublayer:cropLayer];
}
2.UIKit -> UIBezierPath
- (void)setCropRect:(CGRect)cropRect{
CAShapeLayer *cropLayer = [[CAShapeLayer alloc] init];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.view.bounds cornerRadius:0];
UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:cropRect];
[path appendPath:rectPath];
[cropLayer setFillRule:kCAFillRuleEvenOdd];//生成空心遮罩
[cropLayer setPath:path.CGPath];
[cropLayer setFillColor:[UIColor blackColor].CGColor];
[cropLayer setOpacity:0.3];
[cropLayer setNeedsDisplay];
[self.view.layer addSublayer:cropLayer];
}
空心遮罩.PNG
UIImageView的手勢縮放
通過UIScrollViewDelegate中的代理方法來對UIImageView實現(xiàn)簡單的縮放功能
附加手勢實現(xiàn):
縮放比例為1(未進(jìn)行縮放)時存炮,放大倍數(shù)
縮放比例大于1(進(jìn)行過縮放)時炬搭,還原倍數(shù)
_scrollView.minimumZoomScale = 1.0; // 最小縮放比例
_scrollView.maximumZoomScale = 6.0; // 最大縮放比例
_imageView.userInteractionEnabled = YES; // 記得打開UIImageView的用戶交互,否則手勢無法觸發(fā)
#pragma mark - UIScrollView Delegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return _imageView; // 指定需要縮放的view穆桂,否則無法實現(xiàn)縮放功能(可為多個view)
}
#pragma mark - GestureRecogizer Method
- (void)addGestureRecognizer {
// 雙擊的 Recognizer
UITapGestureRecognizer* doubleRecognizer;
doubleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
doubleRecognizer.numberOfTapsRequired = 2; // 雙擊
// _imageView添加雙擊手勢
[_imageView addGestureRecognizer:doubleRecognizer];
}
-(void)doubleTap:(UITapGestureRecognizer*)recognizer
{
if (_scrollView.zoomScale > 1.0) {//放大過 --> 還原大小
[UIView animateWithDuration:.2 animations:^{
_scrollView.zoomScale = 1.0;
}];
} else {//未放大 --> 放大2倍
[UIView animateWithDuration:.2 animations:^{
_scrollView.zoomScale = 2.0;
}];
}
}
手勢縮放.gif
JSON與JSON字符串相互轉(zhuǎn)換
1.JSON轉(zhuǎn)JSON字符串
思路:NSDictionary/NSArray -> NSData -> NSString
方法:
+ (NSString *)parseJSONToJSONString:(id)JSON {
NSError *error;
NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSON options:NSJSONWritingPrettyPrinted error:&error];
NSString *JSONString = [[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding];
return JSONString;
}
2.JSON字符串轉(zhuǎn)JSON
思路:NSString -> NSData -> NSDictionary/NSArray
方法:
+ (id)parseJSONStringToJSON:(NSString *)JSONString {
NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
id JSON = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableLeaves error:nil];
return JSON;
}
備注:
1.NSJSONReadingOptions
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
NSJSONReadingMutableContainers = (1UL << 0),
NSJSONReadingMutableLeaves = (1UL << 1),
NSJSONReadingAllowFragments = (1UL << 2)
} API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
NSJSONReadingMutableContainers // 返回可變?nèi)萜鞴琋SMutableDictionary或NSMutableArray
NSJSONReadingMutableLeaves // 不僅返回的最外層是可變的, 內(nèi)部的子數(shù)值或字典也是可變對象
NSJSONReadingAllowFragments // 返回允許JSON字符串最外層既不是NSArray也不是NSDictionary,但必須是有效的JSON Fragment.
2.NSJSONWritingOptions
typedef NS_OPTIONS(NSUInteger, NSJSONWritingOptions) {
NSJSONWritingPrettyPrinted = (1UL << 0),
NSJSONWritingSortedKeys API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) = (1UL << 1)
} API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
NSJSONWritingPrettyPrinted // 是將生成的json數(shù)據(jù)格式化輸出享完,這樣可讀性高灼芭,不設(shè)置則輸出的json字符串就是一整行
NSJSONWritingSortedKeys // 輸出的json字符串就是一整行 僅支持iOS11以上
利用UIBezierPath繪制三角形
- (void)drawRect:(CGRect)rect {
//繪制路徑
UIBezierPath *path = [UIBezierPath bezierPath];
//設(shè)置顏色
[self.triangleColor set];
//-------------繪制三角形------------
//
// B
// /\
// / \
// / \
// /__ __\
// A C
//
//設(shè)置起點 A
[path moveToPoint:CGPointMake(0, rect.size.height)];
//添加一根線到某個點 B
[path addLineToPoint:CGPointMake(rect.size.width * 0.5, 0)];
//添加一根線到某個點 C
[path addLineToPoint:CGPointMake(rect.size.width, rect.size.height)];
//關(guān)閉路徑
[path closePath];
//填充(會把顏色填充進(jìn)去)
[path fill];
}
驗證碼倒計時
- (void)theCountdown
{
__block int timeout = 60;
__weak __typeof(self)weakSelf = self;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC); intervalInSeconds(倒計時間隔),leeway(期望的延遲時間)
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//dispatch_source_set_event_handler(dispatch_source_t source, dispatch_block_t _Nullable handler); dispatch_block_t 為block
dispatch_source_set_event_handler(timer, ^{
//因為^{}為block,有循環(huán)引用問題般又,所以需要弱引用倒計時按鈕
if(timeout<=0){
//倒計時結(jié)束彼绷,關(guān)閉
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.codeBtn setTitle:@"發(fā)送驗證碼" forState:0];
[weakSelf.codeBtn setTitleColor:[UIColor whiteColor] forState:0];
[weakSelf.codeBtn setUserInteractionEnabled:YES];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.codeBtn setTitle:[NSString stringWithFormat:@"%ds",timeout] forState:0];
[weakSelf.codeBtn setTitleColor:[UIColor whiteColor] forState:0];
[weakSelf.codeBtn setUserInteractionEnabled:NO];
});
timeout--;
}
});
dispatch_resume(timer);
}
驗證碼倒計時.gif
下拉放大
#define headerHeight 200
@property (nonatomic, strong) UIImageView *iconIV;
- (void)viewDidLoad {
[super viewDidLoad];
self.iconIV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scrollViewImage"]];
self.iconIV.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, headerHeight);
//放大時不改變寬高比例
self.iconIV.contentMode = UIViewContentModeScaleAspectFill;
self.iconIV.clipsToBounds = YES;
/*
頭部視圖 x y width 都是不能設(shè)置的 而圖片要隨著下拉 調(diào)整y軸 所以圖片不能直接作為頭部視圖
可以把圖片放到一個view里 view作為頭部 而且view不能剪切子視圖
*/
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, headerHeight)];
headerView.clipsToBounds = NO;//不剪切子視圖超出部分!!!
[headerView addSubview:self.iconIV];
self.tableView.tableHeaderView = headerView;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
cell.textLabel.text = @"這是個下拉放大的Demo!";
return cell;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGPoint offset = scrollView.contentOffset;
NSLog(@"%f", offset.y);
//根據(jù)打印值:向上移動 正數(shù) 向下移動 負(fù)數(shù)
CGFloat height = headerHeight - offset.y;
self.iconIV.frame = CGRectMake(0, offset.y, self.view.frame.size.width, height);
}
下拉放大.gif