본문 바로가기
CODING/Android Studio

[안드로이드/인스타그램클론] # 8 상세화면 페이지 & 좋아요 ♥️ 버튼 만들기

by 밍톨맹톨 2020. 8. 19.
728x90
728x90

진짜 이번꺼 만들다가 오류 엄청뜨고 이틀내내(까지는 아니지만) 아무튼 계속 로그인도 엄청 느려서 처음으로 안드로이드 스튜디오 디버깅도 해봤는데 중괄호위치의 문제였,,다,, 진짜,, 스트렠스,,


상세화면 페이지를

res/layout/new - Layout Resourece File [" item_detail "]을 만들고

위와 같은 화면이 되도록 만들어준다.

 

[ item_detail.xml code ]

더보기
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical">

        <ImageView
            android:id="@+id/detailviewitem_profile_image"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_margin="7.5dp"
            android:src="@mipmap/ic_launcher" />

        <TextView
            android:id="@+id/detailviewitem_profile_textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    <ImageView
        android:id="@+id/detailviewitem_imageview_content"
        android:scaleType="fitXY"
        android:layout_width="match_parent"
        android:layout_height="350dp"/>
    <LinearLayout
        android:gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="50dp">
        <ImageView
            android:id="@+id/detailviewitem_favorite_imageview"
            android:src="@drawable/ic_favorite_border"
            android:layout_margin="10dp"
            android:layout_width="35dp"
            android:layout_height="35dp"/>

        <ImageView
            android:id="@+id/detailviewitem_comment_imageview"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:src="@drawable/ic_chat_black" />
    </LinearLayout>
    <TextView
        android:id="@+id/detailviewitem_favoritecounter_textview"
        android:layout_marginLeft="10dp"
        android:text="Like 0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/detailviewitem_explain_textview"
        android:layout_margin="10dp"
        android:text="Explain content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

 

recycleview를 만들기 위해 [ fragment_detail.xml ] 에 아래의 코드 추가 

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/detailviewfragment_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>

 


그리고 app -> open Module settings -> dependencies -> +버튼 -> Library Dependency로 창을 띄운 후 Glide를 검색 후 com.github.bumptech.glide 를 누르고 OK 한 뒤

 

[ DetailViewFragment.kt ]

 

더보기
package com.example.mingstagram.navigation

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.mingstagram.R
import com.example.mingstagram.navigation.model.ContentDTO
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.android.synthetic.main.fragment_detail.view.*
import kotlinx.android.synthetic.main.item_detail.view.*

class DetailViewFragment : Fragment() {
    var firestore: FirebaseFirestore? = null
    var uid : String? = null
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        var view = LayoutInflater.from(activity).inflate(R.layout.fragment_detail, container, false)

        firestore = FirebaseFirestore.getInstance()
        uid = FirebaseAuth.getInstance().currentUser?.uid

        view.detailviewfragment_recyclerview.adapter = DetailViewRecyclerViewAdapter()
        view.detailviewfragment_recyclerview.layoutManager = LinearLayoutManager(activity)
        return view
    }

    inner class DetailViewRecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        var contentDTOs: ArrayList<ContentDTO> = arrayListOf()
        var contentUidList: ArrayList<String> = arrayListOf()

        init {

            firestore?.collection("images")?.orderBy("timestamp")
                ?.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
                    contentDTOs.clear()
                    contentUidList.clear()
                    for (snapshot in querySnapshot!!.documents) {
                        var item = snapshot.toObject(ContentDTO::class.java)
                        contentDTOs.add(item!!)
                        contentUidList.add(snapshot.id)
                    }
                    notifyDataSetChanged()
                }
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            var view =
                LayoutInflater.from(parent.context).inflate(R.layout.item_detail, parent, false)
            return CustomViewHolder(view)
        }

        inner class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view)

        override fun getItemCount(): Int {
            return contentDTOs.size
        }

        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            var viewholder = (holder as CustomViewHolder).itemView

            //UserId
            viewholder.detailviewitem_profile_textview.text = contentDTOs!![position].userId


            //Image
            Glide.with(holder.itemView.context).load(contentDTOs!![position].imageUrl)
                .into(viewholder.detailviewitem_imageview_content)

            //Explain of content
            viewholder.detailviewitem_explain_textview.text = contentDTOs!![position].explain

            //likes
            viewholder.detailviewitem_favoritecounter_textview.text =
                "Likes " + contentDTOs!![position].favoriteCount

            //ProfileImage
            Glide.with(holder.itemView.context).load(contentDTOs!![position].imageUrl)
                .into(viewholder.detailviewitem_profile_image)

            //This code is when the button is clicked
            viewholder.detailviewitem_favorite_imageview.setOnClickListener {
                favoriteEvent(position)
            }

            //This code is when the page is loaded
            if(contentDTOs!![position].favorites.containsKey(uid)){
                //This is like status
                viewholder.detailviewitem_favorite_imageview.setImageResource(R.drawable.ic_favorite)
            }else{
                //This is unlike status
                viewholder.detailviewitem_favorite_imageview.setImageResource(R.drawable.ic_favorite_border)
            }
        }

        fun favoriteEvent(position: Int) {
            var tsDoc = firestore?.collection("images")?.document(contentUidList[position])
            firestore?.runTransaction { transaction ->

                var uid = FirebaseAuth.getInstance().currentUser?.uid
                var contentDTO = transaction.get(tsDoc!!).toObject(ContentDTO::class.java)

                if (contentDTO!!.favorites.containsKey(uid)) {
                    //When the button is clicked
                    contentDTO?.favoriteCount = contentDTO?.favoriteCount - 1
                    contentDTO?.favorites.remove(uid)
                } else {
                    //When the button is no clicked
                    contentDTO?.favoriteCount = contentDTO?.favoriteCount + 1
                    contentDTO?.favorites[uid!!] = true
                }
                transaction.set(tsDoc,contentDTO)
            }
        }

    }
}

 

  init {

            firestore?.collection("images")?.orderBy("timestamp")
                ?.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
                    contentDTOs.clear()
                    contentUidList.clear()
                    for (snapshot in querySnapshot!!.documents) {
                        var item = snapshot.toObject(ContentDTO::class.java)
                        contentDTOs.add(item!!)
                        contentUidList.add(snapshot.id)
                    }
                    notifyDataSetChanged()
                }
        }

