iOS 가이드 라인 이 있 는 떡 모양 그림 효과 구현(겹 치지 않 음)

효과 도
먼저 위의 그림 을 그리다.

1.효과 도-w220
그림 에서 모든 부채 형 이 아무리 작 아 도 안내 선 에서 안내 하 는 데 이 터 를 분리 하여 겹 치지 않 습 니 다.
첫걸음
그림 의 데이터 에 모델 을 만들어 야 합 니 다.

@interface DVFoodPieModel : NSObject
/**
   
 */
@property (copy, nonatomic) NSString *name;

/**
   
 */
@property (assign, nonatomic) CGFloat value;

/**
   
 */
@property (assign, nonatomic) CGFloat rate;
@end
두 번 째 단계
지금 먼저 떡 그림 중간의 원형 을 만들어 보 세 요.이 건 어렵 지 않 아 요.코드 를 바로 붙 여요.
파일

@interface DVPieCenterView : UIView 
@property (strong, nonatomic) UILabel *nameLabel; 
@end
파일

@interface DVPieCenterView ()
@property (strong, nonatomic) UIView *centerView;
@end
@implementation DVPieCenterView
- (instancetype)initWithFrame:(CGRect)frame {
 if (self = [super initWithFrame:frame]) {
  self.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.4];
  UIView *centerView = [[UIView alloc] init];
  centerView.backgroundColor = [UIColor whiteColor];
  [self addSubview:centerView];
  self.centerView = centerView;
  UILabel *nameLabel = [[UILabel alloc] init];
  nameLabel.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1];
  nameLabel.font = [UIFont systemFontOfSize:18];
  nameLabel.textAlignment = NSTextAlignmentCenter;
  self.nameLabel = nameLabel;
  [centerView addSubview:nameLabel];
 }
 return self;
}


- (void)layoutSubviews {
 [super layoutSubviews];
 self.layer.cornerRadius = self.frame.size.width * 0.5;
 self.layer.masksToBounds = true;
 self.centerView.frame = CGRectMake(6, 6, self.frame.size.width - 6 * 2, self.frame.size.height - 6 * 2);
 self.centerView.layer.cornerRadius = self.centerView.frame.size.width * 0.5;
 self.centerView.layer.masksToBounds = true;
 self.nameLabel.frame = self.centerView.bounds;
}
노출 된 것 은.h 파일 의 namelable 뿐 입 니 다.중간 에 텍스트 를 표시 해 야 할 때 nameLabel 의 text 에 값 을 부여 하면 됩 니 다.
세 번 째 단계
이제 UIView 를 계승 하 는 보 기 를 만 들 고 떡 모양 의 그림 과 안내 선,데 이 터 를 그 릴 수 있 습 니 다.
.h 파일 에는 데이터 배열 과 중간 에 표 시 된 텍스트,그리고 draw 방법 이 필요 합 니 다.(draw 방법 은 개인 적 인 습관 입 니 다.데이터 의 모든 할당 이 완 료 된 후에 이 방법 으로 그림 을 그립 니 다)

@interface DVPieChart : UIView
/**
     
 */
@property (strong, nonatomic) NSArray *dataArray;
/**
   
 */
@property (copy, nonatomic) NSString *title;
/**
     
 */
- (void)draw;
@end
draw 방법 을 호출 하기 전에 데이터 의 모든 할당 이 완료 되 었 는 지 확인 해 야 합 니 다.그리 기 작업 은 사실- (void)drawRect:(CGRect)rect방법 에서 이 루어 졌 기 때문에 h 파일 의 draw 방법 은 시스템 방법 을 호출 하 는 것 입 니 다.
m 파일 에서 draw 방법의 실현

- (void)draw {
 [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 [self setNeedsDisplay];
}
[self setNeedsDisplay];drawRect 방법 을 호출 하 러 왔 습 니 다.[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];이 방법 은 pieChart 에 추 가 된 centerView 를 제거 하 는 것 입 니 다.그렇지 않 으 면 다시 그 릴 때마다 centerView 를 추가 합 니 다.
다음은 draw Rect 방법의 실현 입 니 다.
우선 원 의 반지름,중심 점 과 시작 점 을 확정 해 야 한다.

CGFloat min = self.bounds.size.width > self.bounds.size.height ? self.bounds.size.height : self.bounds.size.width;
CGPoint center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5);
CGFloat radius = min * 0.5 - CHART_MARGIN;
CGFloat start = 0;
CGFloat angle = 0;
CGFloat end = start;
CHART_MARGIN 은 자신 이 정의 한 매크로 입 니 다.원 은 보기 의 변 에 접선 을 할 수 없습니다.여기 서 저 는 CHARTMARGIN 을 60 으로 설정
*제품 의 수요 에 따라 요청 한 데이터 가 비어 있 을 때 순수한 색 의 원 을 표시 하고 안내 선 을 그리 지 않 기 때문에 drawRect 에서 두 가지 상황 으로 나 누 어 이 루어 집 니 다.

