LoginSignup
17
20

More than 5 years have passed since last update.

【iOS】Pathの描画をパーセンテージで指定する

Last updated at Posted at 2015-10-31

まず始めに

Pathをアニメーションで描画するのではなく、パーセンテージで描画する方法について書こうと思います。
パーセンテージ指定でPathの描画をさせると、以下のGIFアニメーションのようにスライダーと連動して描画できるようになったりもします。
path.gif

どのように実装しているのか

実装する上でのポイントは以下のようになります。
- CAShapeLayerのインスタンスをUIViewdrawRectで描画する
- CAShapeLayerstrokeEndを使ってパーセンテージ指定できるようにする

class PathStokeAdjustableView: UIView { 
    private let shapeLayer = CAShapeLayer()

    private var _stroke: CGFloat = 0 {
        didSet {
            shapeLayer.strokeEnd = _stroke
        }
    }
    var stroke: CGFloat {
        set {
            _stroke = max(0, min(1, newValue))
        }
        get {
            return _stroke
        }
    }

    //MARK: - XibやStroyboardから呼ばれた時
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        layer.addSublayer(shapeLayer)
        shapeLayer.strokeEnd = 0
        layoutIfNeeded()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setNeedsDisplay()
    }

    //MARK: - コードで生成された時
    init() {
        super.init(frame: .zero)
        layer.addSublayer(shapeLayer)
        shapeLayer.strokeEnd = 0
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        layer.addSublayer(shapeLayer)
        shapeLayer.strokeEnd = 0
    }

    //MARK: - Pathの描画
    override func drawRect(rect: CGRect) {
        UIColor.whiteColor().setFill()
        shapeLayer.lineWidth = 10
        shapeLayer.strokeColor = UIColor.blackColor().CGColor
        shapeLayer.fillColor = UIColor.whiteColor().CGColor
        shapeLayer.path = path().CGPath
    }
}

extension PathStokeAdjustableView {
    func path() -> UIBezierPath {
        let path = UIBezierPath()
        path.moveToPoint(CGPoint(x: CGRectGetMinX(bounds), y: CGRectGetMinY(bounds)))
        path.addLineToPoint(CGPoint(x: CGRectGetMaxX(bounds), y: CGRectGetMinY(bounds)))
        path.addLineToPoint(CGPoint(x: CGRectGetMaxX(bounds), y: CGRectGetMaxY(bounds)))
        path.addLineToPoint(CGPoint(x: CGRectGetMinX(bounds), y: CGRectGetMaxY(bounds)))
        path.addLineToPoint(CGPoint(x: CGRectGetMinX(bounds), y: CGRectGetMinY(bounds)-5))
        return path
    }
}

StoryboardにはUIViewUISliderを適当に追加してください。

stroyboard.png

この後、PathStokeAdjustableViewStoryboardの中で指定するか、ViewControllerの中でaddSubViewするかによって書き方が少し変わってきます。

Storyboardで指定する場合

以下のスクリーンショットのように、追加したUIViewのCustom ClassをPathStokeAdjustableViewに指定してください。

screen.png

ViewController自体の実装はSliderの値を受け取ったとき、PathStokeAdjustableViewのインスタンスにstrokeの値として受け取ったものを渡すだけです。

class ViewController: UIViewController {
    @IBOutlet weak var pathView: PathStokeAdjustableView!

    @IBAction func sliderValueChanged(sender: AnyObject) {
        guard let slider = sender as? UISlider else {
            return
        }
        pathView.stroke = CGFloat(slider.value)
    }
}

ViewControllerで生成する場合

  • Storyboardで追加したUIViewのCustom Classは変更せず、UIViewのままにしてください。
  • 上記のUIViewpathContainerViewとして使用します。
  • PathStokeAdjustableViewのインスタンスを生成して、AutoLayoutなどを使用しpathContainerViewaddSubviewしてください。
  • strokeへ値を渡す実装に違いはありません。
class ViewController: UIViewController {
    @IBOutlet weak var pathContainerView: UIView!
    private let pathView =  PathStokeAdjustableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        pathView.translatesAutoresizingMaskIntoConstraints = false
        pathContainerView.addSubview(pathView)
        pathContainerView.addConstraints([
            NSLayoutConstraint(item: pathView, attribute: .Top, relatedBy: .Equal, toItem: pathContainerView, attribute: .Top, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pathView, attribute: .Right, relatedBy: .Equal, toItem: pathContainerView, attribute: .Right, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pathView, attribute: .Left, relatedBy: .Equal, toItem: pathContainerView, attribute: .Left, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pathView, attribute: .Bottom, relatedBy: .Equal, toItem: pathContainerView, attribute: .Bottom, multiplier: 1, constant: 0)
        ])
    }

    @IBAction func sliderValueChanged(sender: AnyObject) {
        guard let slider = sender as? UISlider else {
            return
        }
        pathView.stroke = CGFloat(slider.value)
    }
}

注意点

Pathのstrokeには対応していますが、fillには対応していません。

最後に

Pathをパーセンテージ指定して描画できるようにすることによって、UISliderの値に合わせるだけでなく、UITableViewなどのスクロールに合わせて描画したりもできるようになります。

17
20
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
17
20