LoginSignup
12
13

More than 1 year has passed since last update.

CALayerをぐるぐる回す

Last updated at Posted at 2016-10-31

開発環境

  • XCode8.1
  • Swift3

20161031.gif

相変わらずgifではちょっとわかりづらいのですが、タッチの動きに連動して回ります。
一つだけオレンジ色なのは回ってるのか見え辛かったので。(何でオレンジなのかというと、意味はないです、はい)
githubへのリンクは以下

DaialAnimationSample

タッチの移動分を回転角度に変換するようにする

具体的には

  1. 最初のタッチの座標A(x1, y1)と円の中心座標C(xc, xy)の距離(=半径)r1を測る
  2. 次のタッチの座標B(x2, y2)と円の中心座標C(cx, cy)の距離(=半径)r2を測る
  3. r1とr2の比率hirituを測る
  4. 座標Bにhirituを掛けてr1の円周上の座標B'を測る
  5. AとB'の距離をピタゴラスの定理を利用して斜辺hとして測る
  6. hにr1/(回そうとしている円の半径)r0を掛ける
  7. 斜辺をr0、高さをh/2としてsinθ(=h/2 / r0)で求める。それの2倍が回転角度になる

下に図を用意しましたが、ちょっと分かり辛いです。うーむ、画像を作る技術も必要だな・・・

※黒い円が回そうとしている円
イメージ002.jpg

時計回りか反対か

横方向にスワイプしたら時計回りか、逆かはy座標によります。
右向けにスワイプして、y座標が中心点より上なら時計回り、下なら逆。
縦方向にスワイプした時の向きはx座標によります。
下にスワイプして、x座標が中心点より右なら時計回り、左なら逆といった感じです。

以下に角度と向きを算出してる部分を抜き出した。



    //回転演出
    func rotate(_ point : CGPoint, fin : Bool) {
        //斜辺の長さを算出(半径)
        let radius = getHypotenuse(_centerPoint, point2: point)
        //最初の半径とtmpの半径の比率
        let hiritu = radius / _radius
        //最初のポイントがある円周上にpointの座標を比率で割ったものをセット
        let tmpPoint = CGPoint(x: (point.x * hiritu), y: (point.y * hiritu))
        //前回と今回のポイントの距離(斜辺)を算出して対象の円周上で作った斜辺に比率を直す
        let base = getHypotenuse(_previousPoint, point2: tmpPoint) * (_radius/_originalRadius)

        if(base != 0){
            //方向
            var clockwise = true
            
            //270〜360度
            if(_previousPoint.x > _centerPoint.x && _previousPoint.y < _centerPoint.y) {
                //
                if(point.x == _previousPoint.x) {
                    clockwise = point.y > _previousPoint.y ? true : false
                } else {
                    clockwise = point.x > _previousPoint.x ? true : false
                }
                //0〜90度
            } else if(_previousPoint.x > _centerPoint.x && _previousPoint.y > _centerPoint.y) {
                if(point.x == _previousPoint.x) {
                    clockwise = point.y > _previousPoint.y ? true : false
                } else {
                    clockwise = point.x > _previousPoint.x ? false : true
                }
                //90〜180度
            } else if(_previousPoint.x < _centerPoint.x && _previousPoint.y > _centerPoint.y) {
                if(point.x == _previousPoint.x) {
                    clockwise = point.y > _previousPoint.y ? false : true
                } else {
                    clockwise = point.x > _previousPoint.x ? false : true
                }
                //180〜270度
            } else {
                if(point.x == _previousPoint.x) {
                    clockwise = point.y > _previousPoint.y ? false : true
                } else {
                    clockwise = point.x > _previousPoint.x ? true : false
                }
            }
            //sinの計算でラジアンを算出
            let radian = (1/_originalRadius)*(base/2) * 2
            
            if(radian > 0) {
                //アニメーション
                rotateAnimeation(radian, clockwise: clockwise)
             }
        }
        
        _previousPoint = point
        _radius = getHypotenuse(_centerPoint, point2: point)
    }
    
    
    //斜辺算出
    func getHypotenuse(_ point1 : CGPoint, point2 : CGPoint) -> CGFloat {
        let  radius = CGFloat(sqrt(pow(Double(point2.x - point1.x), 2) + pow(Double(point2.y - point1.y),2)))
        
        return radius
    }

もっとうまく出来るのではないかと思うが、煮詰まったのでここら辺で一旦締める。
とりあえず、次はこのダイヤルに加速と減速を加えてみたい。

12
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13