* 본 예제는 간단히 ViewBinding을 사용합니다
https://greensky0026.tistory.com/190
개요
본 예저는 간단히 fragment를 버튼을 클릭해 swap해 보여주는 Application 입니다.
MainActivity는 main, another 버튼이 존재하며 클릭시 해당 fragment를 swap해 보여줍니다.
구성
MainActivity.kt
activity_main.mxl
MainHomeFragment.kt
fragment_main_home.xml
MainAnotherFragment.kt
fragment_main_another.xml
1. MainActivity.kt
변수 선언
val b by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
private val fragmentManager by lazy {
supportFragmentManager
}
private val homeFragment by lazy {
MainHomeFragment()
}
private val anotherFragment by lazy {
MainAnotherFragment()
}
private lateinit var transaction: FragmentTransaction
private var nowFragment: Fragment? = null
by lazy를 사용해 val 변수들을 호출시에 초기화 해주두록 세팅했습니다.
fragmentManager와 각 fragment들을 var변수로 선언했습니다.
transaction은 프레그먼트를 추가, 제거 및 교체를 할 수 있습니다. 자세한 사항은 여기를 참조하세요.
여기서는 단순 교체작업용 만으로 사용합니다.
nowFragment는 현재 보여지고 있는 fragment로 교채를 요청했을 때, 이벤트 발생을 위해 선언했습니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(b.root)
replaceTransaction(homeFragment)
b.btnPresentMainFragment.setOnClickListener {
replaceTransaction(homeFragment)
}
b.btnPresentAnotherFragment.setOnClickListener {
replaceTransaction(anotherFragment)
}
}
버튼을 세팅하고, replaceTransaction 함수를 homeFragment를 매개변수로 넣어서 호출햇습니다.
이름에서 보듯이 해당 함수는 fragment를 swap해주는 함수입니다.
private fun replaceTransaction(fragment: Fragment){
if(nowFragment == fragment){
Toast.makeText(this, "이미 해당 Fragment를 보여주고 있습니다.", Toast.LENGTH_SHORT).show()
return
}
transaction = fragmentManager.beginTransaction()
transaction.replace(b.flFlagmentContainer.id, fragment).commitAllowingStateLoss()
nowFragment = fragment
}
교체시 nowFragment에 현재 fragment를 확인해 같은 프래그먼트라면 교체작업을 진행하지 않고 토스트로 명시 후 작업을 종료합니다.
교체시엔 beginTransaction()호출 후 작업을 명시한 후에 commitAllowingStateLoss를 호출하면 됩니다.
트랜젝션을 시작 후 커밋해야 하다니, 약간은 db 명령어 같죠? ㅎㅎ
교체또한 replace에 fragment를 담을 container view와 framgent객채만 입력해주면 됩니다.
2. activity_main.mxl
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal">
<View
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="0dp"/>
<Button
android:id="@+id/btn_present_main_fragment"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="main"/>
<Button
android:id="@+id/btn_present_another_fragment"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="another"/>
<View
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="0dp"/>
</LinearLayout>
<FrameLayout
android:id="@+id/fl_flagment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
간단히 버튼 두개와 프래그먼트를 출력할 FramLayout으로 구성되어 잇습니다.
3. MainHomeFragment.kt
private var _binding: FragmentMainHomeBinding? = null
private val binding get() = _binding!!
우선은 변수선언부터 해줍니다. view binding을 할 것이므로 초기화 해 주고,
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMainHomeBinding.inflate(inflater, container, false)
return binding.root
}
onCreateView로 view를 그리기 전, 그릴 bingding 객체를 inflate하여 _binding에 저장하고 반환합니다.
override fun onDestroy() {
super.onDestroy()
_binding = null
}
위와같이 작업한다면, 메모리 누수를 방지하기 위해 onDestroy에 꼭!!! _binding을 초기화 해주어야 합니다.
이런 일련의 작업이 불편하다면, androidx.lifecycle을 사용해 편하게 작성할 수 잇습니다. 여기를 참고하세요.
4. fragment_main_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainHomeFragment"
android:background="#FFEFEF">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home Flagment"
android:textSize="40dp"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment를 구분하기 위해 배경색과 text를 입력해뒀습니다.
MainAnotherFragment.kt와 fragment_main_another.xml도 같은 형식이니 생략하겠습니다.
궁금하시다면 아래 전체 코드보기로 봐주세요 ㅎㅎ
결과
전체 코드 보기
https://github.com/gr2nsky/FlagmentPactice
MainActivity
class MainActivity : AppCompatActivity() {
val b by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
private val fragmentManager by lazy {
supportFragmentManager
}
private val homeFragment by lazy {
MainHomeFragment()
}
private val anotherFragment by lazy {
MainAnotherFragment()
}
private lateinit var transaction: FragmentTransaction
private var nowFragment: Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(b.root)
replaceTransaction(homeFragment)
b.btnPresentMainFragment.setOnClickListener {
replaceTransaction(homeFragment)
}
b.btnPresentAnotherFragment.setOnClickListener {
replaceTransaction(anotherFragment)
}
}
private fun replaceTransaction(fragment: Fragment){
if(nowFragment == fragment){
Toast.makeText(this, "이미 해당 Fragment를 보여주고 있습니다.", Toast.LENGTH_SHORT).show()
return
}
transaction = fragmentManager.beginTransaction()
transaction.replace(b.flFlagmentContainer.id, fragment).commitAllowingStateLoss()
nowFragment = fragment
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal">
<View
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="0dp"/>
<Button
android:id="@+id/btn_present_main_fragment"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="main"/>
<Button
android:id="@+id/btn_present_another_fragment"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="another"/>
<View
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="0dp"/>
</LinearLayout>
<FrameLayout
android:id="@+id/fl_flagment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
MainHomeFragment
class MainHomeFragment : Fragment() {
private var _binding: FragmentMainHomeBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMainHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainHomeFragment"
android:background="#FFEFEF">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home Flagment"
android:textSize="40dp"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainAnotherFragment
class MainAnotherFragment : Fragment() {
private var _binding: FragmentMainAnotherBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMainAnotherBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainAnotherFragment"
android:background="#EFF2FF">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Another Flagment"
android:textSize="40dp"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
'IDE & Framework > Android' 카테고리의 다른 글
[Kotlin] InCallService로 Default Dialer 개발하기 (4) | 2021.12.19 |
---|---|
[Kotlin]ActivityForResult 및 checkSelfPerission 을 permissionLauncher로 대체하기 (0) | 2021.12.19 |
[Kotlin] Fragment (1) - Introduce (0) | 2021.12.12 |
[Kotlin] WorkManager 사용해보기 (0) | 2021.11.09 |
[Kotiln] 실행아이콘이 없는, 런처가 없는 앱 만들기 (0) | 2021.11.02 |