[Kotlin] 스크롤 시 배경 이미지 점점 사라지게 하기

park_sujeong·2022년 8월 19일
0

Android

목록 보기
4/13
post-thumbnail

오늘은 화면 스크롤 시 배경이미지를 점점 투명하게 만드는 것을 해볼것이다. 이번에 앱을 만들때 필요했는데 Kotlin 자료가 많이 없어서 Java로 작성된 블로그를 참고했다. 우선 애니메이션으로 할 수 있겠지만 여기서는 스크롤이벤트를 이용할 것이다.

결과물





구현 방법

나는 ScrollView를 커스텀할것이다. 우선 아래 레이아웃을 보면 위에 사라지게 만들 top_image가 있고 그 아래에 "안녕하세요."를 입력받은 TextView가 있다. TextView 아래에는 스크롤을 하기위해 높이가 있는 것으로 채운것이므로 신경쓰지않아도 된다.


자, 그럼 이제 구현해보자!

CustomScrollView.kt

우선, 제일 중요한 ScrollView를 커스텀해보자. 스크롤이 변경될때 이벤트 리스너를 추가하여 Activity나 Fragment단에서 처리할 수 있게 했다.

package com.crystal.customs

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.widget.ScrollView

class CustomScrollView: ScrollView {

    var SCROLL_UP = 0
    var SCROLL_DOWN = 1

    private var onScrollListener: OnScrollListener? = null

    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attr: AttributeSet?) : this(context, attr, 0)
    constructor(context: Context, attr: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attr,
        defStyleAttr
    )

    override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
        super.onScrollChanged(l, t, oldl, oldt)

        val direction = if (oldt > t) SCROLL_DOWN else SCROLL_UP

        onScrollListener?.onScroll(direction, t.toFloat())

    }

    fun setOnScrollListener(listener: OnScrollListener) {
        onScrollListener = listener
    }


    interface OnScrollListener {
        fun onScroll(direction: Int, scrollY: Float)
    }


}



fragment_home.xml

fragment의 layout이다. 보면 layout 바로 아래의 ConstraintLayout의 ImageView가 우리의 배경화면이다.그리고 배경화면과 우리가 만든 스크롤뷰의 부분이 겹치게 둔다. 이건 취향껏 하자.

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

    <ImageView
        android:id="@+id/top_image"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="@string/description_home_image"
        android:scaleType="fitXY"
        android:src="@drawable/night_sky"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="0dp" />

    <com.crystal.customs.CustomScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_height="0dp">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:padding="10dp"
            android:layout_marginTop="300dp"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/greetings_text_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="22sp"
                android:text="안녕하세요."
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toStartOf="parent" />

            <ImageView
                android:id="@+id/imageview1"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/greetings_text_view" />

            <ImageView
                android:id="@+id/imageview2"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/imageview1"
                tools:layout_editor_absoluteX="0dp" />

            <ImageView
                android:id="@+id/imageview3"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/imageview2" />

            <ImageView
                android:id="@+id/imageview4"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/imageview3" />

            <ImageView
                android:id="@+id/imageview5"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/imageview4" />

            <ImageView
                android:id="@+id/imageview6"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                app:layout_constraintTop_toBottomOf="@+id/imageview5" />


        </androidx.constraintlayout.widget.ConstraintLayout>


    </com.crystal.customs.CustomScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>





HomeFragment.kt

package com.crystal.fragments

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.crystal.R
import com.crystal.customs.CustomScrollView
import com.crystal.databinding.FragmentHomeBinding

private const val TAG = "HomeFragment"
class HomeFragment : Fragment() {

    private lateinit var binding: FragmentHomeBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)

        return binding.root

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setupEvents()
        scrollEvent()
    }

    private fun setupEvents() {

    }

    private fun scrollEvent() {

        binding.scrollView.overScrollMode = View.OVER_SCROLL_NEVER

        // ScrollView에서 받는 이벤트 처리
        // 1: 완전 불투명
        // 스크롤 위치에 따라 alpha 값이 변경되므로, 방향은 상관이 없다.
        binding.scrollView.setOnScrollListener(object : CustomScrollView.OnScrollListener {
            override fun onScroll(direction: Int, scrollY: Float) {

        	// statusBar 높이 구하기
        	var statusBarHeight = 0
        	val resId = resources.getIdentifier("status_bar_height", "dimen", "android")
        	if (resId > 0) {
            	statusBarHeight = resources.getDimensionPixelSize(resId)
        	}

			// top_image 높이 구하기, 나는 끝까지 안올리고 100% 불투명도 만들기위해 statusbar 높이를 뺐다.
        	val backgroundImgHeight = binding.topImage.height - statusBarHeight

        	val alpha = ((backgroundImgHeight - scrollY) / backgroundImgHeight)

        	binding.topImage.alpha = alpha


            }

        })
    }

}





난 위에 일부분을 배경이미지로 뒀지만 화면 전체를 배경이미지로 두고 전체 스크롤 시 최상단에서 최하단까지 투명도를 원하는 사람도 있을거라 생각한다. 그럼 내가 참고한 아래 링크로 가면 된다. 나도 저기 링크를 커스텀했다!

https://bbulog.tistory.com/29





참고

profile
Android Developer

0개의 댓글