```objc
if (self.dataArray.count == 0) {

} else {

}
```
*  dataArray    0 

```objc
if (self.dataArray.count == 0) {
 
 end = start + M_PI * 2;
 
 UIColor *color = COLOR_ARRAY.firstObject;
 
 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:start endAngle:end clockwise:true];
 
 [color set];
 
 //        
 [path addLineToPoint:center];
 [path fill];
 
}
```
> COLOR_ARRAY           ,          6 ,      ,            (         ,       )

``` objc
#define COLOR_ARRAY @[\
[UIColor colorWithRed:251/255.0 green:166.9/255.0 blue:96.5/255.0 alpha:1],
[UIColor colorWithRed:151.9/255.0 green:188/255.0 blue:95.8/255.0 alpha:1],
[UIColor colorWithRed:245/255.0 green:94/255.0 blue:102/255.0 alpha:1],
[UIColor colorWithRed:29/255.0 green:140/255.0 blue:140/255.0 alpha:1],
[UIColor colorWithRed:121/255.0 green:113/255.0 blue:199/255.0 alpha:1],
[UIColor colorWithRed:16/255.0 green:149/255.0 blue:224/255.0 alpha:1]
]
```
*dataArray 길이 가 0 이 아 닐 때

```objc

for (int i = 0; i < self.dataArray.count; i++) {
 DVFoodPieModel *model = self.dataArray[i];
 CGFloat percent = model.rate;
 UIColor *color = COLOR_ARRAY[i % 6];
 start = end;
 angle = percent * M_PI * 2;
 end = start + angle;
 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:start endAngle:end clockwise:true];
 [color set];
 //        
 [path addLineToPoint:center];
 [path fill];
}
```
else 에서 이렇게 하면 각 부채 형 을 그 릴 수 있 습 니 다.

