加号界面(发布模块)
一、点击加号modal出发布模块,创建控件,布局控件
1)使用xib加载view,如果在viewDidLoad创建控件并设置frame 那么self.view 的宽高 拿到的是xib的大小
2)如果在viewDidLayouSubviews布局子控件 那么self.view 的宽高 拿到的是屏幕的宽高(这里不推荐 最好在设置frame时 直接用屏幕宽高设置frame)
3)创建按钮,自定义按钮,布局按钮
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.font = [UIFont systemFontOfSize:15]; [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.imageView.y = 0; self.imageView.centerX = self.width * 0.5; self.titleLabel.width = self.width; self.titleLabel.y = CGRectGetMaxY(self.imageView.frame); self.titleLabel.x = 0; self.titleLabel.height = self.height - self.titleLabel.y; }
二、添加动画
1)Core Animation
利用苹果自带的动画方法
动画只能作用在CALayer
无法监听到动画的中间值(frame值并不能改变 只是个假象)
2)pop
facebook出品的动画框架
动画能作用在任何对象
能监听到动画的中间值(真正的修改frame值)
// 动画 POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame]; anim.fromValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonY - CHGScreenH, buttonW, buttonH)]; anim.toValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonY, buttonW, buttonH)]; anim.springSpeed = 10; anim.springBounciness = 10; // CACurrentMediaTime()获得的是当前时间 anim.beginTime = CACurrentMediaTime() + [self.times[i] doubleValue]; [button pop_addAnimation:anim forKey:nil];
3)示例程序
poping
LeamCube
github中搜索Animation
三、动画细节
1、 弹出动画(使用pop)
代码优化
2、退出动画
禁止用户的交互等小细节
// 禁止交互 self.view.userInteractionEnabled = NO;
点击按钮、取消按钮、屏幕三种不同情况
四、modal发段子等子控制器
1)选择正确的控制器去modal 选择的控制器不能是已经消亡的,一般用窗口的根控制器(此处根控制器为tabbarVC)
2)将跳转(发段子等功能)封装到一个block内,区分点击按钮、取消按钮、屏幕三种不同情况下有不同功能,也就是说点击按钮(发段子、发视频等)才需要有跳转的功能,其他两个不需要
#pragma mark - 退出动画 - (void)exit:(void (^)())task { // 禁止交互 self.view.userInteractionEnabled = NO; // 让按钮执行动画 for (int i = 0; i < self.buttons.count; i++) { CHGPublishButton *button = self.buttons[i]; POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionY]; anim.toValue = @(button.layer.position.y + CHGScreenH); // CACurrentMediaTime()获得的是当前时间 anim.beginTime = CACurrentMediaTime() + [self.times[i] doubleValue]; [button.layer pop_addAnimation:anim forKey:nil]; } // 让标题执行动画 POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionY]; anim.toValue = @(self.sloganView.layer.position.y + CHGScreenH); // CACurrentMediaTime()获得的是当前时间 anim.beginTime = CACurrentMediaTime() + [self.times.lastObject doubleValue]; CHGWeakSelf; [anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) { [weakSelf dismissViewControllerAnimated:NO completion:nil]; // 可能会做其他事情 // if (task) task(); !task ? : task(); }]; [self.sloganView.layer pop_addAnimation:anim forKey:nil]; }
三种不同情况
#pragma mark - 点击 - (void)buttonClick:(XMGPublishButton *)button { [self exit:^{ // 按钮索引 NSUInteger index = [self.buttons indexOfObject:button]; switch (index) { case 2: { // 发段子 // 弹出发段子控制器 CHGPostWordViewController *postWord = [[CHGPostWordViewController alloc] init]; [self.view.window.rootViewController presentViewController:[[CHGNavigationController alloc] initWithRootViewController:postWord] animated:YES completion:nil]; break; } case 0: XMGLog(@"发视屏"); break; case 1: XMGLog(@"发图片"); break; default: XMGLog(@"其它"); break; } }]; } - (IBAction)cancel { [self exit:nil]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self exit:nil]; }
五、发段子界面
1)textView 默认会换行,但是没有占位文字,需自定义,封装成工具类、小框架
2)自定义带占位文字的textView
方法一 drawRect 画在一个矩形框内
.h
#import <UIKit/UIKit.h> @interface CHGPlaceholderTextView : UITextView /** 占位文字 */ @property (nonatomic, copy) NSString *placeholder; /** 占位文字颜色 */ @property (nonatomic, strong) UIColor *placeholderColor; @end
.m
#import "CHGPlaceholderTextView.h" @implementation CHGPlaceholderTextView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.font = [UIFont systemFontOfSize:17]; self.textColor = [UIColor blackColor]; self.placeholderColor = [UIColor grayColor]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self]; } return self; } - (void)textDidChange:(NSNotification *)note { // 会重新调用drawRect:方法 [self setNeedsDisplay]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)drawRect:(CGRect)rect { // 如果有文字,就直接返回,不需要画占位文字 // if (self.text.length || self.attributedText.length) return; if (self.hasText) return; // 属性 NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; attrs[NSFontAttributeName] = self.font; attrs[NSForegroundColorAttributeName] = self.placeholderColor; rect.origin.x = 5; rect.origin.y = 8; rect.size.width -= 2 * rect.origin.x; [self.placeholder drawInRect:rect withAttributes:attrs]; } // 若是不写 进入发表界面 占位文字不能随textView上下滚动 - (void)layoutSubviews { [super layoutSubviews]; [self setNeedsDisplay]; } #pragma mark - setter - (void)setPlaceholderColor:(UIColor *)placeholderColor { _placeholderColor = placeholderColor; [self setNeedsDisplay]; } - (void)setPlaceholder:(NSString *)placeholder { _placeholder = placeholder; [self setNeedsDisplay]; } - (void)setFont:(UIFont *)font { [super setFont:font]; [self setNeedsDisplay]; } - (void)setText:(NSString *)text { [super setText:text]; [self setNeedsDisplay]; } - (void)setAttributedText:(NSAttributedString *)attributedText { [super setAttributedText:attributedText]; [self setNeedsDisplay]; } @end
方法二 添加label
.h
#import <UIKit/UIKit.h> @interface CHGPlaceholderTextView2 : UITextView /** 占位文字 */ @property (nonatomic, copy) NSString *placeholder; /** 占位文字颜色 */ @property (nonatomic, strong) UIColor *placeholderColor; @end
.m
#import "CHGPlaceholderTextView2.h" @interface CHGPlaceholderTextView2 () /** 占位文字label */ @property (nonatomic, weak) UILabel *placeholderLabel; @end @implementation CHGPlaceholderTextView2 - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { // 创建label UILabel *placeholderLabel = [[UILabel alloc] init]; placeholderLabel.numberOfLines = 0; [self addSubview:placeholderLabel]; self.placeholderLabel = placeholderLabel; // 设置默认字体 self.font = [UIFont systemFontOfSize:15]; // 设置默认颜色 self.placeholderColor = [UIColor grayColor]; // 使用通知监听文字改变 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self]; } return self; } - (void)textDidChange:(NSNotification *)note { self.placeholderLabel.hidden = self.hasText; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)layoutSubviews { [super layoutSubviews]; self.placeholderLabel.x = 5; self.placeholderLabel.y = 8; self.placeholderLabel.width = self.width - 2 * self.placeholderLabel.x; [self.placeholderLabel sizeToFit]; } #pragma mark - setter - (void)setPlaceholder:(NSString *)placeholder { _placeholder = [placeholder copy]; self.placeholderLabel.text = placeholder; [self.placeholderLabel sizeToFit]; // [self setNeedsLayout]; } - (void)setPlaceholderColor:(UIColor *)placeholderColor { _placeholderColor = placeholderColor; self.placeholderLabel.textColor = placeholderColor; } - (void)setFont:(UIFont *)font { [super setFont:font]; self.placeholderLabel.font = font; [self.placeholderLabel sizeToFit]; // [self setNeedsLayout]; } - (void)setText:(NSString *)text { [super setText:text]; self.placeholderLabel.hidden = self.hasText; } - (void)setAttributedText:(NSAttributedString *)attributedText { [super setAttributedText:attributedText]; self.placeholderLabel.hidden = self.hasText; } @end
3)如何去除占位文字
代理(不推荐)
通知 (参考上面代码)
4)设置占位文字颜色、字体、大小、普通内容、富文本内容、frame等属性
默认的情况下
重新设置的情况下(重写这五个属性的set方法,再重绘或者重新计算,frame重写layoutsubviews)
5)拖拽时取消编辑,退出键盘
设置竖直方向允许拖动,实现拖拽的代理方法控制退出键盘
6)设置导航栏的属性 字体颜色等(layouIfNeeded强制刷新,可解决因为设置属性而影响到状态)
六、三种刷新控件的方法
// 重新刷新自己和子控件的所有内容(状态、尺寸) [tempView layoutIfNeeded]; // 重新调用tempView的layoutSubviews(重新排布子控件的frame) [tempView setNeedsLayout]; // 重新调用tempView的drawRect:方法(重新绘制tempView里面的内容,一般不包括子控件) [tempView setNeedsDisplay];
七、重识bounds、scrollView
1)bounds
bounds 指的是控件矩形框的位置和尺寸
bounds 是以自己内容(内部的子控件)的左上角为坐标原点
y = 正数 子控件会往上
y = 负数 子控件会往下
2)frame
frame 指的是控件矩形框的位置和尺寸
frame 是以自己父控件的左上角为坐标原点
3)bounds和frame的对比
以下图为例子
用绿色表示矩形框bounds(圈圈为坐标原点)
用红色表示矩形框frame
4)scrollView textView
当控制器中有超过两个scrollView(或textView)时,那么系统会在第一个添加的scrollView(或textView)顶部添加一定的偏移量,若有导航控制器,偏移64,若没有,偏移20
self.automaticallyAdjustsScrollViewInsets = NO; // 当你有超过1个scrollView的时候,建议你设置self.automaticallyAdjustsScrollViewInsets = NO;,然后自己根据需要去调整scrollView的inset
5)scrollView常用的属性
scrollView.contentSize; // 滚动范围(内容的尺寸)
scrollView.contentInset; // 内边距
scrollView.frame; // 以父控件内容的左上角为坐标原点,scrollView矩形框的位置和尺寸
scrollView.bounds; // 以自己内容的左上角为坐标原点,scrollView矩形框的位置和尺寸
scrollView.contentOffset; // 偏移量(scrollView.bounds.origin)