【Swift】いかにも選択してますという感じの動く点線の枠を描く

選択中の点線枠

ペイントアプリなんかでよくある、選択した範囲を動く点線で囲むサンプルです。また使いそうなのでメモ代わりに。

こういうやつ
選択中の枠

仕組みは、点線の枠のオフセットをタイマーで変更して動いているように見せているだけです。簡単だけど、点線が動くだけですごくリッチな感じに見えますね。

ドラッグの処理はUIPanGestureRecognizerで行ってます。
ViewController.swift

import UIKit

class ViewController: UIViewController {

    var panGestureRecognizer: UIPanGestureRecognizer! = nil
    var selectAreaView: SelectAreaView! = nil
    var selectStartPoint: CGPoint = CGPointZero
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "dragView:")
        self.view.addGestureRecognizer(panGestureRecognizer)

    }

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        
        self.view.removeGestureRecognizer(panGestureRecognizer)
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func dragView(sender: UIPanGestureRecognizer) {
        
        if sender.state == UIGestureRecognizerState.Began {
            // ドラッグ開始
            selectStartPoint = sender.locationInView(self.view)
            
            var frame = CGRectMake( selectStartPoint.x, selectStartPoint.y,  0, 0)
            selectAreaView = SelectAreaView(frame: frame)
            self.view.addSubview(selectAreaView)
            
        } else if sender.state == UIGestureRecognizerState.Changed {
            // ドラッグ中
            var tapPoint = sender.translationInView(self.view)
            
            var frame: CGRect = CGRectZero
            
            if tapPoint.x > 0 && tapPoint.y > 0 {
                frame = CGRectMake(
                    selectStartPoint.x,
                    selectStartPoint.y,
                    tapPoint.x,
                    tapPoint.y)
                
            } else if tapPoint.x < 0  && tapPoint.y > 0 {
                frame = CGRectMake(
                    selectStartPoint.x + tapPoint.x,
                    selectStartPoint.y,
                    fabs(tapPoint.x),
                    tapPoint.y
                )
                
            } else if tapPoint.x > 0 && tapPoint.y < 0 {
                frame = CGRectMake(
                    selectStartPoint.x,
                    selectStartPoint.y + tapPoint.y,
                    tapPoint.x,
                    fabs(tapPoint.y)
                )
                
            } else if tapPoint.x < 0 && tapPoint.y < 0 {
                frame = CGRectMake(
                    selectStartPoint.x + tapPoint.x,
                    selectStartPoint.y + tapPoint.y,
                    fabs(tapPoint.x),
                    fabs(tapPoint.y)
                )
                
            }
            selectAreaView.changeFrame(frame)
            
            
        } else if sender.state == UIGestureRecognizerState.Ended {
            // ドラッグ終了
            selectAreaView.removeFromSuperview()
            
        }
    }

}

こちらが動く点線枠のクラス
SelectAreaView.swift

import Foundation
import UIKit

class SelectAreaView: UIView {
    
    let segmentSize: CGFloat = 4.0     // 点線の線のサイズ
    let gapSize: CGFloat = 4.0    // 点線の間のサイズ
    
    var myTimer: NSTimer! = nil
    var phaseCount: CGFloat = 0.0
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.backgroundColor = UIColor.clearColor()
        
        myTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "phaseChange:", userInfo: nil, repeats: true)
    }
    
    deinit {
        if myTimer != nil {
            myTimer.invalidate()
            myTimer = nil
        }
    }
    
    func phaseChange(timer: NSTimer) {
        
        phaseCount += 1.0
        
        if phaseCount >= segmentSize + gapSize {
            phaseCount = 0
        }
        self.setNeedsDisplay()
    }
    
    override func drawRect(rect: CGRect) {
        
        var path = UIBezierPath()
        
        UIColor.blackColor().set()
        
        path.lineWidth = 1
        
        var dashPattern = [segmentSize, gapSize]
        path.setLineDash(dashPattern, count:2, phase:phaseCount)
        
        path.moveToPoint(CGPointZero)
        
        path.addLineToPoint(CGPointMake(self.frame.size.width, 0))
        path.addLineToPoint(CGPointMake(self.frame.size.width, self.frame.size.height))
        path.addLineToPoint(CGPointMake(0, self.frame.size.height))
        path.addLineToPoint(CGPointMake(0, 0))
        path.stroke()
    }
    
    func changeFrame(frame: CGRect) {
        self.frame = frame
        self.setNeedsDisplay()
    }

}
タイトルとURLをコピーしました