[Android 앱 개발 입문]팀 과제 - 하이커스(4)메인 화면 기능 구현

0
post-thumbnail
post-custom-banner

🍥구현 기능

  • 화면 상단:
    • 현재 로그인 한 회원의 이름, 프로필 이미지 표시
    • 프로필 이미지 클릭 시, 마이페이지로 이동
    • 마이페이지로 이동할 때, 프로필 이미지를 공유하는 애니메이션 사용
  • 화면 중앙:
    • 최신 게시글 10개 표시
    • 게시글을 클릭하는 경우, 해당 게시글의 디테일 화면으로 이동
    • 게시글의 하트를 클릭하는 경우, 해당 게시글 좋아요/좋아요 취소 처리
  • 화면 하단:
    • 플로팅 버튼 클릭 시, 글쓰기 화면으로 이동

🍥구현하기

MainActivity.kt

  • onResume() 메소드 오버라이드
    • 글쓰기 화면에서 새로운 글 작성 후 메인 화면으로 돌아온 경우
      or 디테일 화면에서 좋아요 버튼 클릭 후 메인 화면으로 돌아온 경우
      -> ScrollView 항목에 변경사항 반영되어야 함
      -> onResume() 내부에서 initScrollView() 메소드 호출
    • 마이 페이지 화면에서 회원 정보 수정 후 메인 화면으로 돌아온 경우
      -> 화면 상단 프로필 영역에 변경사항 반영되어야 함
      -> onResume() 내부에서 initProfile() 메소드 호출
  • 메인 화면에서 마이 페이지 화면으로 이동 시,
    공유 요소가 있는 화면 애니메이션 적용

📌참고자료: 애니메이션으로 활동 시작 | Android Developers

공유 요소가 있는 활동 시작

(1) 공유 요소가 있는 두 레이아웃의 XML 파일에서,
공유 요소의 android:transitionName 속성으로 공통 이름 지정
(2) ActivityOptions.makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName) 메소드 사용
(3) startActivity의 Bundle 인자로 option 넘겨주기

    // get the element that receives the click event
    val imgContainerView = findViewById<View>(R.id.img_container)
    // get the common element for the transition in this activity
    val androidRobotView = findViewById<View>(R.id.image_small)
    // define a click listener
    imgContainerView.setOnClickListener( {
        val intent = Intent(this, Activity2::class.java)
        // create the transition animation - the images in the layouts
        // of both activities are defined with android:transitionName="robot"
        val options = ActivityOptions
                .makeSceneTransitionAnimation(this, androidRobotView, "robot")
        // start the new activity
        startActivity(intent, options.toBundle())
    })
