연습장/실습

6주차_ Kakao API 활용 앱 1. ViewPager/TabLayout

아이른 2024. 5. 3. 16:33

1. ViewPager

  • 페이지를 넘기듯 화면 슬라이드에 자동으로 애니메이션이 적용되어 페이지가 전환
  • ViewPager > ViewPager2 라이브러리 사용 권장
  • build.gradle 설정
dependencies {
    //viewpager2
    implementation("androidx.viewpager2:viewpager2:1.0.0")
}

 

2. TabLayout 

  • 화면 전환 시, 해당 화면에 따라 Tap을 표시하는 레이아웃 

 

3. ViewPager/TabLayout  사용법

커서를 원하는 방향으로 끌면 화면 전환

 

3-1. fragment_main.xml에서 ViewPager2/TapLayout을 사용할 경우

① fragment_main.xml

 

② MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    //뷰바인딩 설정
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        enableEdgeToEdge()
        setContentView(binding.root)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        setFragment()
        //프래그먼트 호출
    }

    private fun setFragment() {
        supportFragmentManager
            .beginTransaction()
            .replace(binding.frameLayout.id, MainFragment())
            .addToBackStack("")
            .commit()
    }
}

 

ViewPagerAdapter.kt

  • ViewPager2가 제공하는 FragmentStateAdapter을 상속 받는 ViewPagerAdapter 생성
    • activity_main.xml에서 ViewPager2을 사용 : FragmentActivity
      • 하나의 Activity안에 다른 Activity를 넣고 싶다면 Fragment를 상속받는 Activity여야하기 때문
    • fragment_main.xml에서 ViewPager2을 사용 : Fragment
  • FragmentStateAdapter 오버라이딩 메서드
    • getItemCount : 페이지 개수 반환
    • createFragment : position에 연결된 프래그먼트 생성 후 반환
class ViewPagerAdapter(fragment: Fragment): FragmentStateAdapter(fragment) {

    val fragments = listOf<Fragment>(RecyclerViewFragment(),DetailFragment())
    /*
    ViewPager에 노출시킬 Fragment 나열 
    MainFragment는 ViewPager을 담는 HostActivity가 되기 때문에 넣으면 안됨
    (넣으면 무한루트로 생성되다 앱 꺼짐)
    */
    
    override fun getItemCount(): Int {
        return fragments.size
    }

    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }
}

 

④ MainFragment.kt

class MainFragment : Fragment() {

    private var _binding: FragmentMainBinding? = null
    private val binding: FragmentMainBinding
        get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentMainBinding.inflate(inflater, container, false)
        
        //ViewPager 연결
        val viewPagerAdapter = ViewPagerAdapter(this)
        binding.viewPager.adapter = viewPagerAdapter
        
        //TapLayout 연결 및 커스텀
        TabLayoutMediator(binding.tabLayout, binding.viewPager) { tap, position ->
            when (position) {
                0 -> {
                    tap.setIcon(R.drawable.tap1)
                    tap.text = "이미지 검색"
                }
                1 -> {
                    tap.setIcon(R.drawable.tap2)
                    tap.text = "내 보관함"
                }
            }
        }.attach()
        return binding.root
    }

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

 

3-2. activity_main.xml에서 ViewPager2/TapLayout을 사용할 경우

① activity_main.xml

 

② MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        enableEdgeToEdge()
        setContentView(binding.root)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        
        initViewPager()
        
    }

    private fun initViewPager() {
        val viewPagerAdapter = ViewPagerAdapter(this)
        binding.viewPager.adapter = viewPagerAdapter
        TabLayoutMediator(binding.tabLayout, binding.viewPager) { tap, position ->
            when (position) {
                0 -> {
                    tap.setIcon(R.drawable.tap1)
                    tap.text = "이미지 검색"
                }

                1 -> {
                    tap.setIcon(R.drawable.tap2)
                    tap.text = "내 보관함"
                }
            }
        }.attach()
    }
}

 

② ViewPagerAdapter.kt

class ViewPagerAdapter(fragmentActivity: FragmentActivity): FragmentStateAdapter(fragmentActivity) {

    val fragments = listOf<Fragment>(MainFragment(), DetailFragment())
    override fun getItemCount(): Int {
        return fragments.size
    }
    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }
}