LoginSignup
9
11

More than 5 years have passed since last update.

【Swift3】ハート型レーティング作った【Xcode8】

Last updated at Posted at 2016-10-08

デモ

UIButtonと画像を使って以下のようなハート型のレーティングを作りました。

demo.gif

素材の準備

2種類のハート型の画像ファイルを準備します。
自作するのが面倒くさいのでアイコンフォントをPNGに変換できるサイトfa2png.ioを使います。
アイコンの形、大きさを統一させたいのでFontAwesomeの「fa-heart」と「fa-heart-o」を使います。
以下のようにフォント名や色、サイズを指定して「Generate」ボタンを押下後、「Download」ボタンを押下して画像ファイルをダウンロード。
heart1.PNG

そして出来上がった画像がこちら。
heartEmpty.png
heartEmpty.png
heartFill.png
heartFill.png

Xcodeで実装

1. Single View Applicationで適当にプロジェクトを作成します。

今回はHeartRatingという名前で作成しました。

2. 先程作った画像をドラッグ&ドロップしてプロジェクトに追加します。

1.png

3. UIButtonを配置します。

2.png

4. UIButtonの文字を削除して画像(heartEmpty)を設定します。

3.png

5. これと同じものを全部で5つ作ります。AutoLayoutも設定してキレイに並べます。

4.png

6. レーティングの数字を表示させるLableを配置し、初期値を0にしておきます。

スクリーンショット 2016-10-08 9.22.50.png

7. 先程作ったボタンとラベルをIBOutletで接続します。

あと画像のインスタンス生成とレーティングの数字を入れる変数も用意しておきます。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var heart1: UIButton!
    @IBOutlet weak var heart2: UIButton!
    @IBOutlet weak var heart3: UIButton!
    @IBOutlet weak var heart4: UIButton!
    @IBOutlet weak var heart5: UIButton!
    @IBOutlet weak var rateLabel: UILabel!

    var rate: Int = 0

    let heartFill:UIImage = UIImage(named:"heartFill")!
    let heartEmpty:UIImage = UIImage(named:"heartEmpty")!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

8. さらにボタンをIBActionで接続します。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var heart1: UIButton!
    @IBOutlet weak var heart2: UIButton!
    @IBOutlet weak var heart3: UIButton!
    @IBOutlet weak var heart4: UIButton!
    @IBOutlet weak var heart5: UIButton!
    @IBOutlet weak var rateLabel: UILabel!

    var rate: Int = 0

    let heartFill:UIImage = UIImage(named:"heartFill")!
    let heartEmpty:UIImage = UIImage(named:"heartEmpty")!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func heart1Tapped(_ sender: AnyObject) {
    }

    @IBAction func heart2Tapped(_ sender: AnyObject) {
    }

    @IBAction func heart3Tapped(_ sender: AnyObject) {
    }

    @IBAction func heart4Tapped(_ sender: AnyObject) {
    }

    @IBAction func heart5Tapped(_ sender: AnyObject) {
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

9. 各ボタンをタップした時に数字と画像が変わるように設定し、完成

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var heart1: UIButton!
    @IBOutlet weak var heart2: UIButton!
    @IBOutlet weak var heart3: UIButton!
    @IBOutlet weak var heart4: UIButton!
    @IBOutlet weak var heart5: UIButton!
    @IBOutlet weak var rateLabel: UILabel!

    var rate: Int = 0

    let heartFill:UIImage = UIImage(named:"heartFill")!
    let heartEmpty:UIImage = UIImage(named:"heartEmpty")!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func heart1Tapped(_ sender: AnyObject) {
        switch rate {            
        case 1:
            rate = 0

            heart1.setImage(heartEmpty, for: UIControlState())
            heart2.setImage(heartEmpty, for: UIControlState())
            heart3.setImage(heartEmpty, for: UIControlState())
            heart4.setImage(heartEmpty, for: UIControlState())
            heart5.setImage(heartEmpty, for: UIControlState())
        default:
            rate = 1

            heart1.setImage(heartFill, for: UIControlState())
            heart2.setImage(heartEmpty, for: UIControlState())
            heart3.setImage(heartEmpty, for: UIControlState())
            heart4.setImage(heartEmpty, for: UIControlState())
            heart5.setImage(heartEmpty, for: UIControlState())
        }
        rateLabel.text = String(rate)
    }

    @IBAction func heart2Tapped(_ sender: AnyObject) {
        rate = 2

        heart1.setImage(heartFill, for: UIControlState())
        heart2.setImage(heartFill, for: UIControlState())
        heart3.setImage(heartEmpty, for: UIControlState())
        heart4.setImage(heartEmpty, for: UIControlState())
        heart5.setImage(heartEmpty, for: UIControlState())

        rateLabel.text = String(rate)
    }

    @IBAction func heart3Tapped(_ sender: AnyObject) {
        rate = 3

        heart1.setImage(heartFill, for: UIControlState())
        heart2.setImage(heartFill, for: UIControlState())
        heart3.setImage(heartFill, for: UIControlState())
        heart4.setImage(heartEmpty, for: UIControlState())
        heart5.setImage(heartEmpty, for: UIControlState())

        rateLabel.text = String(rate)
    }

    @IBAction func heart4Tapped(_ sender: AnyObject) {
        rate = 4

        heart1.setImage(heartFill, for: UIControlState())
        heart2.setImage(heartFill, for: UIControlState())
        heart3.setImage(heartFill, for: UIControlState())
        heart4.setImage(heartFill, for: UIControlState())
        heart5.setImage(heartEmpty, for: UIControlState())

        rateLabel.text = String(rate)
    }

    @IBAction func heart5Tapped(_ sender: AnyObject) {
        rate = 5

        heart1.setImage(heartFill, for: UIControlState())
        heart2.setImage(heartFill, for: UIControlState())
        heart3.setImage(heartFill, for: UIControlState())
        heart4.setImage(heartFill, for: UIControlState())
        heart5.setImage(heartFill, for: UIControlState())

        rateLabel.text = String(rate)
    }
}

