デモ
UIButtonと画像を使って以下のようなハート型のレーティングを作りました。
素材の準備
2種類のハート型の画像ファイルを準備します。
自作するのが面倒くさいのでアイコンフォントをPNGに変換できるサイトfa2png.ioを使います。
アイコンの形、大きさを統一させたいのでFontAwesomeの「fa-heart」と「fa-heart-o」を使います。
以下のようにフォント名や色、サイズを指定して「Generate」ボタンを押下後、「Download」ボタンを押下して画像ファイルをダウンロード。
そして出来上がった画像がこちら。
heartEmpty.png
heartFill.png
Xcodeで実装
1. Single View Applicationで適当にプロジェクトを作成します。
今回はHeartRatingという名前で作成しました。
2. 先程作った画像をドラッグ&ドロップしてプロジェクトに追加します。
3. UIButtonを配置します。
4. UIButtonの文字を削除して画像(heartEmpty)を設定します。
5. これと同じものを全部で5つ作ります。AutoLayoutも設定してキレイに並べます。
6. レーティングの数字を表示させるLableを配置し、初期値を0にしておきます。
7. 先程作ったボタンとラベルをIBOutletで接続します。
あと画像のインスタンス生成とレーティングの数字を入れる変数も用意しておきます。
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で接続します。
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. 各ボタンをタップした時に数字と画像が変わるように設定し、完成
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を切り替える。
コードがだいぶ短くなり、スッキリしました。ありがとうございます。
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^)/
ありがとうございます。
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
}
}
}