3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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数左にあるハートマークも変更できるようにしています。

swift
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/d9407b87-9bcb-c565-f616-44f6262d6ed9.png)

![Haiku_-_Cloud_Firestore_-_Firebase_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/35ff3eca-9113-f595-b8af-a979610109f1.png)

**タップ後**
![iPhone_11_–_14_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/9e779848-76cd-8fe0-1f89-7e12dbf12a8f.png)

![Haiku_-_Cloud_Firestore_-_Firebase_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/7e36ebf7-b6a9-760b-7133-4a6f379c54b0.png)

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

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

### 実装方法
![ezgif-7-f0350d0318d1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/713a1ebd-ff12-21b9-db1e-63ef32c7d60a.gif)


```swift
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?