美文网首页
OC(十八):自定义组件,人造轮子

OC(十八):自定义组件,人造轮子

作者: IMSong | 来源:发表于2017-02-10 12:49 被阅读20次

    前情提要: 年前公司比较忙,抽间隙时间,搞搞轮子.但是也是由于自己的懒惰,一下班就来个葛优躺,机不离手的刷着头条新闻,微博什么的,一看就是一两个小时,也就懒得再开电脑码字了,本打算节前完成此文章,再看一下上次更新文章的时间,已经一个多月啊,懒惰真是可怕啊.现在已经是二月了,2017的年终终结还只是在计划中,想想自己都笑了,哈哈😁.年后这段时间有点清闲,趁春困还没来,赶紧填上这个坑.不说了,继续码些有用的, 皮皮虾,我们走!!!

    先预览一哈效果图

    效果图

    ①AlertView(delegate 方式)

    虽然苹果公司将 Alertview 和 actionsheet 整合到了一起alertViewController, 但是还是钟情之前的定义方式,现在重新定义样式,使之更有个性.
    关键代码

    @class SAlertView;
    /**
     *  代理方法
     */
    @protocol SAlertViewDelegate <NSObject>
    
    @required
    
    /**
     *  代理方法
     *
     *  @param sAlert            alertView
     *  @param buttonIndex       点击按钮的 index
     */
    
    -(void)sAlert:(SAlertView *)sAlert clickedButtonAtIndex:(NSInteger)buttonIndex;
    
    @end
    
    @interface SAlertView : UIView
    
    @property (nonatomic , weak) id<SAlertViewDelegate> delegate;
    
    /**
     *  初始化方法
     *
     *  @param title             标题
     *  @param message           正文
     *  @param cancelButtonTitle 取消
     *  @param otherButtonTitles 确定
     *  @param view              添加alertView的 View
     *  @param delegate          id
     *
     *  @return self
     */
    -(instancetype)initWithTitle:( NSString *)title message:( NSString *)message cancelButtonTitle:( NSString *)cancelButtonTitle otherButtonTitles:( NSString *)otherButtonTitles withView:(UIView *) view delegate:(id)delegate;
    
    
    -(void)show;
    
    
    -(void)showAnimation{
        
        self.alpha = 0;
        self.transform = CGAffineTransformMakeScale(1.5, 1.5);
        
        [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:0
                         animations:^{
                             self.alpha = 1.f;
                             self.transform = CGAffineTransformMakeScale(1, 1);
                         } completion:^(BOOL finished) {
                             
                         }];
    }
    
    -(void)hideAnimation{
        
        [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:0
                         animations:^{
                             self.alpha = 0;
                             self.transform = CGAffineTransformMakeScale(.5, .5);
                         } completion:^(BOOL finished){
                             
                             [self.backView removeFromSuperview];
                             [self removeFromSuperview];
                             
                         }];
    }
    
    

    ②button(点赞效果)

    通过对 layer 层的操作,添加 帧动画和粒子动画,使得效果更加的炫酷.

    - (void)animation {
        
        //关键帧动画
        CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
        if (self.selected) {
            
            keyAnimation.values = @[@1.4 ,@0.9, @1.0,@1.3,@1.0];
            keyAnimation.duration = 0.4;
            
            if (self.isShowAnimation) {
                
                [self startShoot];
            }
        }else
        {
            keyAnimation.values = @[@0.7, @1.0];
            keyAnimation.duration = 0.3;
        }
        // 动画模式
        keyAnimation.calculationMode = kCAAnimationCubic;
        [self.imageView.layer addAnimation:keyAnimation forKey:@"transform.scale"];
    }
    
    
    - (void)startShoot{
        
        // 每秒喷射的300个
        [self.caEmitterLayer setValue:@300 forKeyPath:@"emitterCells.emitterCell.birthRate"];
        // 开始时间 : 现在立即开始
        self.caEmitterLayer.beginTime = CACurrentMediaTime();
        // 0.1秒后停止,相当于立即停止
        [self performSelector:@selector(stopShoot) withObject:nil afterDelay:0.1];
        
    }
    
    
    - (void)stopShoot {
        
        [self.caEmitterLayer setValue:@0 forKeyPath:@"emitterCells.emitterCell.birthRate"];
    }
    
    

    ③actionSheet(Block 方式)

    类似微信的样式,参数已经设定好了,可以直接修改值进行调整样式.使用不定长度的参数,进行设置按钮的个数 -- otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION,通过va_arg(btnTitle, NSString *)取出各个参数,直到遇到 nil,所以在传入参数时候,最后一定要加上 nil 标志.

    -(instancetype)initWithFrame:(CGRect)frame cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION{
        
        NSMutableArray * arrayTitle = [NSMutableArray array];
    
        //指向参数的指针变量
        va_list btnTitle;
        //初始化上面的变量 otherButtonTitles 是可选参数的第一个参数
        va_start(btnTitle, otherButtonTitles);
        
        if(otherButtonTitles){
        
            //第一个直接放进数组
            [arrayTitle addObject:otherButtonTitles];
            //循环遍历放入数组
                //返回下一个参数,nsstring 为类型, 并指向下一个参数
            while ((otherButtonTitles = va_arg(btnTitle, NSString *))) {
               
                [arrayTitle addObject:otherButtonTitles];
            }
    
        }
        
        //释放指针变量
        va_end(btnTitle);
        
        
        
        if (self = [super initWithFrame:frame]) {
            
            _arrayCount = arrayTitle.count;
            
            [self addSubview:self.bgView];
            
            //按钮的背景
            _btnBGView = [[UIView alloc]initWithFrame:(CGRect){0,HEIGHTOFSCREEN ,WIDTHOFSCREEN,(arrayTitle.count + 1 ) * 50 + 5 }];
            
            _btnBGView.backgroundColor = setRGBColor(233, 233, 233, 1.0);
            [self addSubview:_btnBGView];
            
            //创建按钮组
            for (int i = 0 ;i <= arrayTitle.count ; i++) {
                
                UIButton * btn = [[UIButton alloc]initWithFrame:(CGRect){0, 50.5 * i,WIDTHOFSCREEN,50}];
                
                
                btn.backgroundColor = [UIColor whiteColor];
                btn.tag = i ;
                [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
                [btn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
                
                if (i != arrayTitle.count) {
                    
                    [btn setTitle:arrayTitle[i] forState:UIControlStateNormal];
                    
                }else{
                    
                    
                    btn.frame = (CGRect){0, 50.5 * i + 5,WIDTHOFSCREEN,50};
                    [btn setTitle:cancelButtonTitle forState:UIControlStateNormal];
                    
                }
                
                [_btnBGView addSubview:btn];
            }
            
            
        }
    
        return self;
    }
    
    

    ④label

    类似QQ 空间的会员的炫酷名称,有一个炫光从左至右的扫过,颜色可以自己设置,使用的渐变色进行渲染.

    -(void)setFlushStyle:(BOOL) isFlush{
        
        self.gradientLayer.frame = CGRectMake( 0,0,self.frame.size.width,self.frame.size.height);
        
        
        NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
        style.alignment = NSTextAlignmentLeft;
        
        //开始
        UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 0);
        
        [self.text drawInRect:self.bounds withAttributes:@{NSParagraphStyleAttributeName:style , NSFontAttributeName: self.font}];
        
        //获取当前
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        //结束
        UIGraphicsEndImageContext();
        
        CALayer * maskLayer = [CALayer layer];
        maskLayer.backgroundColor = [UIColor clearColor].CGColor;
        
        maskLayer.frame = CGRectOffset((CGRect){0,0,self.frame.size}, 0, 0);
        maskLayer.contents = (id)image.CGImage;
        
        self.gradientLayer.mask = maskLayer;
        
        if (isFlush)
            
            [self.layer addSublayer: self.gradientLayer];
        else
            [self.layer addSublayer:maskLayer];
        
        CABasicAnimation * basicAnim = [CABasicAnimation animationWithKeyPath:@"locations"];
        basicAnim.fromValue = @[@0.0, @0.0, @0.25];
        basicAnim.toValue = @[@0.75, @1.0, @1.0];
        basicAnim.duration = 2.8;
        basicAnim.repeatCount = CGFLOAT_MAX;
        basicAnim.removedOnCompletion = NO;
        [self.gradientLayer addAnimation:basicAnim forKey:nil];
        
    }
    
    

    ⑤button(消息数显示和清除)

    类似QQ 的消息清除,直接拖拽,可以消除消息提示.主要使用贝塞尔曲线的绘制粘性体

    /** 绘制贝赛尔曲线方法
     */
    - (void)drawBezierLine {
        
        //定义一个角度 Θ 正余弦: sinΘ = (x2 - x1)/distance ,cosΘ = (y2 - y1)/distance
        CGFloat sinΘ = (self.x2 - self.x1)/ self.remoteDistance;
        CGFloat cosΘ = (self.y2 - self.y1)/ self.remoteDistance;
        
        CGPoint pointA = (CGPoint){ self.x1 - r* cosΘ* self.scale, self.y1 + r* sinΘ* self.scale };
        CGPoint pointB = (CGPoint){ self.x1 + r* cosΘ* self.scale, self.y1 - r* sinΘ* self.scale };
        CGPoint pointC = (CGPoint){ self.x2 + R* cosΘ, self.y2 - R* sinΘ };
        CGPoint pointD = (CGPoint){ self.x2 - R* cosΘ, self.y2 + R* sinΘ };
        
        
        CGPoint pointE = (CGPoint){ pointA.x + self.remoteDistance *.5 * sinΘ , pointA.y + self.remoteDistance* .5* cosΘ};   //控制点1,与不动的 view 的半径垂直
        CGPoint pointF = (CGPoint){ pointB.x + self.remoteDistance *.5 * sinΘ , pointB.y + self.remoteDistance* .5* cosΘ };  //控制点2,与不动的 view 的半径垂直
        //    设 pointG (x, y),
        //    已知(x1,y1),(x2,y2)
        /*  ①
         
         x1 - x2       x - x2
         ---------  =  --------
         y1 - y2       y - y2
         
         ②
         R² = (x - x2)² + (y - y2)² 可以得出(x , y)
         
         */
        
        CGPoint pointG = CGPointZero;
        
        CGFloat pointGY = sqrtf( R*R*4/(((self.x1 - self.x2 ) / (self.y1 - self.y2))*((self.x1 - self.x2 ) / (self.y1 - self.y2)) + 1)) + self.y2;
        CGFloat pointGX = (pointGY - self.y2) * (self.x1 - self.x2 ) / (self.y1 - self.y2) + self.x2;
        
        
        CGFloat distance = sqrtf((self.x1 - pointGX)*(self.x1 - pointGX) + (self.y1 - pointGY)*(self.y1 - pointGY));
        
        if (distance < self.remoteDistance) {
            
            pointG = (CGPoint){ pointGX, pointGY };
        }else{
            
            pointG = (CGPoint){ 2* self.x2 - pointGX, 2*self.y2 - pointGY };
        }
        
        
        
        UIBezierPath * bezierPath = [UIBezierPath bezierPath];
        //起点
        [bezierPath moveToPoint:pointA];
        //直线
        [bezierPath addLineToPoint:pointB];
        //曲线
        [bezierPath addQuadCurveToPoint:pointC controlPoint:pointF];
        //直线
        //[bezierPath addLineToPoint:pointD];
        [bezierPath addQuadCurveToPoint:pointD controlPoint:pointG];
        //曲线
        [bezierPath addQuadCurveToPoint:pointA controlPoint:pointE];
        
        self.shapelayer.path = [bezierPath CGPath];
        [self.layer addSublayer:self.shapelayer];
    
    }
    
    

    结尾的结尾: 年关已过,又是一个春天,何不趁着春风,来一次旅行呢?我在北京,欢迎你~🍻

    相关文章

      网友评论

          本文标题:OC(十八):自定义组件,人造轮子

          本文链接:https://www.haomeiwen.com/subject/redgittx.html