iOS的各种奇淫怪技, 不定时更新

本文仅记录日常iOS开发的一些技巧, 不定时更新, 最新的置顶, 欢迎关注打赏订阅

5.记录百度地图的一个bug:

百度地图刷新页面标注点的时候, 首先需要删除所有标注,如下

//删除所有标注
    NSArray *arrayAnmation=[[NSArray alloc] initWithArray:_mapView.annotations];
    [_mapView removeAnnotations:arrayAnmation];

然后添加新的标注:

 [_mapView addAnnotation:point];

添加完标注之后, 就会响应下面的回调:

- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation{

      BMKAnnotationView* view = nil;
      view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
}

问题就出在上面的view, 调用复用之后, 心想已经删除所有标注了, 调用[mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];后应该返回nil, 但在添加第一个标注点的时候, 发现会有返回值, 而不是空. 除了第一个标注点之外, 却不会有返回值, 于是加入下面的代码:

- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation{

      BMKAnnotationView* view = nil;
      view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
if (view == nil) {
                
                view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"start_node"];
}else{
              view = nil;
              view = [[BMKAnnotationView alloc]initWithAnnotation:routeAnnotation reuseIdentifier:@"start_node"];
}
return view;
}

总结: 删除标注点后, 内存还会有一份复用的view保存着, UITableView的复用机制应该也是这样的. 所以即使删除了所有复用视图, 还是要判空一下.

4.有些场景下, 我们使用Masonry进行自动布局时, 会获取不到frame或者bounds

例如当想设置图片只有两个圆角的时候, 或者设置控件需要取得frame的时候, 会发现frame或者bounds都为0, 即这样设置圆角时:

_thumbView = [[UIImageView alloc] init];
    [self.contentView addSubview:_thumbView];
    [_thumbView mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.left.equalTo(_bubbleView.mas_left);
        make.size.mas_equalTo(CGSizeMake(kGridViewHeight, kGridViewHeight ));
        make.top.equalTo(_bubbleView.mas_top);
    }];
    
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_thumbView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake(6, 6)];

    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame = _thumbView.bounds;
    maskLayer.path = maskPath.CGPath;
    _thumbView.layer.mask = maskLayer;

图片直接就不显示了, 打个断点在maskLayer.frame = _thumbView.bounds;的前面, 会发现_thumbView.bounds全部为0.于是搜寻各种方法, 了解到了下面这些方法:

setNeedsLayout:告知页面需要更新,但是不会立刻开始更新。执行后会立刻调用layoutSubviews。
layoutIfNeeded:告知页面布局立刻更新。所以一般都会和setNeedsLayout一起使用。如果希望立刻生成新的frame需要调用此方法,利用这点一般布局动画可以在更新布局后直接使用这个方法让动画生效。
layoutSubviews:系统重写布局
setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始
updateConstraintsIfNeeded:告知立刻更新约束
updateConstraints:系统更新约束

而我们就可以在layoutIfNeeded里面获取到空间的frame, 直接贴代码:

- (void)layoutIfNeeded{

    [super layoutIfNeeded];
    
     UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_thumbView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake(6, 6)];
     
     CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
     maskLayer.frame = _thumbView.bounds;//这里就可以获取到我们想要的frame啦
     maskLayer.path = maskPath.CGPath;
     _thumbView.layer.mask = maskLayer;
}

效果如图:


END

3.实现UITableView头部弹弹的动画效果,

先上效果图

弹弹的效果.gif

其实就是检测UIScrollView(当然了,UITableView也是UIScrollView)滚动到某个位置, 如果小于某个位置回弹, 大于某个位置展开, 当然也可以换作自己的动画逻辑, 然后让UIScrollView继续平滑滚动, 滚动到固定的位置, 使其定住. 注意这个平滑的要求, 有种方案就是设置UIScrollView的contentoff, 但这种方案是一下子滚动到指定位置, 而不是平滑. 于是我们搜寻一下UIScrollView的代理方法:

@protocol UIScrollViewDelegate<NSObject>

@optional

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;                                               // any offset changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2); // any zoom scale changes

// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// called on finger up if the user dragged. velocity is in points/millisecond. targetContentOffset may be changed to adjust where the scroll view comes to rest
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0);
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;   // called on finger up as we are moving
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;      // called when scroll view grinds to a halt

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView; // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating

- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;     // return a view that will be scaled. if delegate returns nil, nothing happens
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view NS_AVAILABLE_IOS(3_2); // called before the scroll view begins zooming its content
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale; // scale between minimum and maximum. called after any 'bounce' animations

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;   // return a yes if you want to scroll to the top. if not defined, assumes YES
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;      // called when scrolling animation finished. may be called immediately if already at top

