3
2

More than 3 years have passed since last update.

【SwiftUI】Likeボタンタップ時のLike数増減とFirebaseの更新機能の実装

Posted at

はじめに

SwiftUIでカード内のLikeボタンを押した場合にLike数を+1し、再度押した場合に-1する機能を実装することと、その場合にFirebaseのデータベースを更新できるようにすることを目的とする。

今回はカード内のLikeボタンの実装を行います。

前回までの記事は以下を参考ください。

参考記事
【SwiftUI】Likeボタンとリスト内セルにボタンを実装する場合の注意点

開発環境

OSX 10.15.7 (Catalina)
Xcode 12.2.0
CocoaPods 1.10.0

実装したコード

ContentRowView_swift.png

主な変更点
・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
                        }
                    }
                }
            }
        }
    }
}

実装後のイメージ

タップ前
iPhone_11_–_14_2.png

Haiku_-_Cloud_Firestore_-_Firebase_コンソール.png

タップ後
iPhone_11_–_14_2.png

Haiku_-_Cloud_Firestore_-_Firebase_コンソール.png

再度、タップするとFirebaseのLike数は-1になり、Likeの見た目が元に戻ります。

ハートをアニメーションで動かす

Likeボタンをタップした場合に、ハートにアニメーションがかかるようにしました。

実装方法

ezgif-7-f0350d0318d1.gif

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))
    }
}

実際に実装した後のイメージ

かわいい感じになりました。
ezgif-7-eca8634e67ec.gif

以上です。

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