package com.example.appuiclone
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.appuiclone.databinding.RecyclerviewBinding
// 여기서 리스트의 값들을 비교하는 것이다. 리스트가 업데이트 되었을 때 변경된 부분만 캐치해 낼 수 있다고 한다.
// 전체 리스트와 string 값의 변화를 비교한다.
// 근데 이 친구는 데이터가 하나 뿐이라서 비교하는 걸 두 개 만들 이유가 없지만... ㅋㅋㅋ
class PapagoAdapter (private val onClick: (Item) -> Unit) :
ListAdapter<Item, PapagoAdapter.ViewHolder>(object: DiffUtil.ItemCallBack<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem.string == newItem.string
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
}) {
// 여기는 맨날 똑같다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding =
RecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
// ViewHolder를 생성할 때 Item 객체를 position 위치에 맞는 걸로 가져온다.
// bind로 값을 전달한다.
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item, onClick)
}
inner class ViewHolder(private val binding: RecyclerviewBinding) :
RecyclerView.ViewHolder(binding.root) {
// 아이템 객체인데 거기에 대한 text 설정 및 클릭 리스너 설정. TransportResultAActivity로 가서 onClick 람다함수를 실행한다.
fun bind(item: Item, onClick: (Item) -> Unit) {
binding.tvTransportResultText.text = item.string
itemView.setOnClickListener {
onClick(item)
}
}
}
}
// MainActivity.kt
package com.example.layouttraining
import ImagePagerAdapter
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.layouttraining.databinding.ActivityMainBinding
import com.google.android.material.tabs.TabLayoutMediator
class MainActivity : AppCompatActivity() {
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
// TabLayout에 들어갈 텍스트들
private val tabTitles = listOf(R.string.tab1, R.string.tab2, R.string.tab3)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
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
}
// ViewPagerAdapter랑 연결한 후
// TabLayout 만든 것이랑 그 ViewPager를 연결하면 된다.
// tab.text는 Tab Layout에 들어갈 텍스트들을 차례로 넣어주는 것이다.
with(binding) {
viewPager.adapter = ViewPagerAdapter(this@MainActivity)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = getString(tabTitles[position])
}.attach()
}
}
}
ViewPagerAdapter
package com.example.layouttraining
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// 총 들어갈 TabeLayout 텍스트 개수는 3개
// 각각의 TabLayout 숫자에 따라 보여줄 Fragment를 나누어서 관리
class ViewPagerAdapter(activity: AppCompatActivity) : FragmentStateAdapter(activity) {
override fun getItemCount() = 3
override fun createFragment(position: Int) = when (position) {
0 -> HomeFragment()
1 -> SearchFragment()
2 -> SettingFragment()
else -> throw IllegalStateException("Invalid position: $position")
}
}
activity_main.xml
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#FFEB3B"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tab_layout"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
// TabLayout과 ViewPager를 여기서 정의 해준다. 그리고 Fragment를 각각 만들어서 ViewPager 안에 넣어주는 것이다.
주의!
// 맨 처음 Activity에서
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
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
}
/*
보면 여러 가지 설정이 있는데 setContentView 밑의 코드는 지워야 한다.
안 그러면 NavigationView 밑에 여백이 뜬다.. ㅠㅠ
이거 가지고 한참 헤매다 지우고 나서 실행하니 정상적으로 되었다.. ㅠㅠ */
package com.example.layouttraining
import android.os.Bundle
import android.text.TextUtils.replace
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import com.example.layouttraining.databinding.ActivitySecondBinding
class SecondActivity : AppCompatActivity() {
private lateinit var binding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivitySecondBinding.inflate(layoutInflater)
setContentView(binding.root)
// bottomNavigation의 아이템을 다른 xml로 정의하고
// 아이템의 아이디에 따라 각각 다른 Fragment를 띄우는 것이다.
binding.bottomNavigation.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.test1 -> {
HomeFragment().loadFragment()
true
}
R.id.test2 -> {
SearchFragment().loadFragment()
true
}
R.id.test3 -> {
SettingFragment().loadFragment()
true
}
else -> false
}
}
}
private fun Fragment.loadFragment() {
supportFragmentManager.commit {
replace(R.id.fragment_container, this@loadFragment)
setReorderingAllowed(true)
addToBackStack(null)
}
}
}
// 여기서 각각의 bottomNavigation의 아이템들을 정의하면 된다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/test1"
android:title="test1" />
<item android:id="@+id/test2"
android:title="test2"/>
<item android:id="@+id/test3"
android:title="test3"/>
</menu>