본문 바로가기

Android Project

[Android / Kotlin] SNS 앱 팀 프로젝트 - 디테일페이지

저번 포스팅에서 리사이클러뷰 아이템을 클릭했을때 DetailActivity로 이동하고 이동할때 title,content,image데이터를 전달해주는 작업까지 완료했다

이제 DetailActivity를 디자인하고 보낸 데이터를 받아서 화면에 표시해주는 작업을 해볼것이다!

 

# DetailActivity 레이아웃 디자인

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DetailActivity">

    <ImageView
        android:id="@+id/detail_img_imgview"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:background="#EAEAEA"
        android:scaleType="fitXY"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />

    <ImageButton
        android:id="@+id/detail_back_imgbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:background="@android:color/transparent"
        android:contentDescription="back button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_detail_back"
        tools:ignore="TouchTargetSizeCheck" />


    <TextView
        android:id="@+id/detail_title_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="28dp"
        android:layout_marginTop="240dp"
        android:minHeight="25dp"
        android:text="@string/title_name"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/detail_back_imgbtn" />

    <!-- 더보기 버튼 구현으로 minHeight 삭제-->
    <TextView
        android:id="@+id/detail_post_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="24dp"
        android:layout_marginRight="30dp"
        android:ellipsize="end"
        android:maxLines="2"
        android:text="@string/post_text"
        android:textColor="@color/black"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/detail_title_textview" />


    <ImageButton
        android:id="@+id/detail_empty_imgbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="@+id/detail_img_imgview"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_detail_border" />

    <ImageButton
        android:id="@+id/detail_heart_imgbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:background="@android:color/transparent"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/detail_img_imgview"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_detail_heart" />

    <TextView
        android:id="@+id/detail_postextend_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/post_textextend"
        android:textStyle="bold"
        android:visibility="gone"
        app:layout_constraintStart_toStartOf="@+id/detail_post_textview"
        app:layout_constraintTop_toBottomOf="@+id/detail_post_textview" />


</androidx.constraintlayout.widget.ConstraintLayout>

activity_detail.xml

 

activity_detail.xml

 

어짜피 데이터를 뿌려줄거기 때문에 이런식으로 디자인했다

처음엔 빈하트가 보이고 빈하트를 누르면 채워진하트 이미지로 변경해줄것이기 때문에 빈하트는 visibility를 visible로 설정해서 보이게 했고, 채워진하트는 invisible로 설정해서 일단 화면에 안보이게 했다

그리고 더보기버튼으로 텍스트의 길이를 길게 보여주는 용도로 사용할건데, 초기에는 보이지 않게 visibility를 gone으로 설정해서 안보이게 해줬다

둘다 visibility 속성을 썼는데 다른방식으로 사용해봤다

 

 

# DetailActivity

DetailActivity에서는 데이터를 받아와서 레이아웃에 표시하는 작업과 (빈하트 클릭 -> 채워진하트) , (채워진하트 클릭 -> 빈하트) 이런식으로 나오게 해볼것이고, 글자수가 2줄이 넘어가면 ...더보기 버튼이 활성화되어서 클릭하면 글이 다 보이는것을 다 구현해볼것이다

 

DetailActivity 전체코드이다

class DetailActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_detail)

        val back_btn = findViewById<ImageButton>(R.id.detail_back_imgbtn)
        // 백버튼 클릭시
        back_btn.setOnClickListener {
            finish()
        }

        val heart_btn = findViewById<ImageButton>(R.id.detail_heart_imgbtn)
        val empty_btn = findViewById<ImageButton>(R.id.detail_empty_imgbtn)
        val post_title_tv = findViewById<TextView>(R.id.detail_title_textview)
        val post_content_tv = findViewById<TextView>(R.id.detail_post_textview)
        val idol_image = findViewById<ImageView>(R.id.detail_img_imgview)

		// 빈하트 클릭시
        empty_btn.setOnClickListener {
            if(heart_btn.visibility == View.VISIBLE) {
                heart_btn.visibility = View.INVISIBLE
            } else {
                heart_btn.visibility = View.VISIBLE
            }
        }

		// 채워진 하트 클릭시
        heart_btn.setOnClickListener {
            if(heart_btn.visibility == View.VISIBLE) {
                heart_btn.visibility = View.INVISIBLE
            } else {
                heart_btn.visibility = View.VISIBLE
            }
        }


        // HomeFragment에서 보낸 데이터 받아오기
        val title = intent.extras?.getString("title")
        val content = intent.extras?.getString("content")
        val image = intent.extras?.getInt("image")      //image는 타입을 int로 설정했기때문에 getInt로 받아오기


        // 레이아웃과 데이터 연결
        post_title_tv.text = title
        post_content_tv.text = content

        if (image != null) {
            idol_image.setImageResource(image)
        }


        post_content_tv.setOnClickListener(this)


    }

    override fun onClick(v: View?) {

        var post_tv = findViewById<TextView>(R.id.detail_post_textview)
        var postExtend_tv = findViewById<TextView>(R.id.detail_postextend_textview)

        if(post_tv.lineCount > 2) {
            post_tv.maxLines = 2
            postExtend_tv.visibility = View.VISIBLE
        }

    }


    override fun onResume() {
        super.onResume()

        var post_tv = findViewById<TextView>(R.id.detail_post_textview)
        var postExtend_tv = findViewById<TextView>(R.id.detail_postextend_textview)

        setViewMore(post_tv,postExtend_tv)



    }


   @SuppressLint("SuspiciousIndentation")
   private fun setViewMore(contentTextView: TextView, viewMoreTextView: TextView) {
        contentTextView.post {
            val lineCount  = contentTextView.layout.lineCount
                // ...이 있으면 더보기 버튼 활성화
                if (contentTextView.layout.getEllipsisCount(lineCount - 1) > 0) {
                    viewMoreTextView.visibility = View.VISIBLE

                    // 더보기 클릭시 버튼 사라지게, 최대 6줄까지 늘어남
                    viewMoreTextView.setOnClickListener {
                        contentTextView.maxLines = 6
                        viewMoreTextView.visibility = View.GONE
                    }

            }
        }


    }


}

 

 

- 데이터를 받아와서 레이아웃에 표시

위 코드 중 이부분에 해당하는 코드인데

getString과 getInt를 사용해서 HomeFragment에서 보낸 데이터를 받아와준뒤,

해당하는 레이아웃에 방금 받아온 데이터를 연결해준다 

이미지는 setImageResoure를 사용해서 연결해준다 (Glide를 사용할 수도 있음)

// HomeFragment에서 보낸 데이터 받아오기
val title = intent.extras?.getString("title")
val content = intent.extras?.getString("content")
val image = intent.extras?.getInt("image")      //image는 타입을 int로 설정했기때문에 getInt로 받아오기


// 레이아웃과 데이터 연결
post_title_tv.text = title
post_content_tv.text = content

if (image != null) {
    idol_image.setImageResource(image)
}

 

- 데이터 받아오기 실행화면

이런식으로 클릭했을때 해당하는 레이아웃에 image,title,content가 잘 뿌려진걸 확인할 수 있다

 

 

 

 

 

 

- 하트 클릭

위 코드 중 이부분에 해당하는 코드인데 

빈하트 클릭시에 만약 채워진하트가 활성화되어있다면 채워진하트를 안보이게하고, 활성화되어있지 않으면 그때 채워진하트를 보이게하는 코드다. (즉, 빈하트 클릭했을때 채워진하트가 보이게하는코드다)

그리고 채워진 하트 클릭시에 만약 채워진하트가 활성화되어있다면 안보이게하고, 활성화되어있지 않으면 채워진하트를 보이게 하는것이다

