zoukankan      html  css  js  c++  java
  • iOS开发——项目篇—高仿百思不得姐 05——发布界面、发表文字界面、重识 bounds、frame、scrollView

    加号界面(发布模块)

    一、点击加号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)

    将来的你会感谢今天如此努力的你! 版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    TinyMail研究—Camellite的插件系统
    Dual Tone Multifrequency
    Linux PPP 数据收发流程
    这个五一怎么过?
    Linux下的磁盘加密方法
    udev的实现原理
    c语言中程序的循环控制,for语句。
    创建一个函数,将和有n个元素的数组中的key相等的所有元素的下标存储在另一数组中,并返回和key元素相同的元素的个数。
    c语言中数组元素的哨兵查找法
    c语言中数组,一般数组
  • 原文地址:https://www.cnblogs.com/chglog/p/4798180.html
Copyright © 2011-2022 走看看