近期公司項目告一段落,閑來無事,看到山東中國移動客戶端有個轉(zhuǎn)盤動畫挺酷的。于是試著實現(xiàn)一下,看似簡單,可在coding時卻發(fā)現(xiàn)不少坑,填坑的同時還順便復(fù)習(xí)了一下高中數(shù)學(xué)知識(三角函數(shù)),收獲不小。
Demo & 效果圖:

1、首先初始化6個UIImageView
1)分析imgView的中心點位置

Δx = _radius * sin(α);
Δy = _radius * cos(α);
所以,
imgView.center.x = centerX + _radius * sin(currentAngle);
imgView.center.y = centerY - _radius * cos(currentAngle);
2)代碼
- (void)customUI {
CGFloat centerX = CGRectGetWidth(self.frame) * 0.5f;
CGFloat centerY = centerX;
_centerPoint = CGPointMake(centerX, centerY);//中心點
_blueView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];//藍色view
_blueView.center = _centerPoint;
_blueView.backgroundColor = [UIColor blueColor];
[self addSubview:_blueView];
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];//紅色view
redView.backgroundColor = [UIColor redColor];
[_blueView addSubview:redView];
_deltaAngle = M_PI / 3.0f;//6個imgView的間隔角度
CGFloat currentAngle = 0;
CGFloat imgViewCenterX = 0;
CGFloat imgViewCenterY = 0;
CGFloat imgViewW = 80;
CGFloat imgViewH =imgViewW;
_radius = centerX - imgViewW * 0.5f;//imgView.center到self.center的距離
for (int i = 0; i < 6; i++) {
currentAngle = _deltaAngle * i;
imgViewCenterX = centerX + _radius * sin(currentAngle);
imgViewCenterY = centerY - _radius * cos(currentAngle);
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, imgViewW, imgViewH)];
imgView.tag = kTag + i;
imgView.center = CGPointMake(imgViewCenterX, imgViewCenterY);
imgView.image = [UIImage imageNamed:[NSString stringWithFormat:@"circle%d", i]];
[self addSubview:imgView];
}
}
2、轉(zhuǎn)起來
1)計算任意點相對于原點(O)及x軸的夾角?

以點A為例:
CGFloat currentPointRadius = sqrt(pow(currentPoint.y - _centerPoint.y, 2) + pow(currentPoint.x - _centerPoint.x, 2));
所以,? = arccos((A.x - O.x) / OA),CGFloat curentPointAngle = acos((currentPoint.x - _centerPoint.x) / currentPointRadius);?。。∽⒁?,此處有坑
坑在哪?cos(x)和sin(x)的周期是2π,所以必定在求arccos(x)時一個值對應(yīng)兩個角度,此時需要判斷點是在哪個象限(
對于cos函數(shù)來說,要判斷點在第一、二象限還是在第三、四象限,如果是sin函數(shù),則應(yīng)該判斷點是第二、三象限還是在第一、四象限)再進行計算。下面是以cos函數(shù)分析:
如圖003,點C和點D,C在第二象限,D在第三象限,它們對應(yīng)的值相同但對應(yīng)的角度不同。
如果是C點,則CGFloat curentPointAngle = acos((currentPoint.x - _centerPoint.x) / currentPointRadius);
如果是D點,則curentPointAngle = (π - curentPointAngle) + π = 2 * π - curentPointAngle;
003
另外一個坑?。?!
不要嘗試用tan函數(shù)計算點相對于原點及x軸的夾角!
不要嘗試用tan函數(shù)計算點相對于原點及x軸的夾角??!
不要嘗試用tan函數(shù)計算點相對于原點及x軸的夾角!??!
因為tan函數(shù)在[0,2π]區(qū)間有2個周期,用的話會有出現(xiàn)各種bug!
2)計算變化的角度 Δ
以1)方法計算當(dāng)前點的角度curentPointAngle
上一個點的角度lastAngle
則變化角度CGFloat angle = lastAngle - curentPointAngle;
3)改變6個imgView中心點位置
_lastImgViewAngle = fmod(_lastImgViewAngle + angle, 2 * M_PI);//對當(dāng)前角度取模
CGFloat currentAngle = 0;
CGFloat imgViewCenterX = 0;
CGFloat imgViewCenterY = 0;
for (int i = 0; i < 6; i++) {
UIImageView *imgView = [self viewWithTag:kTag];
currentAngle = _deltaAngle * i + _lastImgViewAngle;
imgViewCenterX = _centerPoint.x + _radius * sin(currentAngle);
imgViewCenterY = _centerPoint.x - _radius * cos(currentAngle);
imgView = [self viewWithTag:kTag + i];
imgView.center = CGPointMake(imgViewCenterX, imgViewCenterY);
}
4)旋轉(zhuǎn)邏輯代碼
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
//計算上一個點相對于x軸的角度
CGFloat lastPointRadius = sqrt(pow(point.y - _centerPoint.y, 2) + pow(point.x - _centerPoint.x, 2));
if (lastPointRadius == 0) {
return;
}
_lastPointAngle = acos((point.x - _centerPoint.x) / lastPointRadius);
if (point.y > _centerPoint.y) {
_lastPointAngle = 2 * M_PI - _lastPointAngle;
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
//1.計算當(dāng)前點相對于x軸的角度
CGFloat currentPointRadius = sqrt(pow(currentPoint.y - _centerPoint.y, 2) + pow(currentPoint.x - _centerPoint.x, 2));
if (currentPointRadius == 0) {//當(dāng)點在中心點時,被除數(shù)不能為0
return;
}
CGFloat curentPointAngle = acos((currentPoint.x - _centerPoint.x) / currentPointRadius);
if (currentPoint.y > _centerPoint.y) {
curentPointAngle = 2 * M_PI - curentPointAngle;
}
//2.變化的角度
CGFloat angle = _lastPointAngle - curentPointAngle;
_blueView.transform = CGAffineTransformRotate(_blueView.transform, angle);
_lastImgViewAngle = fmod(_lastImgViewAngle + angle, 2 * M_PI);//對當(dāng)前角度取模
CGFloat currentAngle = 0;
CGFloat imgViewCenterX = 0;
CGFloat imgViewCenterY = 0;
for (int i = 0; i < 6; i++) {
UIImageView *imgView = [self viewWithTag:kTag];
currentAngle = _deltaAngle * i + _lastImgViewAngle;
imgViewCenterX = _centerPoint.x + _radius * sin(currentAngle);
imgViewCenterY = _centerPoint.x - _radius * cos(currentAngle);
imgView = [self viewWithTag:kTag + i];
imgView.center = CGPointMake(imgViewCenterX, imgViewCenterY);
}
_lastPointAngle = curentPointAngle;
}
最后,推薦一個同事@shelin分享的實用小工具,iOS-Images-Extractor,能快速獲得iOS *.ipa包中的圖片(包括Assets.car)。