데이터 베이스에 접근해서 timestamp순으로 받아오고 notifyDataSetChanged()로 새로 고침해주면서 화면을 내릴 수 있게 해준다

 

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            var view =
                LayoutInflater.from(parent.context).inflate(R.layout.item_detail, parent, false)
            return CustomViewHolder(view)
        }

inner class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view)

🌿 RecycleView를 사용할 때 메모리를 적게 사용하기 위해 CustomViewHolder 사용

 

        override fun getItemCount(): Int {
            return contentDTOs.size
        }

 🌿 가지고 있는 데이터 베이스 개수

 

        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            var viewholder = (holder as CustomViewHolder).itemView

            //UserId
            viewholder.detailviewitem_profile_textview.text = contentDTOs!![position].userId


            //Image
            Glide.with(holder.itemView.context).load(contentDTOs!![position].imageUrl)
                .into(viewholder.detailviewitem_imageview_content)

            //Explain of content
            viewholder.detailviewitem_explain_textview.text = contentDTOs!![position].explain

            //likes
            viewholder.detailviewitem_favoritecounter_textview.text =
                "Likes " + contentDTOs!![position].favoriteCount

            //ProfileImage
            Glide.with(holder.itemView.context).load(contentDTOs!![position].imageUrl)
                .into(viewholder.detailviewitem_profile_image)

            //This code is when the button is clicked
            viewholder.detailviewitem_favorite_imageview.setOnClickListener {
                favoriteEvent(position)
            }

            //This code is when the page is loaded
            if(contentDTOs!![position].favorites.containsKey(uid)){
                //This is like status
                viewholder.detailviewitem_favorite_imageview.setImageResource(R.drawable.ic_favorite)
            }else{
                //This is unlike status
                viewholder.detailviewitem_favorite_imageview.setImageResource(R.drawable.ic_favorite_border)
            }
        }

화면에 띄울 때 데이터를 매핑해주고 마지막 if문은 좋아요를 누르면 하트가 채워지고 else는 하트가 다시 빈하트로 바뀔 수 있게 해준다. 그리고 그 전에 있는

//This code is when the button is clicked
            viewholder.detailviewitem_favorite_imageview.setOnClickListener {
                favoriteEvent(position)
            }

이 부분은 하트 부분을 눌렀을 때 favoriteEvent(에 대한 설명은 아래에 있음)를 실행하는 코드 

 

[ mainActivity.kt ]에 아래의 코드를 넣어줘야함 

 

bottom_navigation.selectedItemId = R.id.action_home

 

[ 좋아요 버튼 기능 ]

  fun favoriteEvent(position: Int) {
            var tsDoc = firestore?.collection("images")?.document(contentUidList[position])
            firestore?.runTransaction { transaction ->

                var uid = FirebaseAuth.getInstance().currentUser?.uid
                var contentDTO = transaction.get(tsDoc!!).toObject(ContentDTO::class.java)

                if (contentDTO!!.favorites.containsKey(uid)) {
                    //When the button is clicked
                    contentDTO?.favoriteCount = contentDTO?.favoriteCount - 1
                    contentDTO?.favorites.remove(uid)
                } else {
                    //When the button is no clicked
                    contentDTO?.favoriteCount = contentDTO?.favoriteCount + 1
                    contentDTO?.favorites[uid!!] = true
                }
                transaction.set(tsDoc,contentDTO)
            }
        }

user의 정보를 가져와서 if 는 이미 클릭되어있을 경우 else 는 그렇지 않은 경우 

transaction.set(tsDoc,contentDTO) - 서버로 다시 결과를 보내주는 역할

 

동작화면

 

이번에는 너무 귀찮아서 대충쓰긴했는데 그래도 에러고치느라고 이미 코드를 너무 많이 보고 이해해버려서 그냥 메모 용도로 써버렸다,, 후,,

역시 에러가 나야 정신이 든달까,,?

728x90

댓글