본문 바로가기
개발

TIL : 맨 위로 가기 버튼 만들기(floating button)

by kks950115 2024. 1. 11.
728x90

맨 위에 있으면 fade out 효과가 적용되면서 버튼이 사라지고 맨 위가 아니면 fade in이 적용되면서 버튼이 나타나는 것을 구현하는 기능을 구현하라는 선택과제 주어졌다. 사실 안해도 상관없지만 나의 도전욕구를 자극해서 해보았다.

 

 

위에 사진처럼 나오게 하며 되는데... 여느 앱을 들여다보면 다 있는 정말 일반적인 기능이다.

 

 

코드

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">    
    
    //.....
    
    <ImageView
        android:id="@+id/btn_floating"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginEnd="15dp"
        android:layout_marginBottom="15dp"
        android:background="@drawable/btn_floating"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

xml을 만들고...

 

private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    private lateinit var fadeInAnim :Animation
    private lateinit var fadeOutAnim :Animation
//....

fadeInAnim = AnimationUtils.loadAnimation(this, R.anim.fade_in)
        fadeOutAnim = AnimationUtils.loadAnimation(this, R.anim.fade_out)

        var aniCheck = true
        binding.rvMainList.addOnScrollListener(object : RecyclerView.OnScrollListener(){
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)

                //Log.d("test","recyclerView.Y : ${recyclerView.computeVerticalScrollOffset()} ")
                if(recyclerView.computeVerticalScrollOffset() < 5){ //스크롤 위치 인식
                    aniCheck = true
                    binding.btnFloating.startAnimation(fadeOutAnim)

                } else if(aniCheck) {
                    binding.btnFloating.startAnimation(fadeInAnim)
                    aniCheck = false

                }
            }

        })

        binding.btnFloating.setOnClickListener {
            binding.rvMainList.smoothScrollToPosition(0) // 스크롤 맨 위로 올리기
        }

 

액티비티를 만들고...

 

res/anim/ 안에다가 애니메이션을 만들고...

fade_in.xml

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    android:fillAfter="true"
    android:duration="1000" />

fade.out.xml

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="1.0"   //처음 시작 불투명도 1.0은 불투명
    android:toAlpha="0.0"	  //결과 불투명도 0.0은 완전 투명
    android:fillAfter="true" //true로 하면 애니메이션의 결과를 적용시킴
    android:duration="1000"   //애니메이션이 진행되는 시간. 숫자가 작을수록 빠르게 진행됨
    />

 

 

어려웠던 점

1.성능이슈

처음에 애니메이션타입의  fade변수 하나로 fadein , fadeout 을 그 때 그때 상황에 따라 넣어서 쓸려고 했었다. 그러다보니 애니메이션 초기화를 onScrolled 안에다가 하는 바람에 엄청난 성능저하를 겪었었다. 

계속 모르고 있다가 chatgpt에 코드를 올려보니 알려주더라. 참으로 멍청한 실수가 아닐 수 없지만 본인은 계속 모르고 있었다.... 

결국 onscrolled 바깥으로 뺴고 애니메이션을 2개로 나눴다.

 

2.애니메이션 적용 문제

if else 문으로 만들고 제대로 적용이 되는걸 보니 끝난 줄 알았는데 최상단이 아닌 아래에서 스크롤을 조금씩 위로 아래로 움직이니까 스크롤이 사라졌다가 나타났다가를 반복했다. 가이드에 따르면 버튼은 최상단이 아닌한 사라지면 안되는데 말이다.

결국 check라는 변수를 만들어서 사라지지 않게 만들었다.

 

3. 최상단 인식 문제

테스트하면서 에뮬레이터로 이리저리 움직이다보니 버튼이 사라졌다가 나오는 게 빈번했다. 분명 맨 위에 있으면 사라져야하는데 왜 나오는거지? 했는데 관성같은 게 적용되는 거 같았다. 그래서 scrolloffset을 0이 아니라 조금 여유롭게 5로 했더니 좀 더  편하게 쓸 수 있었다.

728x90
반응형

댓글