はじめに
SwiftUIでカード内のLikeボタンを押した場合にLike数を+1し、再度押した場合に-1する機能を実装することと、その場合にFirebaseのデータベースを更新できるようにすることを目的とする。
今回はカード内のLikeボタンの実装を行います。
前回までの記事は以下を参考ください。
参考記事
【SwiftUI】Likeボタンとリスト内セルにボタンを実装する場合の注意点
開発環境
OSX 10.15.7 (Catalina)
Xcode 12.2.0
CocoaPods 1.10.0
実装したコード
主な変更点
・Likeボタン内にif文を設定
→ボタンを押した場合はLike数を+1、再度押した場合は-1になるようにしました。また、押した場合はFirebaseのデータベースが更新されるようにしています。
struct ContentRowView: View {
var id = ""
var user = ""
...略...
static let formatter = RelativeDateTimeFormatter()
// 以下を追記
@State var isLiked = false
var body: some View {
...略...
// Likes Number
HStack {
Image(systemName: isLiked ? "heart.fill": "heart").font(.headline).foregroundColor(Color("pinkColor"))
Text(likes).font(.headline).foregroundColor(Color("pinkColor"))
Spacer()
}.padding(.top, 5)
// Info
HStack {
...略...
// Like Button push Image to add like's Number.
Image(systemName: isLiked ? "heart.fill": "heart")
.font(.title)
.foregroundColor(Color("pinkColor"))
.onTapGesture {
self.isLiked.toggle()
if isLiked == true {
// push button
print("true. likes+1")
// update likes...
let db = Firestore.firestore()
let like = Int.init(self.likes)!
db.collection("ikku").document(id).updateData(["likes": "\(like + 1)"]) { (err) in
if err != nil{
print((err) as Any)
return
}
print("updated....")
}
} else {
// And push Button
print("false. likes-1")
// update likes...
let db = Firestore.firestore()
let like = Int.init(self.likes)!
db.collection("ikku").document(id).updateData(["likes": "\(like - 1)"]) { (err) in
if err != nil{
print((err) as Any)
return
}
print("updated....")
}
}
}
.frame(width: 30, height: 30)
}.padding(5)
}.padding(.top, 8).frame(height: 391)
}
}
・getDataクラス内に.modified
を実装
→Likeボタンを押すと、Like数も変更するようにしました。実装にあたって、ボタンを押すと、Like数左にあるハートマークも変更できるようにしています。
class getData: ObservableObject {
@Published var datas = [dataType]()
init() {
let db = Firestore.firestore()
db.collection("ikku").order(by: "now", descending: true).addSnapshotListener{ (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
for i in snap!.documentChanges{
if i.type == .added{
let id = i.document.documentID
let user = i.document.get("userName") as! String
let haiku = i.document.get("haiku") as! String
let place = i.document.get("place") as! String
let likes = i.document.get("likes") as! String
let mapImage = i.document.get("mapImage") as! String
let userImage = i.document.get("userImage") as! String
let now = i.document.get("now") as! Timestamp
let stamp = i.document.get("createdDate") as! Timestamp
let formatterDate = DateFormatter()
formatterDate.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let createdDate = formatterDate.string(from: stamp.dateValue())
let isLiked = false
DispatchQueue.main.async {
self.datas.append(dataType(id: id, user: user, haiku: haiku, place: place, likes: likes, mapImage: mapImage, userImage: userImage, stamp: stamp.dateValue(), createdDate: createdDate, now: now.dateValue(), isLiked: isLiked ))
}
}
// 以下を追加
if i.type == .removed{
let id = i.document.documentID
for j in 0 ..< self.datas.count {
if self.datas[j].id == id{
self.datas.remove(at: j)
return
}
}
}
if i.type == .modified{
let id = i.document.documentID
let likes = i.document.get("likes") as! String
for j in 0 ..< self.datas.count {
if self.datas[j].id == id{
self.datas[j].likes = likes
return
}
}
}
}
}
}
}
実装後のイメージ
再度、タップするとFirebaseのLike数は-1になり、Likeの見た目が元に戻ります。
ハートをアニメーションで動かす
Likeボタンをタップした場合に、ハートにアニメーションがかかるようにしました。
実装方法
import SwiftUI
struct ContentView: View {
@State private var isLiked = false
var body: some View {
VStack {
Text(isLiked ? "Liked!" : "unLiked!")
HeartButton(isLiked: $isLiked)
}
}
}
struct HeartButton: View {
@Binding var isLiked : Bool
private let animationDuration : Double = 0.1
private var animationScale : CGFloat {
isLiked ? 0.7 : 1.3
}
@State private var animate = false
var body: some View {
Button(action: {
self.animate = true
DispatchQueue.main.asyncAfter(deadline: .now() + self.animationDuration, execute: {
self.animate = false
self.isLiked.toggle()
})
if isLiked == true {
// push button
print("true")
} else {
// And push Button
print("false")
}
}, label: {
Image(systemName: isLiked ? "heart.fill": "heart")
.font(.largeTitle)
.foregroundColor(Color.red)
.frame(width: 100, height: 100)
})
.scaleEffect(animate ? animationScale : 1)
.animation(.easeIn(duration: animationDuration))
}
}
実際に実装した後のイメージ
以上です。