class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"

    private val userGreetingTextView: TextView by lazy { findViewById(R.id.tv_user_greeting) }
    private val userProfileImageView: ImageView by lazy { findViewById(R.id.iv_user_profile) }

    private val noPostTextView: TextView by lazy { findViewById(R.id.tv_no_post) }
    private val postScrollView: ScrollView by lazy { findViewById(R.id.scroll_view_post) }

    private val writeFloatingButton: FloatingActionButton by lazy { findViewById(R.id.floating_btn_write) }

    private val postItemList by lazy {
        listOf<ViewGroup>(
            findViewById(R.id.post_item1),
            findViewById(R.id.post_item2),
            findViewById(R.id.post_item3),
            findViewById(R.id.post_item4),
            findViewById(R.id.post_item5),
            findViewById(R.id.post_item6),
            findViewById(R.id.post_item7),
            findViewById(R.id.post_item8),
            findViewById(R.id.post_item9),
            findViewById(R.id.post_item10)
        )
    }

    //postItemIDMap[postItem]: postItem이 표시하는 게시물 ID
    private val postItemIDMap by lazy {
        mutableMapOf<Int, Int>(
            R.id.post_item1 to -1,
            R.id.post_item2 to -1,
            R.id.post_item3 to -1,
            R.id.post_item4 to -1,
            R.id.post_item5 to -1,
            R.id.post_item6 to -1,
            R.id.post_item7 to -1,
            R.id.post_item8 to -1,
            R.id.post_item9 to -1,
            R.id.post_item10 to -1
        )
    }

    private val userManager = UserManager.newInstance()
    private val postManager = PostManager.newInstance()

    //현재 로그인 한 유저의 아이디
    private val userID by lazy {
        intent.getStringExtra(EXTRA_ID) ?: "lee_younghee"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //화면 상단 프로필 영역 표시
        initProfile()
        //프로필 이미지 클릭 이벤트 처리하기
        initProfileImageView()

        //최신 게시글 표시
        initScrollView()
        //게시글 클릭 이벤트 처리하기
        initPostItem()

        //글쓰기 버튼 클릭 이벤트 처리하기
        initWriteFloatingButton()
    }

    override fun onResume() {
        super.onResume()

        Log.d(TAG, postManager.getRecentPostList(1).toString())
        //최신 게시글 새로 표시
        initScrollView()
        //프로필 영역 새로 표시
        initProfile()
    }

    private fun initProfile() {
        val loginUser = userManager.findUserByID(userID)!!
        val userName = loginUser.name
        val userImage = loginUser.profileImage

        userGreetingTextView.text = getString(R.string.user_greeting, userName)
        userProfileImageView.run {
            if (userImage != null){
                try{
                    Log.d(TAG, "user profile image uri is not null")
                    setImageURI(userImage)
                }
                catch(e:Exception){
                    Log.d(TAG, "프로필 이미지 uri 접근 문제 발생!")
                    setImageResource(R.drawable.default_profile)
                }
            }
            else {
                Log.d(TAG, "user profile image uri is null")
                setImageResource(R.drawable.default_profile)
            }
        }
    }


    private fun initProfileImageView() {
        userProfileImageView.setOnClickListener {
            Log.d(TAG, "profile image clicked")
            //로그인한 회원 ID 전달하며, 마이페이지 화면으로 이동
            val profileIntent = Intent(this, MyPage::class.java).apply {
                putExtra(EXTRA_ID, userID)
            }

            //공유 요소가 있는 화면 애니메이션 만들기
            val options = ActivityOptions
                .makeSceneTransitionAnimation(this, userProfileImageView, resources.getString(R.string.trans_profile_image))

            startActivity(profileIntent, options.toBundle())
        }
    }

    private fun initScrollView() {
        postItemList.forEach { it.isVisible = false }
        val recentPostList = postManager.getRecentPostList(10)

        //최신 글이 없는 경우
        if (recentPostList.isEmpty()) {
            noPostTextView.isVisible = true
            postScrollView.isVisible = false
            return
        }
        //최신 글이 있는 경우
        noPostTextView.isVisible = false
        postScrollView.isVisible = true
        for ((index, post) in recentPostList.withIndex()) {
            val postItem = postItemList[index]

            postItemIDMap[postItem.id] = post.postID
            postItem.isVisible = true

            //게시글 정보 표시하기
            val imageImageView = postItem.findViewById<ImageView>(R.id.iv_img)
            val titleTextView = postItem.findViewById<TextView>(R.id.tv_title)
            val locationTextView = postItem.findViewById<TextView>(R.id.tv_location)
            val writerNameTextView = postItem.findViewById<TextView>(R.id.tv_writer_name)
            val timeTextView = postItem.findViewById<TextView>(R.id.tv_time)

            imageImageView.run {
                if (post.image != null) {
                    try {
                        Log.d(TAG, "postID: ${post.postID}, image uri is not null")
                        setImageURI(post.image)
                        scaleType = ImageView.ScaleType.CENTER_CROP
                    }
                    catch (e:Exception){
                        Log.d(TAG, "게시물 이미지 uri 접근 문제 발생!")
                        setImageResource(R.drawable.hikers_icon_small_grey)
                        scaleType = ImageView.ScaleType.CENTER
                    }
                } else {
                    Log.d(TAG, "postID: ${post.postID}, image uri is null")
                    setImageResource(R.drawable.hikers_icon_small_grey)
                    scaleType = ImageView.ScaleType.CENTER
                }
            }
            titleTextView.text = post.title
            locationTextView.text = post.location
            writerNameTextView.text = userManager.findUserByID(post.writerId)!!.name
            timeTextView.text = post.writtenTime

            //게시글 좋아요 여부 표시하기
            val heartImageView = postItem.findViewById<ImageView>(R.id.iv_heart)

            val loginUser = userManager.findUserByID(userID)!!
            heartImageView.setImageResource(
                if (loginUser.isInLikedPostIDList(post.postID)) R.drawable.full_heart_icon
                else R.drawable.empty_heart_icon
            )
        }
    }

    private fun initPostItem() {
        for (postItem in postItemList) {
            //좋아요 클릭 이벤트 처리하기
            val heartImageView = postItem.findViewById<ImageView>(R.id.iv_heart)
            heartImageView.setOnClickListener {
                val postID = postItemIDMap[postItem.id]!!
                Log.d(TAG, "post item heart clicked) post id: ${postID}")

                //좋아요 여부 확인하기
                val loginUser = userManager.findUserByID(userID)!!

                //이미 좋아요한 경우, 좋아요 삭제하기
                if (loginUser.isInLikedPostIDList(postID)) {
                    heartImageView.setImageResource(R.drawable.empty_heart_icon)
                    loginUser.deleteLikedPostID(postID)

                    postManager.findPostByID(postID)!!.minusHeartCount()
                }
                //이미 좋아요하지 않은 경우, 좋아요 추가하기
                else {
                    heartImageView.setImageResource(R.drawable.full_heart_icon)
                    loginUser.addLikedPostID(postID)

                    postManager.findPostByID(postID)!!.plusHeartCount()
                }
            }

            //게시글 클릭 이벤트 처리하기
            postItem.setOnClickListener {
                val postID = postItemIDMap[postItem.id]
                Log.d(TAG, "post item clicked) post id: ${postID}")

                if(postID == -1) return@setOnClickListener

                //로그인한 회원 ID와 게시물 ID 전달하며, 디테일 화면으로 이동
                val detailIntent = Intent(this, DetailPageActivity::class.java).apply{
                    putExtra("userID", userID)
                    putExtra("postID", postID)
                }

                //메인 화면과 디테일 화면의 공유 요소
                val postImageView = postItem.findViewById<ImageView>(R.id.iv_img)
                //공유 요소가 있는 화면 애니메이션 만들기
                val options = ActivityOptions
                    .makeSceneTransitionAnimation(this, postImageView,getString(R.string.trans_post_image))

                startActivity(detailIntent, options.toBundle())
            }
        }
    }
    private fun initWriteFloatingButton() {
        writeFloatingButton.setOnClickListener {
            Log.d(TAG, "write button clicked")
            Log.d(TAG, userID)

            //로그인한 회원 ID 전달하며, 글쓰기 화면으로 이동
            val makeNewPostIntent = Intent(this, MakeNewPostActivity::class.java).apply {
                putExtra("userID", userID)
            }
            startActivity(makeNewPostIntent)
        }
    }
}
profile
Be able to be vulnerable, in search of truth
post-custom-banner

0개의 댓글