@end

里面有个方法我们比较感兴趣, 但平日里比较少用, 就是这个:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset;
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards

注释里告诉我们, 滚动完之后, 可以继续移动. 而targetContentOffset就是我们想要的目标偏移量, 里面的(inout CGPoint *)回调也比较奇怪, 字面意思大概就是可以当作输入输出, 应该是当作一个指针当作回传, 告诉UIScrollView将要移动到哪, 我们可以在targetContentOffset设置输入量, 如下:

targetContentOffset->x = 0;
targetContentOffset->y = -104;

当然这种设置并不完美, 在一些奇葩的拖动会有鬼畜的效果, 于是我们对速度加入了约束:

//也就是速度为0 之后再做滚动
 if (velocity.y == 0) {
        
        if ((-newY) > 100 && (-(newY) + 64) < self.headerView.sectionHeaderViewOrinY) {
            
            targetContentOffset->x = 0;
            targetContentOffset->y = -104;
            
        }
     
    }

于是就可以作出开头显示的动画了.END

2.实现UITextField回删按钮的回调检测

UITextField的代理事件只有下面几种:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; 
- (void)textFieldDidBeginEditing:(UITextField *)textField;   
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField; 
- (void)textFieldDidEndEditing:(UITextField *)textField;  
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;   
- (BOOL)textFieldShouldClear:(UITextField *)textField;  
- (BOOL)textFieldShouldReturn:(UITextField *)textField;  

想要检测回删按钮的事件时, 发现没有回调事件,看来需要我们自己来实现UITextField回删按钮的回调.
首先点进UITextField的实现

NS_CLASS_AVAILABLE_IOS(2_0) @interface UITextField : UIControl <UITextInput, NSCoding, UIContentSizeCategoryAdjusting>

实现了UITextInput的协议, 再点进UITextInput的协议看看

protocol UITextInput <UIKeyInput>
@required

/* Methods for manipulating text. */
- (nullable NSString *)textInRange:(UITextRange *)range;
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text;

里面的几个方法没有我们感兴趣的, 继续点进UIKeyInput,可以看到

@protocol UIKeyInput <UITextInputTraits>

#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly) BOOL hasText;
#else
- (BOOL)hasText;
#endif
- (void)insertText:(NSString *)text;
- (void)deleteBackward;
@end

好了, 我们找到了- (void)deleteBackward;就是隐藏的删除回调方法, 只是没写在UITextField的回调方法里面而已. 因此我们可以写一个继承UITextField的自定义类, 如下:

#import <UIKit/UIKit.h>

@protocol KeyboardInputDelegate <NSObject>

@optional
//我们自己定义的一个回删按钮的回调方法, 顺便传回UITextField
- (void)deleteBackword:(UITextField *)field;

@end

@interface DeleteDetectionTextField : UITextField

@property (nonatomic, weak) id<KeyboardInputDelegate> KeyboardInputDelegate;

@end

然后重写一下- (void)deleteBackward;方法

//这个就是被隐藏的回删方法, 咱们覆写一下
- (void)deleteBackward{

    [super deleteBackward];
    
    if (self.KeyboardInputDelegate && [self.KeyboardInputDelegate respondsToSelector:@selector(deleteBackword:)]) {
//这句话会不会引发循环引用?
        [self.KeyboardInputDelegate deleteBackword:self];
    }
}

然后我们调用自定义的DeleteDetectionTextField使用时, 记得设置一下代理:

 inputField.delegate = self;
 inputField.KeyboardInputDelegate = self;

实现回调:

#pragma mark - 回删按钮的回调
- (void)deleteBackword:(UITextField *)field{
    //这里就可以干羞羞的事情
}

完成

1.xib拖的控件不能用代码作动画,用代码作动画会无端出现很多坑. 因此xib比较适合静态视图的搭建,一些动画视图还是使用纯代码比较合适些

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 一觉醒来,我竟然变成了一只小绵羊 我叫高阳,我很早就发育了合适的身高,也长了合适的脸,所以,初中时候我就找了同班最...
    编剧王安鹏阅读 714评论 0 1
  • 稻田里的人踩着失望入冬 黄昏把西河的云彩染红 大雁带走南方的热情 十月 缅怀的人今已故去疆土 落霞里挣扎着归家的...
    宁谷阅读 1,093评论 3 4
  • 你要对得起自己&陌仔 如果有一天,你闭着眼睛都睡不着,和睡神大战了三百回合后,依旧睁着眼睛望向天花板,你会想些什么...
    陌籽阅读 216评论 0 1