Android – 프래그먼트를 이용해서 슬라이딩 탭뷰를 만들어 보자! with. 코틀린

슬라이딩 탭뷰는 화면을 좌우로 넘기며 탭이 바뀌는 탭뷰를 말합니다.
정식 명칭은 아니고 필자가 지어낸 것입니다.

넘기기 기능을 위해서 ViewPager라는 컴포넌트가 필요합니다.
이 위젯은 여러 페이지를 아이템으로 담고 화면에 나타냅니다.
현재 아이템이 (페이지1)이라면 화면에는 (페이지1)이 나타납니다.
또한, 사용자가 화면을 오른쪽으로 넘기면 (페이지2)가 나타납니다.

여기서 페이지는 프래그먼트에 해당됩니다.
프래그먼트는 임시 액티비티, 서브 액티비티의 개념으로
여러 화면을 메모리 적게 사용하여 만들기에 용이합니다!
프래그먼트를 만들 때는 file->new->Fragment를 하면 됩니다.

이 프래그먼트도 생명주기가 있습니다.
newInstance로 생성됨 -> onCreate -> onCreateView -> onViewCreated
만 일단 알아둡시다!

프래그먼트는 inflate를 통해 xml파일을 가져오는데 onCreateView에 이 소스가 위치하니,
프래그먼트 xml의 컴포넌트를 수정하기 위해서는 onViewCreated에 코딩해야 됩니다.

이 정도만 일단 설명하고 소스를 살펴 봅시다!

MainActivity.kt

package com.example.tab_app
import android.os.Bundle
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import com.example.tab_app.ui.main.PagerAdapter
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 어댑터 생성 <어댑터는 여러 프래그먼트를 만들고 관리함>
        val Adapter = PagerAdapter(supportFragmentManager)
        // 뷰 페이저에 어댑터 연결
        view_pager.adapter = Adapter
        view_pager.currentItem=0
        // 탭 레아아웃에 뷰페이저 연결
        tabs.setupWithViewPager(view_pager)
        // 탭뷰 각각 이름 만들기
        val feel=arrayOf("Funny","Happy","Sad")
        for(i in 0..2)
            tabs.getTabAt(i)?.setText(feel[i])
    }
}

먼저 어댑터가 인스턴스화되면 생성자에서 프래그먼트들을 만듭니다.
supportFragmentManager라는 매니저 객체를 인수로 보내야 합니다!

또한, 어댑터에서는 Items리스트가 (생성한 프래그먼트)를 요소로 가집니다.

어댑터 객체를 만든 후 view_pager.adapter = Adapter를 통해 뷰페이저에 어댑터를 연결합니다. 이로써 뷰페이저는 어댑터 Items를 마음대로 사용할 수 있습니다. 예를 들어 view_pager.currentItem을 출력하면 Items요소 개수가 출력됩니다. 이 Items을 가지고 화면에 나타내는건 뷰 페이저가 알아서 해줍니다.

이후 탭 레이아웃에 뷰 페이저를 연결해야 합니다. setupwithViewPager()가 쓰입니다.
연결이 되면, 뷰 페이저가 가진 페이지 개수만큼 탭이 늘어나고
현재 아이템(페이지)이 바뀌면 탭도 따라 바뀝니다!

탭들이 만들어지면 setText를 통해 탭들 이름을 바꾸면 되겠습니다!

PagerAdapter.kt

package com.example.tab_app.ui.main
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.fragment.app.FragmentStatePagerAdapter
import com.example.tab_app.R
class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
    // 프래그먼트 담는 리스트
    private val items= ArrayList<Fragment>()
    init{
    // 프래그먼트 생성 후 리스트에 저장
        items.add(Page1Fragment.newInstance(1))
        items.add(Page2Fragment.newInstance(2))
        items.add(Page3Fragment.newInstance(3))
    }
    override fun getItem(position: Int): Fragment {
        return items[position]
    }
    override fun getCount(): Int {
        return items.size
    }
}

앞에서 설명한대로 생성자에서 프래그먼트를 만듭니다. 프래그먼트를 만들 때는 newInstance()를 이용합니다.
newInstance()는 만든 프래그먼트 객체를 반환하고, 어댑터에서는 받은 객체를 items에 넣는 방식입니다.

필자는 탭을 3개 만들었고 이에 맞춰 프래그먼트 파일도 세 개 만들었습니다.
그래서 newInstance를 세 번 한 것입니다.

getItem과 getCount같은 경우, 뷰 페이저에서 아이템을 가져가기 편하게 위처럼 소스를 짜면 됩니다.

get 메소드는 ViewPager가 알아서 호출하니 사용자가 직접 호출할 필요는 없습니다.

Page1Fragment.kt

package com.example.tab_app.ui.main
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.tab_app.R
import kotlinx.android.synthetic.main.fragment_main.*
class Page1Fragment : Fragment() {
    // 뷰 생성 <onCreate다음에 호출됨>
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_main, container, false)
        return root
    }
    // 뷰 생성이 완료되면 호출되는 메소드
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        section_label.text=arguments?.let{
            it.getInt(num).toString()
        }
         imageView.setImageResource(R.drawable.funny)
    }
    companion object {
        private const val num = "num"
        @JvmStatic
        fun newInstance(Number: Int): Page1Fragment {
            return Page1Fragment().apply {
                arguments = Bundle().apply {
                    putInt(num, Number)
                }
            }
        }
    }
}

마지막으로 프래그먼트 파일입니다. 이 파일을 새로 만들 때는 위 소스랑 사뭇 다릅니다. 소스가 너무 깔끔하지 않아 필자가 위처럼 수정하였습니다.

Companion블럭부터 보면 되겠습니다. num전역변수를 만들었는데 이 변수는 arguments라고 하는 컬렉션에서 key로 작용합니다. arguments는 컬렉션 중 map과 비슷한데, map은 요소를 ‘키’와 ‘밸류’로 저장합니다. putInt(키,밸류)로 저장하면 getInt(키)메소드로 밸류를 가져올 수 있습니다!

newInstance메소드에서
Page1Fragment().apply를 리턴한다는 것은, Page1Fragment를 인스턴스화하고 이 객체를 보낸다고 생각하면 됩니다.

onCreateView를 살펴 봅시다. 프래그먼트가 뷰를 만드는 메소드입니다. 이 때 inflate를 통해서 프래그먼트와 같이 만들어진 xml을 매핑하면 됩니다.

onViewCreated는 뷰 생성이 완료되면 호출되는 메소드입니다. 여기서 사용자가 원하는 위젯을 수정할 수도 있고,어댑터에서 넘어 온 변수도 arguments를 통해 활용할 수 있습니다.

사실 이 파일은 안드로이드 스튜디오에서 만들어 준 것이니 그냥 소스만 조금 수정하여 활용하면 됩니다.

이번 탭뷰 레퍼런스는 파일로 제공합니다!

Leave a Reply

Your email address will not be published. Required fields are marked *