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

前情提要: 年前公司比较忙,抽间隙时间,搞搞轮子.但是也是由于自己的懒惰,一下班就来个葛优躺,机不离手的刷着头条新闻,微博什么的,一看就是一两个小时,也就懒得再开电脑码字了,本打算节前完成此文章,再看一下上次更新文章的时间,已经一个多月啊,懒惰真是可怕啊.现在已经是二月了,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];

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值