처음 조건문 한개만 작성해주면 잘 될것같지만, 그렇게만 써주면 (채워진하트 -> 빈하트) 부분이 정상적으로 작동하지 않기때문에 코드를 한번 더 써줬다

	// 빈하트 클릭시
        empty_btn.setOnClickListener {
            if(heart_btn.visibility == View.VISIBLE) {
                heart_btn.visibility = View.INVISIBLE
            } else {
                heart_btn.visibility = View.VISIBLE
            }
        }

		// 채워진 하트 클릭시
        heart_btn.setOnClickListener {
            if(heart_btn.visibility == View.VISIBLE) {
                heart_btn.visibility = View.INVISIBLE
            } else {
                heart_btn.visibility = View.VISIBLE
            }
        }

 

- 좋아요 실행화면

 

 

 

 

 

 

- 더보기 버튼

일단 처음에 레이아웃을 디자인할때 게시물 내용부분에  maxLines, ellipsize를 설정해서 글이 2줄이 넘어가면 뒤에 ...이 뜨도록 설정했다

그리고 더보기버튼은 초기에는 보이지 않게 디자인해줬다

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DetailActivity">

	...

    <TextView
        android:id="@+id/detail_post_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="24dp"
        android:layout_marginRight="30dp"
        android:ellipsize="end"
        android:maxLines="2"
        android:text="@string/post_text"
        android:textColor="@color/black"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/detail_title_textview" />

    <TextView
        android:id="@+id/detail_postextend_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/post_textextend"
        android:textStyle="bold"
        android:visibility="gone"
        app:layout_constraintStart_toStartOf="@+id/detail_post_textview"
        app:layout_constraintTop_toBottomOf="@+id/detail_post_textview" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

코틀린 코드는 아래에 해당하는 부분이다 setViewMore이라는 함수를 만들어서

if문을 통해 게시물내용이 maxLines인 2줄을 넘어가서 마지막줄에  ellipsis(...)가 형성되었는지 체크를 해준다음 

더보기버튼이 보이도록 활성화 시켜준다

그리고 더보기 버튼을 클릭했을때 최대 6줄까지 보이도록 설정해주었고, 더보기버튼이 보이지 않도록 설정해주었다

그리고 이 함수를 onResume()상태일때 호출되도록 했다

마지막으로 게시글이 두줄 이상일때만 더보기버튼이 활성화되도록 따로 설정해주었다. 한줄일때는 딱히 더보기버튼을 표시해주지 않도록 했다

class DetailActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_detail)
        
        ...
        

        post_content_tv.setOnClickListener(this)

    }


    override fun onClick(v: View?) {

        var post_tv = findViewById<TextView>(R.id.detail_post_textview)
        var postExtend_tv = findViewById<TextView>(R.id.detail_postextend_textview)

        if(post_tv.lineCount > 2) {
            post_tv.maxLines = 2
            postExtend_tv.visibility = View.VISIBLE
        }
    }


    override fun onResume() {
        super.onResume()

        var post_tv = findViewById<TextView>(R.id.detail_post_textview)
        var postExtend_tv = findViewById<TextView>(R.id.detail_postextend_textview)
		
        // setViewMore함수 호출
        setViewMore(post_tv,postExtend_tv)
    }


   @SuppressLint("SuspiciousIndentation")
   private fun setViewMore(contentTextView: TextView, viewMoreTextView: TextView) {
        contentTextView.post {
            val lineCount  = contentTextView.layout.lineCount
                // 게시물내용이 2줄을 넘어가서 마지막줄에 ellipsis(...)가 생겼는지 체크
                if (contentTextView.layout.getEllipsisCount(lineCount - 1) > 0) {
                	// 더보기 버튼 보이게 활성화
                    viewMoreTextView.visibility = View.VISIBLE

                    // 더보기버튼 클릭시
                    viewMoreTextView.setOnClickListener {
                        contentTextView.maxLines = 6			// 최대 6줄까지 보이도록
                        viewMoreTextView.visibility = View.GONE	// 더보기버튼 안보이게
                    }
            }
        }
    }

}

 

- 더보기 버튼 실행화면