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

先预览一哈效果图

OC(十八)-自定义组件,人造轮子 - 图1

①AlertView(delegate 方式)

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

  1. @class SAlertView;
  2. /**
  3. * 代理方法
  4. */
  5. @protocol SAlertViewDelegate <NSObject>
  6. @required
  7. /**
  8. * 代理方法
  9. *
  10. * @param sAlert alertView
  11. * @param buttonIndex 点击按钮的 index
  12. */
  13. -(void)sAlert:(SAlertView *)sAlert clickedButtonAtIndex:(NSInteger)buttonIndex;
  14. @end
  15. @interface SAlertView : UIView
  16. @property (nonatomic , weak) id<SAlertViewDelegate> delegate;
  17. /**
  18. * 初始化方法
  19. *
  20. * @param title 标题
  21. * @param message 正文
  22. * @param cancelButtonTitle 取消
  23. * @param otherButtonTitles 确定
  24. * @param view 添加alertView的 View
  25. * @param delegate id
  26. *
  27. * @return self
  28. */
  29. -(instancetype)initWithTitle:( NSString *)title message:( NSString *)message cancelButtonTitle:( NSString *)cancelButtonTitle otherButtonTitles:( NSString *)otherButtonTitles withView:(UIView *) view delegate:(id)delegate;
  30. -(void)show;
  1. -(void)showAnimation{
  2. self.alpha = 0;
  3. self.transform = CGAffineTransformMakeScale(1.5, 1.5);
  4. [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:0
  5. animations:^{
  6. self.alpha = 1.f;
  7. self.transform = CGAffineTransformMakeScale(1, 1);
  8. } completion:^(BOOL finished) {
  9. }];
  10. }
  11. -(void)hideAnimation{
  12. [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:0
  13. animations:^{
  14. self.alpha = 0;
  15. self.transform = CGAffineTransformMakeScale(.5, .5);
  16. } completion:^(BOOL finished){
  17. [self.backView removeFromSuperview];
  18. [self removeFromSuperview];
  19. }];
  20. }

②button(点赞效果)

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

  1. - (void)animation {
  2. //关键帧动画
  3. CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
  4. if (self.selected) {
  5. keyAnimation.values = @[@1.4 ,@0.9, @1.0,@1.3,@1.0];
  6. keyAnimation.duration = 0.4;
  7. if (self.isShowAnimation) {
  8. [self startShoot];
  9. }
  10. }else
  11. {
  12. keyAnimation.values = @[@0.7, @1.0];
  13. keyAnimation.duration = 0.3;
  14. }
  15. // 动画模式
  16. keyAnimation.calculationMode = kCAAnimationCubic;
  17. [self.imageView.layer addAnimation:keyAnimation forKey:@"transform.scale"];
  18. }
  19. - (void)startShoot{
  20. // 每秒喷射的300个
  21. [self.caEmitterLayer setValue:@300 forKeyPath:@"emitterCells.emitterCell.birthRate"];
  22. // 开始时间 : 现在立即开始
  23. self.caEmitterLayer.beginTime = CACurrentMediaTime();
  24. // 0.1秒后停止,相当于立即停止
  25. [self performSelector:@selector(stopShoot) withObject:nil afterDelay:0.1];
  26. }
  27. - (void)stopShoot {
  28. [self.caEmitterLayer setValue:@0 forKeyPath:@"emitterCells.emitterCell.birthRate"];
  29. }

