LoginSignup
0
2

More than 1 year has passed since last update.

SwiftでレーダーのUIを作ってみた。[iOS、iPhoneアプリ]

Posted at

レーダーを作ってみたい

映画「トップガンマーヴェリック」を見て、戦闘機に付いているようなレーダーを再現してみたいと思い作ってみました。

完成図

スクリーンショット 2022-06-01 11.12.28.png

カスタムクラスを作る

今回はRadarViewというカスタムクラスを作って実装しました。

RadarView.swift
func configureUI() {
    isUserInteractionEnabled = false
    backgroundColor = UIColor.black
    layer.cornerRadius = bounds.width / 2
    layer.borderColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor
    layer.borderWidth = 1.0
        
    drawCircle()
    drawCenterCircle()
    rotateRadarImageView()
    startAnimating()
    addRadarImageView()
}

この関数でUIを作成し、ソナーを回転させる処理も行なっています。
まず

private func drawCircle() {
    let width = bounds.width / 2
    for i in 1...3 {
            
        let grayPath = UIBezierPath()
        grayPath.addArc(withCenter: CGPoint(x: width, y: width), // 中心
                            radius: (width / 4) * CGFloat(i), // 半径
                            startAngle: 0, // 開始角度
                            endAngle: .pi * 2.0, // 終了角度
                            clockwise: true) // 時計回り
        let grayLayer = CAShapeLayer()
        grayLayer.path = grayPath.cgPath
        grayLayer.fillColor = UIColor.clear.cgColor // 塗り色
        grayLayer.strokeColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 線の色
        grayLayer.lineWidth = 1.0 // 線の幅
        layer.addSublayer(grayLayer)            
    }
}

この関数で
レーダー画面の中に三つ円を描きます。

以下の関数ではレーダー画面の真ん中に点を描いています。

private func drawCenterCircle() {
    let width = bounds.width / 2
    let grayPath = UIBezierPath()
    grayPath.addArc(withCenter: CGPoint(x: width, y: width), // 中心
                        radius: 2.0, // 半径
                        startAngle: 0, // 開始角度
                        endAngle: .pi * 2.0, // 終了角度
                        clockwise: true) // 時計回り
    let grayLayer = CAShapeLayer()
    grayLayer.path = grayPath.cgPath
    grayLayer.fillColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 塗り色
    grayLayer.strokeColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 線の色
    grayLayer.lineWidth = 0.5 // 線の幅
    layer.addSublayer(grayLayer)        
}

次に、背景が透明な以下の様な画像を用意します。
自分はGIMPで作成しました。
haikei.png
この画像をレーダー画面の上に載せて、回転させれば完成です。

以下にコード全文載せておくので確認していただけると幸いです。

RadarView.swift
//
//  RadarView.swift
//  radarApp
//
//

import Foundation
import UIKit


class RadarView : UIView {
    
    var screenView = UIView()
    var radarLine = UIView()
    
    let arcLayer = CAShapeLayer()
    
    var isAnimating : Bool = false
    
    var animationTimer: Timer?
    var blinkingTimer: Timer?
    
    let radarImageView = UIImageView(image: UIImage(named: "haikei"))
    
    let redDot = UIView()
    
    //無いといけない奴ら
    override init(frame: CGRect) {
        super.init(frame: frame)
//        configureUI()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
//        configureUI()
    }
    
    func configureUI() {
        
        isUserInteractionEnabled = false
        backgroundColor = UIColor.black
        layer.cornerRadius = bounds.width / 2
        layer.borderColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor
        layer.borderWidth = 1.0
        
        drawCircle()
        drawCenterCircle()
        rotateRadarImageView()
        startAnimating()
        addRadarImageView()

    }
    
    private func addRadarImageView() {
        
        addSubview(radarImageView)
        radarImageView.center = center
        radarImageView.frame = bounds
        radarImageView.contentMode = .scaleAspectFill
        radarImageView.isUserInteractionEnabled = false
        
    }
    
    private func drawRadarLine() {
        
        let width = bounds.width / 2
        radarLine.backgroundColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0)
        addSubview(radarLine)
        radarLine.layer.anchorPoint = CGPoint(x: 0.0, y: 0.0)
        radarLine.frame = CGRect(x: width, y: width, width: width, height: 0.7)
        
    }
    
    private func drawCircle() {
        
        let width = bounds.width / 2
        for i in 1...3 {
            
            let grayPath = UIBezierPath()
            grayPath.addArc(withCenter: CGPoint(x: width, y: width), // 中心
                            radius: (width / 4) * CGFloat(i), // 半径
                            startAngle: 0, // 開始角度
                            endAngle: .pi * 2.0, // 終了角度
                            clockwise: true) // 時計回り
            let grayLayer = CAShapeLayer()
            grayLayer.path = grayPath.cgPath
            grayLayer.fillColor = UIColor.clear.cgColor // 塗り色
            grayLayer.strokeColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 線の色
            grayLayer.lineWidth = 1.0 // 線の幅
            layer.addSublayer(grayLayer)
            
        }

    }
    
    private func drawCenterCircle() {
        
        let width = bounds.width / 2
        let grayPath = UIBezierPath()
        grayPath.addArc(withCenter: CGPoint(x: width, y: width), // 中心
                        radius: 2.0, // 半径
                        startAngle: 0, // 開始角度
                        endAngle: .pi * 2.0, // 終了角度
                        clockwise: true) // 時計回り
        let grayLayer = CAShapeLayer()
        grayLayer.path = grayPath.cgPath
        grayLayer.fillColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 塗り色
        grayLayer.strokeColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1.0).cgColor // 線の色
        grayLayer.lineWidth = 0.5 // 線の幅
        layer.addSublayer(grayLayer)
    }

    
    @objc func moveRadarLine() {
        
        let moveAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation")
        moveAnimation.isRemovedOnCompletion = false
        moveAnimation.fillMode = CAMediaTimingFillMode.forwards
        moveAnimation.fromValue = 0
        moveAnimation.toValue = Double.pi * 2
        moveAnimation.duration = 6.0
        radarLine.layer.add(moveAnimation, forKey: "animation")
    }
    
    @objc func rotateRadarImageView() {
        let moveAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation")
        moveAnimation.isRemovedOnCompletion = false
        moveAnimation.fillMode = CAMediaTimingFillMode.forwards
        moveAnimation.fromValue = 0
        moveAnimation.toValue = Double.pi * 2
        moveAnimation.duration = 6.0
        radarImageView.layer.add(moveAnimation, forKey: "animation")
    }
    
    @objc func startAnimating() {
        
        animationTimer = Timer.scheduledTimer(timeInterval: 6.0, target: self, selector: #selector(rotateRadarImageView), userInfo: nil, repeats: true)
        
    }
    
    @objc func stopAnimating() {
        
        self.animationTimer?.invalidate()
        
    }
    
}

最後に、このカスタムクラスをViewControllerの方で呼んであげればアプリの完成です。
ですが、addSublayerで追加されたCALayerはビューのサイズ変更に追従してくれないそうなので

ViewController
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    radarView.configureUI()        
}

このようにViewControllerの方でUIをセッティングしてあげる必要があります。

最後に

今回はレーダーのUIを作ってみました。
これを何かに使うわけではないですが、いつか本物のレーダーとして使えればと思います。

また、今回は説明がざっくり過ぎてごめんなさない(>_<)
説明することが多くなりそうでざっくりにしてしまいました。
わからないことがあれば質問お願いします。

0
2
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
0
2