前一陣看了墨跡天氣的24小時折線圖魁衙,感覺很有意思。尤其是里面View跟著手指的滑動一起實時運動蜈彼,效果體驗很好。 就嘗試寫了一下俺驶,先看一下最終的效果圖:
寫這個折線圖幸逆,讓曲線可滑動難點不大。直接在UIScrollView上面繪制就好了暮现,主要是這個圓角View的運動軌跡計算还绘。 計算運動軌跡,無非就是計算x和y軸的坐標栖袋。下面說下我的計算思路
1.運動坐標分為x和y坐標拍顷。我們先來計算x的運動坐標。通過比例關(guān)系塘幅,很容易得出以下公式
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGSize size = scrollView.contentSize;
CGFloat x = (_dataArray.count - 1) * self.lineSpace * scrollView.contentOffset.x / (size.width - scrollView.width) + self.leftMargin;
}
其中dataArray為數(shù)據(jù)源數(shù)組, lineSpace為每個點之間的距離,leftMargin為曲線的外邊距昔案。
2.由于曲線本身就是有無數(shù)個直線所組成。我們可以通過直線的方法來處理計算曲線上點的坐標电媳。在求出實時運動軌跡的x點坐標后踏揣,下來我們來計算y坐標:
- 計算貝塞爾曲線這個點的前后兩點的在位置數(shù)組位置的下標
- 得到兩點后,問題就變得很簡單了匾乓。直線方程求解
- 求出斜率捞稿, 通過點斜式計算得出。點斜式公式:y-y1 = k(x - x1)
-(CGFloat)getLableyAxisWithX:(CGFloat)xAxis;
{
CGPoint startPoint,endPoint;
NSInteger index;
CGFloat sum = self.leftMargin;
for (index = 0; index < _dataArray.count; index++)
{
sum += self.lineSpace;
if (xAxis < sum)
{
startPoint = CGPointMake(_modelPostionArray[index].xPosition, _modelPostionArray[index].yPosition);
_currentIndex = index;
break;
}
}
endPoint = CGPointMake(_modelPostionArray[index+1].xPosition, _modelPostionArray[index+1].yPosition);
CGFloat k = (endPoint.y - startPoint.y) / (endPoint.x -startPoint.x);
CGFloat y = k *(xAxis - startPoint.x) + startPoint.y;
return y;
}
3.關(guān)于這個圓角箭頭的View拼缝,我們也是通過貝塞爾曲線繪制得出
娱局,圓角計算一下四個圓角的相應(yīng)角度即可。?
-(void)addCirLayer
{
self.lineLayer = [CAShapeLayer layer];
self.lineLayer.strokeColor = [UIColor clearColor].CGColor;
self.lineLayer.fillColor = [[UIColor whiteColor] CGColor];
self.lineLayer.lineWidth = 1;
self.lineLayer.contentsScale = [UIScreen mainScreen].scale;
[self.layer addSublayer:self.lineLayer];
CGSize size = self.size;
UIBezierPath *path = [UIBezierPath bezierPath];
double offsetH = size.height - RADIUS*2 - AllowSize.height;
double offsetW = (size.width - RADIUS*2)/2;
CGPoint point = CGPointMake(RADIUS, 0);
[path moveToPoint:point];
point.x += size.width - RADIUS*2;
point.y += RADIUS;
[path addArcWithCenter:point radius:RADIUS startAngle:M_PI*3/2 endAngle:0 clockwise:YES];
point.x += RADIUS;
point.y += offsetH;
[path addLineToPoint:point];
point.x -= RADIUS;
[path addArcWithCenter:point radius:RADIUS startAngle:0 endAngle:M_PI/2 clockwise:YES];
point.y += RADIUS;
point.x -= offsetW;
[path addLineToPoint:point];
point.x -= AllowSize.width/2;
point.y += AllowSize.height;
[path addLineToPoint:point];
point.x -= AllowSize.width/2;
point.y -= AllowSize.height;
[path addLineToPoint:point];
point.x-= offsetW;
[path addLineToPoint:point];
point.y -= RADIUS;
[path addArcWithCenter:point radius:RADIUS startAngle:M_PI/2 endAngle:M_PI clockwise:YES];
point.x -= RADIUS;
point.y -= offsetH;
[path addLineToPoint:point];
point.x += RADIUS;
[path addArcWithCenter:point radius:RADIUS startAngle:M_PI endAngle:M_PI*3/2 clockwise:YES];
[path closePath];
self.lineLayer.path = path.CGPath;
}
4.關(guān)于光滑貝塞爾曲線的繪制
1.可以通過數(shù)學插值計算得出;
2.也可以通過計算兩個控制點繪制得出珍促。這里的繪制方法借鑒的是一位網(wǎng)上一位大牛的方法铃辖,其選擇的是第二種方法。
-(void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
寫到最后
1.Github地址點我下載
2.如果覺得還不錯猪叙,給個小星星吧(O(∩_∩)O~~)
3.如果有更好的思路娇斩,歡迎給我簡書留言?