*         ,  centerView
```objc
//      label
DVPieCenterView *centerView = [[DVPieCenterView alloc] init];
centerView.frame = CGRectMake(0, 0, 80, 80);
CGRect frame = centerView.frame;
frame.origin = CGPointMake(self.frame.size.width * 0.5 - frame.size.width * 0.5, self.frame.size.height * 0.5 - frame.size.width * 0.5);
centerView.frame = frame;
centerView.nameLabel.text = self.title;
[self addSubview:centerView];
```
네 번 째 단계,회화 가이드 라인 과 데이터
안내 선 을 그립 니 다.부채 형 을 그 릴 때 몇 개의 데 이 터 를 확인 하고 이 몇 가지 데이터 에 따라 그립 니 다.
  • 각 부채 형 원호 의 중심 점
  • 안내 선의 중점(효과 도 에 원점 이 있 는 위치)
  • 
    //          
    CGFloat radianCenter = (start + end) * 0.5;
    //         
    CGFloat lineStartX = self.frame.size.width * 0.5 + radius * cos(radianCenter);
    CGFloat lineStartY = self.frame.size.height * 0.5 + radius * sin(radianCenter);
    CGPoint point = CGPointMake(lineStartX, lineStartY);
    이 그림 은 방금 만 들 었 을 때 겹 쳐 서 제품 의 수요 에 따라 변경 되 었 기 때문에 변수 이름 이 약간 다른 의미 가 있 을 수 있 습 니 다.바 꾸 기 가 불편 합 니 다.저 는 주석 만 잘 할 수 있 습 니 다.여러분 은 주석 을 기준 으로 합 니 다.
    순서대로 그리 면 안내 선의 위치 가 겹 치지 않 기 때문에 중간 에 있 는 데 이 터 를 먼저 그리고 중간 데이터 양쪽 의 데 이 터 를 그립 니 다.
    그러면 위 에서 확인 해 야 할 데 이 터 를 배열 에 순서대로 추가 해 야 합 니 다.
    예:원 데 이 터 는@[@1,@2,@3,@4,@5,@6]입 니 다.
    가이드 라인 을 그 릴 때 는 데이터 가 필요 합 니 다.@[@3,@2,@1,@4,@5,@6]
    그래서 for 순환 에서 이렇게 바 꿔 야 돼 요.
    데이터 가 순 서 를 변경 한 후,그 릴 때 모델 데이터 와 색상 데이터 도 순 서 를 변경 해 야 합 니 다.
    우선 두 변 수 를 설명 합 니 다.
    
    @interface DVPieChart ()
    @property (nonatomic, strong) NSMutableArray *modelArray;
    @property (nonatomic, strong) NSMutableArray *colorArray;
    @end
    else 에서 이렇게 됐어 요.
    
    NSMutableArray *pointArray = [NSMutableArray array];
    NSMutableArray *centerArray = [NSMutableArray array];
    self.modelArray = [NSMutableArray array];
    self.colorArray = [NSMutableArray array];
    for (int i = 0; i < self.dataArray.count; i++) {
     DVFoodPieModel *model = self.dataArray[i];
     CGFloat percent = model.rate;
     UIColor *color = COLOR_ARRAY[i];
     start = end;
     angle = percent * M_PI * 2;
     end = start + angle;
     UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:start endAngle:end clockwise:true]; 
     [color set];
     //        
     [path addLineToPoint:center];
     [path fill];
     //          
     CGFloat radianCenter = (start + end) * 0.5;
     //         
     CGFloat lineStartX = self.frame.size.width * 0.5 + radius * cos(radianCenter);
     CGFloat lineStartY = self.frame.size.height * 0.5 + radius * sin(radianCenter);
     CGPoint point = CGPointMake(lineStartX, lineStartY);
     if (i <= self.dataArray.count / 2 - 1) {
      [pointArray insertObject:[NSValue valueWithCGPoint:point] atIndex:0];
      [centerArray insertObject:[NSNumber numberWithFloat:radianCenter] atIndex:0];
      [self.modelArray insertObject:model atIndex:0];
      [self.colorArray insertObject:color atIndex:0];
     } else {
      [pointArray addObject:[NSValue valueWithCGPoint:point]];
      [centerArray addObject:[NSNumber numberWithFloat:radianCenter]];
      [self.modelArray addObject:model];
      [self.colorArray addObject:color];
     }
    }
    for 순환 에서 필요 한 데 이 터 를 확 정 했 습 니 다:
    pointArray、centerArray、self.modelArray、self.colorArray
    위 에서 확 정 된 데이터 에 따라 안내 선 을 그립 니 다.논리 가 복잡 합 니 다.방법 을 써 서 그립 니 다.
    
    - (void)drawLineWithPointArray:(NSArray *)pointArray centerArray:(NSArray *)centerArray
    for 순환 외 호출
    
    //   pointArray centerArray     
    [self drawLineWithPointArray:pointArray centerArray:centerArray];
    다섯 번 째 단계
    방법 내부 실현
    확인 할 데이터 가 있 습 니 다:
    1.가이드 라인 길이
    2.가이드 라인 의 출발점,종점,전환점
    3.가이드 라인 데이터 가 차지 하 는 rect 범위(다음 을 그 릴 때 겹 치 는 지 확인 하 는 데 사용)
    아래 에 직접 코드 를 붙 여 실현 합 니 다.주석 을 주의 깊 게 보 세 요.저 는 코드 밖 에 다시 쓰 지 않 겠 습 니 다.
    
    - (void)drawLineWithPointArray:(NSArray *)pointArray centerArray:(NSArray *)centerArray {
     //                    (    )
     CGRect rect = CGRectZero;
     //          
     CGFloat width = self.bounds.size.width * 0.5;
     for (int i = 0; i < pointArray.count; i++) {
      //     
      NSValue *value = pointArray[i];
      //           
      CGPoint point = value.CGPointValue;
      //           
      CGFloat radianCenter = [centerArray[i] floatValue];
      //   (       )
      UIColor *color = self.colorArray[i % 6];
      //     (       )
      DVFoodPieModel *model = self.modelArray[i];
      //      
      NSString *name = model.name;
      NSString *number = [NSString stringWithFormat:@"%.2f%%", model.rate * 100];
    
      //       x  y 
      CGFloat x = point.x;
      CGFloat y = point.y;
      
      //         (x, y)
      CGFloat startX = x + 10 * cos(radianCenter);
      CGFloat startY = y + 10 * sin(radianCenter);
      
      //          (x, y)
      CGFloat breakPointX = x + 20 * cos(radianCenter);
      CGFloat breakPointY = y + 20 * sin(radianCenter);
      
      //              (   +20,          ,       ,+20    )
      CGFloat margin = fabs(width - breakPointX) + 20;
      
      //      
      CGFloat lineWidth = width - margin;
      
      //      (x, y)
      CGFloat endX;
      CGFloat endY;
      
      //         ,   size(width height)
      // width  lineWidth  ,                
      CGFloat numberWidth = 80.f;
      CGFloat numberHeight = 15.f;
      
      CGFloat titleWidth = numberWidth;
      CGFloat titleHeight = numberHeight;
      
      //              (x, y)          frame
      CGFloat numberX;// = breakPointX;
      CGFloat numberY = breakPointY - numberHeight;
      
      CGFloat titleX = breakPointX;
      CGFloat titleY = breakPointY + 2;
      
      
      //       (          )
      NSMutableParagraphStyle * paragraph = [[NSMutableParagraphStyle alloc]init];
      //     
      paragraph.alignment = NSTextAlignmentRight;
      
      //   x  ,              
      //               
      //           
      if (x <= width) { //    
       
       endX = 10;
       endY = breakPointY;
       
       //     
       paragraph.alignment = NSTextAlignmentLeft;
       
       numberX = endX;
       titleX = endX;
       
      } else { //    
       
       endX = self.bounds.size.width - 10;
       endY = breakPointY;
       
       numberX = endX - numberWidth;
       titleX = endX - titleWidth;
      }
      
      
      if (i != 0) {
       
       //  i!=0 ,         (      rect) rect1(        )     
       CGRect rect1 = CGRectMake(numberX, numberY, numberWidth, titleY + titleHeight - numberY);
       
       CGFloat margin = 0;
       
       if (CGRectIntersectsRect(rect, rect1)) {
        //       
        //     
        // 1.    
        // 2.    
        // 3.   
        //               
        if (CGRectContainsRect(rect, rect1)) {//   
         
         if (i % self.dataArray.count <= self.dataArray.count * 0.5 - 1) {
          //              
          margin = CGRectGetMaxY(rect1) - rect.origin.y;
          endY -= margin;
         } else {
          //              
          margin = CGRectGetMaxY(rect) - rect1.origin.y;
          endY += margin;
         }
         
         
        } else { //   
         
         if (CGRectGetMaxY(rect1) > rect.origin.y && rect1.origin.y < rect.origin.y) { //        
          margin = CGRectGetMaxY(rect1) - rect.origin.y;
          endY -= margin;
          
         } else if (rect1.origin.y < CGRectGetMaxY(rect) && CGRectGetMaxY(rect1) > CGRectGetMaxY(rect)) { //       
          margin = CGRectGetMaxY(rect) - rect1.origin.y;
          endY += margin;
         }
         
        }
       }
       titleY = endY + 2;
       numberY = endY - numberHeight;
       
       
       //               
       CGRect rect2 = CGRectMake(numberX, numberY, numberWidth, titleY + titleHeight - numberY);
       
       //      rect    rect  
       if (numberX == rect.origin.x) {
        //                  
        if (rect2.origin.y < rect.origin.y) {
         rect = CGRectMake(rect.origin.x, rect2.origin.y, rect.size.width, rect.size.height + rect2.size.height);
        } else {
         rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height + rect2.size.height);
        }
       }
       
      } else {
       rect = CGRectMake(numberX, numberY, numberWidth, titleY + titleHeight - numberY);
      }
    
      //        
      if (endX == 10) {
       breakPointX = endX + lineWidth;
      } else {
       breakPointX = endX - lineWidth;
      }
      
      breakPointY = endY;
      //1.     
      CGContextRef ctx = UIGraphicsGetCurrentContext();
      //2.    
      UIBezierPath *path = [UIBezierPath bezierPath];
      [path moveToPoint:CGPointMake(endX, endY)];
      [path addLineToPoint:CGPointMake(breakPointX, breakPointY)];
      [path addLineToPoint:CGPointMake(startX, startY)];
      CGContextSetLineWidth(ctx, 0.5);
      //    
      [color set];
      //3.              
      CGContextAddPath(ctx, path.CGPath);
      //4.          View (   View layer)(stroke fill)
      CGContextStrokePath(ctx);
    
      //        (   )
      // movePoint,           
      CGFloat movePoint = -2.5;
      UIView *view = [[UIView alloc] init];
      view.backgroundColor = color;
      [self addSubview:view];
      CGRect rect = view.frame;
      rect.size = CGSizeMake(5, 5);
      rect.origin = CGPointMake(startX + movePoint, startY - 2.5);
      view.frame = rect;
      view.layer.cornerRadius = 2.5;
      view.layer.masksToBounds = true;
    
      //        
      [name drawInRect:CGRectMake(numberX, numberY, numberWidth, numberHeight) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:9.0], NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:paragraph}];
      
      //       title
      [number drawInRect:CGRectMake(titleX, titleY, titleWidth, titleHeight) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:9.0],NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:paragraph}];
     } 
    }
    github 주소 첨부:https://github.com/FireMou/DVPieChart ( 로 컬 다운로드
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기