※10/8 追記

コメントでアドバイスを頂きましたので修正いたしました。
ViewDidLoad内でnormalとselected時の画像を設定。
rateにwillsetを設定して、タップ時にボタンのstateを切り替える。

コードがだいぶ短くなり、スッキリしました。ありがとうございます。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var heart1: UIButton!
    @IBOutlet weak var heart2: UIButton!
    @IBOutlet weak var heart3: UIButton!
    @IBOutlet weak var heart4: UIButton!
    @IBOutlet weak var heart5: UIButton!
    @IBOutlet weak var rateLabel: UILabel!


    let heartFill:UIImage = UIImage(named:"heartFill")!
    let heartEmpty:UIImage = UIImage(named:"heartEmpty")!

    var rate: Int = 0 {
        willSet {
            let hearts = [heart1, heart2, heart3, heart4, heart5]
            for (i, heart) in hearts.enumerated() {
                heart?.isSelected = i < newValue
            }
            rateLabel.text = "\(newValue)"
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let hearts = [heart1, heart2, heart3, heart4, heart5]
        for heart in hearts {
            heart?.setImage(heartEmpty, for: .normal)
            heart?.setImage(heartFill, for: .selected)
        }
    }

    @IBAction func heart1Tapped(_ sender: AnyObject) {
        switch rate {
        case 1:
            rate = 0

        default:
            rate = 1
        }
    }

    @IBAction func heart2Tapped(_ sender: AnyObject) {
        rate = 2
    }

    @IBAction func heart3Tapped(_ sender: AnyObject) {
        rate = 3
    }

    @IBAction func heart4Tapped(_ sender: AnyObject) {
        rate = 4
    }

    @IBAction func heart5Tapped(_ sender: AnyObject) {
        rate = 5
    }
}

※10/9 追記

コメントでさらにアドバイスを頂きました。
StoryBoard上で、UIButtonのState ConfigをSelectedにしてImageにheartFill.pngを設定。viewDidLoad内のコードは要らなくなったので削除しました。

さらにheart1~5のUIButtonのtagにそれぞれ1~5を設定。
全てのButtonのIBActionを一つにまとめて、その中に処理を記述。

コードがめちゃくちゃ短くなりました\(^O^)/
ありがとうございます。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var heart1: UIButton!
    @IBOutlet weak var heart2: UIButton!
    @IBOutlet weak var heart3: UIButton!
    @IBOutlet weak var heart4: UIButton!
    @IBOutlet weak var heart5: UIButton!
    @IBOutlet weak var rateLabel: UILabel!


    let heartFill:UIImage = UIImage(named:"heartFill")!
    let heartEmpty:UIImage = UIImage(named:"heartEmpty")!

    var rate: Int = 0 {
        willSet {
            let hearts = [heart1, heart2, heart3, heart4, heart5]
            for (i, heart) in hearts.enumerated() {
                heart?.isSelected = i < newValue
            }
            rateLabel.text = "\(newValue)"
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func heartButtonDidTap(_ sender: UIButton) {
        switch rate {
        case 1:
            if sender.tag == 1 {
                rate = 0
            } else {
                rate = sender.tag
            }
        default:
            rate = sender.tag
        }
    }
}
9
11
4

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
9
11