class OneFragment: Fragment() {
// ...
}
<fragment
android:name="com.example.OneFragment"
android:id="@+id/fragmentView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
val fragmentManager: FragmentManager = supportFragmentManager
val transaction: FragmentTransaction = fragmentManager.beginTransaction()
transaction.add(R.id.fragment_content, oneFragment)
transaction.commit()
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".OneFragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="20sp"
android:text="I am OneFragment" />
</LinearLayout>
package com.tutorial.c91
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class OneFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_one, container, false)
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/oneButton"
android:text="one"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/twoButton"
android:text="two"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
package com.tutorial.c91
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tutorial.c91.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val oneFragment = OneFragment()
val twoFragment = TwoFragment()
val manager = supportFragmentManager
val transaction = manager.beginTransaction()
transaction.add(R.id.fragment_container, oneFragment)
transaction.commit() // 이때 화면에 프래그먼트가 출력되면서, 트랜잭션 객체는 닫히게 됨.
binding.oneButton.setOnClickListener {
val tran = manager.beginTransaction() // 따라서, 다시 얻어줘야 함.
tran.replace(R.id.fragment_container, oneFragment)
tran.commit()
}
binding.twoButton.setOnClickListener {
val tran = manager.beginTransaction()
tran.replace(R.id.fragment_container, twoFragment)
tran.commit()
}
}
}
목록의 한 항목 구성하려면 여러 개의 뷰가 필요하다. 이러한 뷰 객체들을 갖고 있는 게 뷰 홀더
의 역할이다. 그리고 어댑터
에 의해 뷰에 데이터를 출력하며, 이러한 항목들은 레이아웃 매니저
에 의해 배치되어 리사이클러뷰가 완성된다.
class MyViewHolder(val binding: ItemMainBinding): RecyclerView.ViewHolder(binding.root)
class MyAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun getItemCount(): Int {
TODO("Not yet implemented")
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
TODO("Not yet implemented")
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
TODO("Not yet implemented")
}
}
binding.recycler.layoutManager = LinearLayoutManager(this)
binding.recycler.adapter = MyAdapter(datas)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/item_img"
android:src="@drawable/ic_launcher_background"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/item_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="16dp"/>
</LinearLayout>
package com.tutorial.c92
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.tutorial.c92.databinding.ItemMainBinding
class MyViewHolder(val binding: ItemMainBinding): RecyclerView.ViewHolder(binding.root)
class MyAdapter(val datas: List<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int {
return datas.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(ItemMainBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val binding = (holder as MyViewHolder).binding
binding.itemTitle.text = datas[position]
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
package com.tutorial.c92
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.tutorial.c92.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val datas = mutableListOf<String>()
for(i in 1..10){
datas.add("item $i")
}
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = MyAdapter(datas)
binding.recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
}
}
참고: 카드를 사용하여 이미지 목록 표시하는 방법 (코드랩)
implementation 'androidx.viewpager2:viewpager2:1.0.0'
<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
class MyPagerViewHolder(val binding: ItemPagerBinding): RecyclerView.ViewHolder(binding.root)
class MyPagerAdapter(val datas: MutableList<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun getItemCount(): Int{
return datas.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
= MyPagerViewHolder(ItemPagerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
// ...
}
}
class MyFragmentPagerAdapter(activity: FragmentActivity): FragmentStateAdapter(activity){
val fragments: List<Fragment>
init {
fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
Log.d("kkang" ,"fragments size : ${fragments.size}")
}
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
binding.viewpager.orientation = ViewPager2.ORIENTATION_VERTICAL
implementation 'androidx.viewpager2:viewpager2:1.0.0'
package com.tutorial.c93
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
class MyAdapter(activity: FragmentActivity): FragmentStateAdapter(activity) {
val fragments: List<Fragment> = listOf(OneFragment(), TwoFragment(), ThreeFragment())
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
package com.tutorial.c93
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tutorial.c93.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.viewpager.adapter = MyAdapter(this)
}
}
위의 그림을 보면 액션바는 컨텐츠 영역과 구분되어 있지만, 툴바는 컨텐츠 영역에 포함된다. 따라서, 툴바는 우리가 직접 구현하는 레이아웃 xml 파일에 포함되는 뷰이다.
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Toolbar.Primary"/>
setSupportActionBar(binding.toolbar)
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.AndroidLab" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu1"
android:title="menu1"/>
<item
android:id="@+id/menu2"
android:title="menu2"
android:icon="@android:drawable/ic_menu_add"
app:showAsAction="always"/>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Toolbar.Primary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"/>
</LinearLayout>
package com.tutorial.c94
import android.os.Bundle
import android.view.Menu
import androidx.appcompat.app.AppCompatActivity
import com.tutorial.c94.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return super.onCreateOptionsMenu(menu)
}
}
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:text="extended FAB"
app:icon="@android:drawable/ic_input_add"/>
binding.fab.setOnClickListener {
when(binding.fab.isExtended){
true -> binding.fab.shrink()
false -> binding.fab.extend()
}
}
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:text="extended FAB"
app:icon="@android:drawable/ic_input_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.tutorial.c95
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tutorial.c95.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.fab.setOnClickListener {
when(binding.fab.isExtended){
true -> binding.fab.shrink()
false -> binding.fab.extend()
}
}
}
}
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout .................. >
<!-- ............. -->
</LinearLayout>
<TextView
android:layout_gravity="start"/>
</androidx.drawerlayout.widget.DrawerLayout>
toggle = ActionBarDrawerToggle(this, binding.drawer, R.string.drawer_opened, R.string.drawer_closed)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toggle.syncState() // 토글 버튼 클릭과 스와이프 동작에 대한 싱크 맞추기
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(toggle.onOptionsItemSelected(item)){ // 토글 버튼을 클릭하는 경우 메뉴 이벤트로 처리
return true
}
return super.onOptionsItemSelected(item)
}
<com.google.android.material.navigation.NavigationView
android:id="@+id/main_drawer_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/menu_navigation"/>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:text="I am header"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="#ffffff"
android:background="#ff0000"
android:gravity="left|bottom"
android:paddingBottom="32dp"
android:paddingLeft="32dp"
android:layout_height="200dp">
</TextView>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu1"
android:title="menu1"
android:icon="@android:drawable/ic_input_add"/>
<item
android:id="@+id/menu2"
android:title="menu2"
android:icon="@android:drawable/ic_menu_search"/>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="20sp"
android:textStyle="bold"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:menu="@menu/menu_nav">
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
<resources>
<string name="app_name">c96</string>
<string name="open">open drawer</string>
<string name="close">close drawer</string>
</resources>
package com.tutorial.c96
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import com.tutorial.c96.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
lateinit var toggle: ActionBarDrawerToggle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
toggle = ActionBarDrawerToggle(this, binding.drawer, R.string.open, R.string.close)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toggle.syncState() // 토글 버튼 클릭과 스와이프 동작에 대한 싱크 맞추기
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
}
토글 버튼 클릭이나 스와이프 동작을 통해 네비게이션 뷰를 꺼내거나 숨길 수 있다.