③actionSheet(Block 方式)

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

  1. -(instancetype)initWithFrame:(CGRect)frame cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION{
  2. NSMutableArray * arrayTitle = [NSMutableArray array];
  3. //指向参数的指针变量
  4. va_list btnTitle;
  5. //初始化上面的变量 otherButtonTitles 是可选参数的第一个参数
  6. va_start(btnTitle, otherButtonTitles);
  7. if(otherButtonTitles){
  8. //第一个直接放进数组
  9. [arrayTitle addObject:otherButtonTitles];
  10. //循环遍历放入数组
  11. //返回下一个参数,nsstring 为类型, 并指向下一个参数
  12. while ((otherButtonTitles = va_arg(btnTitle, NSString *))) {
  13. [arrayTitle addObject:otherButtonTitles];
  14. }
  15. }
  16. //释放指针变量
  17. va_end(btnTitle);
  18. if (self = [super initWithFrame:frame]) {
  19. _arrayCount = arrayTitle.count;
  20. [self addSubview:self.bgView];
  21. //按钮的背景
  22. _btnBGView = [[UIView alloc]initWithFrame:(CGRect){0,HEIGHTOFSCREEN ,WIDTHOFSCREEN,(arrayTitle.count + 1 ) * 50 + 5 }];
  23. _btnBGView.backgroundColor = setRGBColor(233, 233, 233, 1.0);
  24. [self addSubview:_btnBGView];
  25. //创建按钮组
  26. for (int i = 0 ;i <= arrayTitle.count ; i++) {
  27. UIButton * btn = [[UIButton alloc]initWithFrame:(CGRect){0, 50.5 * i,WIDTHOFSCREEN,50}];
  28. btn.backgroundColor = [UIColor whiteColor];
  29. btn.tag = i ;
  30. [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  31. [btn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
  32. if (i != arrayTitle.count) {
  33. [btn setTitle:arrayTitle[i] forState:UIControlStateNormal];
  34. }else{
  35. btn.frame = (CGRect){0, 50.5 * i + 5,WIDTHOFSCREEN,50};
  36. [btn setTitle:cancelButtonTitle forState:UIControlStateNormal];
  37. }
  38. [_btnBGView addSubview:btn];
  39. }
  40. }
  41. return self;
  42. }

④label

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

  1. -(void)setFlushStyle:(BOOL) isFlush{
  2. self.gradientLayer.frame = CGRectMake( 0,0,self.frame.size.width,self.frame.size.height);
  3. NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
  4. style.alignment = NSTextAlignmentLeft;
  5. //开始
  6. UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 0);
  7. [self.text drawInRect:self.bounds withAttributes:@{NSParagraphStyleAttributeName:style , NSFontAttributeName: self.font}];
  8. //获取当前
  9. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  10. //结束
  11. UIGraphicsEndImageContext();
  12. CALayer * maskLayer = [CALayer layer];
  13. maskLayer.backgroundColor = [UIColor clearColor].CGColor;
  14. maskLayer.frame = CGRectOffset((CGRect){0,0,self.frame.size}, 0, 0);
  15. maskLayer.contents = (id)image.CGImage;
  16. self.gradientLayer.mask = maskLayer;
  17. if (isFlush)
  18. [self.layer addSublayer: self.gradientLayer];
  19. else
  20. [self.layer addSublayer:maskLayer];
  21. CABasicAnimation * basicAnim = [CABasicAnimation animationWithKeyPath:@"locations"];
  22. basicAnim.fromValue = @[@0.0, @0.0, @0.25];
  23. basicAnim.toValue = @[@0.75, @1.0, @1.0];
  24. basicAnim.duration = 2.8;
  25. basicAnim.repeatCount = CGFLOAT_MAX;
  26. basicAnim.removedOnCompletion = NO;
  27. [self.gradientLayer addAnimation:basicAnim forKey:nil];
  28. }

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

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

  1. /** 绘制贝赛尔曲线方法
  2. */
  3. - (void)drawBezierLine {
  4. //定义一个角度 Θ 正余弦: sinΘ = (x2 - x1)/distance ,cosΘ = (y2 - y1)/distance
  5. CGFloat sinΘ = (self.x2 - self.x1)/ self.remoteDistance;
  6. CGFloat cosΘ = (self.y2 - self.y1)/ self.remoteDistance;
  7. CGPoint pointA = (CGPoint){ self.x1 - r* cosΘ* self.scale, self.y1 + r* sinΘ* self.scale };
  8. CGPoint pointB = (CGPoint){ self.x1 + r* cosΘ* self.scale, self.y1 - r* sinΘ* self.scale };
  9. CGPoint pointC = (CGPoint){ self.x2 + R* cosΘ, self.y2 - R* sinΘ };
  10. CGPoint pointD = (CGPoint){ self.x2 - R* cosΘ, self.y2 + R* sinΘ };
  11. CGPoint pointE = (CGPoint){ pointA.x + self.remoteDistance *.5 * sinΘ , pointA.y + self.remoteDistance* .5* cosΘ}; //控制点1,与不动的 view 的半径垂直
  12. CGPoint pointF = (CGPoint){ pointB.x + self.remoteDistance *.5 * sinΘ , pointB.y + self.remoteDistance* .5* cosΘ }; //控制点2,与不动的 view 的半径垂直
  13. // 设 pointG (x, y),
  14. // 已知(x1,y1),(x2,y2)
  15. /* ①
  16. x1 - x2 x - x2
  17. --------- = --------
  18. y1 - y2 y - y2
  19. R² = (x - x2)² + (y - y2)² 可以得出(x , y)
  20. */
  21. CGPoint pointG = CGPointZero;
  22. 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;
  23. CGFloat pointGX = (pointGY - self.y2) * (self.x1 - self.x2 ) / (self.y1 - self.y2) + self.x2;
  24. CGFloat distance = sqrtf((self.x1 - pointGX)*(self.x1 - pointGX) + (self.y1 - pointGY)*(self.y1 - pointGY));
  25. if (distance < self.remoteDistance) {
  26. pointG = (CGPoint){ pointGX, pointGY };
  27. }else{
  28. pointG = (CGPoint){ 2* self.x2 - pointGX, 2*self.y2 - pointGY };
  29. }
  30. UIBezierPath * bezierPath = [UIBezierPath bezierPath];
  31. //起点
  32. [bezierPath moveToPoint:pointA];
  33. //直线
  34. [bezierPath addLineToPoint:pointB];
  35. //曲线
  36. [bezierPath addQuadCurveToPoint:pointC controlPoint:pointF];
  37. //直线
  38. //[bezierPath addLineToPoint:pointD];
  39. [bezierPath addQuadCurveToPoint:pointD controlPoint:pointG];
  40. //曲线
  41. [bezierPath addQuadCurveToPoint:pointA controlPoint:pointE];
  42. self.shapelayer.path = [bezierPath CGPath];
  43. [self.layer addSublayer:self.shapelayer];
  44. }

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