몰?.루();

안드로이드 scrollView scrollY 제대로 안 먹힐 때 (doOnLayout) 본문

프로그래밍/안드로이드, 코틀린

안드로이드 scrollView scrollY 제대로 안 먹힐 때 (doOnLayout)

toonraon 2023. 2. 27. 22:39

제가 원한 것은 SubActivity를 띄웠을 때 바로 스크롤뷰가 특정 scrollY만큼 이동한 상태에서 화면이 보여지는 것이었습니다.

원했던 그림

버튼을 누르는 순간 서브 레이아웃으로 교체되면서 스크롤뷰가 아래로 내려가야합니다.

 

실패한 코드 1 - onCreate나 onResume에 setScrollY 넣어보기

package com.example.test

import android.os.Bundle
import android.widget.ScrollView
import androidx.appcompat.app.AppCompatActivity

class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)
    }

    override fun onResume() {
        super.onResume()

        val scrollView = findViewById<ScrollView>(R.id.scrollView)
        scrollView.scrollY = 10000
    }
}

onResume에 scrollView.scrollY = 10000을 넣어봤지만 전혀 쓸모 없었습니다.

onResume에 setScrollY를 적은 상태

당연히 onCreate나 onStart에 넣어도 효과가 없었습니다.

실패한 코드 2 - .post 사용하기

package com.example.test

import android.os.Bundle
import android.widget.ScrollView
import androidx.appcompat.app.AppCompatActivity

class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val scrollView = findViewById<ScrollView>(R.id.scrollView)
        scrollView.post { scrollView.scrollY = 10000 }
    }
}

이번엔 스택오버플로우에서 추천한 방식인 scrollView.post { scrollView.scrollY = 10000 } 을 사용하였습니다.

 

post에 setScrollY

멀쩡하게 잘 동작하는 것 같지만 사실 아닙니다.

버튼을 클릭하면 서브 액티비티가 뿅 하고 나타나는 게 아니라 스스륵 올라오는데 이때 자세히 보면 스크롤뷰가 순간적으로 스크롤 위치를 변경하는 게 보입니다.

서브 액티비티가 등장할 때 올라오는 애니메이션을 제거하면 훨씬 더 잘 보입니다.

 

순간적으로 제일 위에 있던 스크롤이 아래로 훅 내려가는 게 눈에 보인다

저는 사용자가 스크롤이 바뀌는 걸 눈치채면 안 되는 상황이었기 때문에 post를 사용하는 방식은 쓸 수 없었습니다.

참고로 View.post는 uithread의 큐에 작업을 추가하는 함수입니다. 따라서 ui 작업이 모두 끝난 후, 제가 코드로 넣은 setScrollY가 발동됩니다. 그렇기 때문에 처음 스크롤뷰가 보일 때부터 스크롤이 최하단으로 내려간 상태에서 시작하는 게 아니라, 스크롤뷰 최상단인 상태에서 uithread가 일을 마치고 나서 스크롤을 아래로 내리기 때문에 이런 현상이 발생했습니다.

성공한 방법 - doOnLayout

사수님에게 물어봤더니 doOnLayout이라는 게 있다고 써보라고 하셨습니다.

package com.example.test

import android.os.Bundle
import android.widget.ScrollView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.doOnLayout

class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val scrollView = findViewById<ScrollView>(R.id.scrollView)
        scrollView.doOnLayout { it.scrollY = 10000 }
    }
}

결과는 대성공이었습니다.

 

doOnLayout에 setScrollY를 사용한 모습

doOnLayout은 처음 들어봤는데 찾아보니까 해당 View가 레이아웃에 놓여지는 순간 작업을 수행하는 콜백함수였습니다.

덕분에 원하는 기능을 구현할 수 있었습니다.

Comments