반응형
Fragment
설명
- Activity의 화면을 여러 영역으로 나누어 관리하고자 하는 목적으로 사용
코드
res/layout/fragment_first.xml<?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="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/submitButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="submit" />
</LinearLayout>
FirstFragment
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val mainActivity = activity as MainActivity
val view = inflater.inflate(R.layout.fragment_first, container, false)
val editText = view.findViewById<EditText>(R.id.editText)
val submitButton = view.findViewById<Button>(R.id.submitButton)
submitButton.setOnClickListener {
mainActivity.text = editText.text.toString()
mainActivity.setFragment("second")
}
return view
}
}
res/layout/fragment_second.xml
<?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="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/displayTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<Button
android:id="@+id/backButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="back" />
</LinearLayout>
SecondFragment
class SecondFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val mainActivity = activity as MainActivity
val view = inflater.inflate(R.layout.fragment_second, container, false)
val displayTextView = view.findViewById<TextView>(R.id.displayTextView)
val backButton = view.findViewById<Button>(R.id.backButton)
displayTextView.text = mainActivity.text
backButton.setOnClickListener {
mainActivity.supportFragmentManager.popBackStack()
}
return view
}
}
res/layout/activity_main.xml
<?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="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private val first = FirstFragment()
private val second = SecondFragment()
var text: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setFragment("first")
}
fun setFragment(name: String) {
val transaction = supportFragmentManager.beginTransaction()
// transaction.add(R.id.frameLayout, first) // 여러 fragment가 겹쳐 보이도록 설정
when (name) {
"first" -> {
transaction.replace(R.id.frameLayout, first) // 한 fragment만 보이도록 설정
}
"second" -> {
transaction.replace(R.id.frameLayout, second)
transaction.addToBackStack(null) // back button 터치시 이전 화면으로 이동
}
}
transaction.commit()
// transaction 반영은 비동기적으로 처리되기 때문에
// 처리 완료 대기를 위해서는 executePendingTransactions() 메소드를 호출해야 한다.
// 아래는 transaction 반영 완료 이후의 fragment를 출력하는 코드
if (supportFragmentManager.executePendingTransactions()) {
val fragment = supportFragmentManager.findFragmentById(R.id.frameLayout)
Log.d("TEST", fragment.toString())
}
}
}
참고
Fragment Animation
설명
- Fragment 변경시 Animation 효과 적용이 가능하다.
예제
res/animator/slide_up.xml<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:propertyName="translationY"
android:valueFrom="1280"
android:valueTo="0"
android:valueType="floatType" />
res/animator/slid_down.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:propertyName="translationY"
android:valueFrom="0"
android:valueTo="1280"
android:valueType="floatType" />
DefaultFragment
class DefaultFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return TextView(activity).apply { text = "default" }
}
}
res/layout/activity_main.xml
<?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="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="click" />
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private val defaultFragment = DefaultFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun onClick(view: View) {
val transaction = supportFragmentManager.beginTransaction()
transaction.setCustomAnimations(R.animator.slide_up, R.animator.slide_down) // enter일 경우에만 animation 적용
// transaction.setCustomAnimations(R.animator.slide_up, R.animator.slide_down, R.animator.slide_up, R.animator.slide_down) // enter, pop일 경우 모두 animation 적용
transaction.replace(R.id.frameLayout, defaultFragment)
transaction.addToBackStack(null)
transaction.commitAllowingStateLoss()
}
}
참고
[이슈] Can not perform this action after onSaveInstanceState
설명
- Activity 화면 회전과 같은 이벤트 발생시 Activity의 상태는 초기화 되고 레이아웃도 다시 그리게 된다.
- 이 때 상태를 저장하고 처리할 수 있도록 onSaveInstanceState() 메소드를 제공하고 있다.
- 어떤 이벤트가 발생했을 때 비동기적으로 transaction.commit()을 하게될 경우 commit() 전에 onSaveInstanceState()가 먼저 호출되었으면 해당 오류가 발생한다.
이슈 해결
- transaction.commit()을 비동기적으로 하지 않도록 개발한다.
- transaction.commit() 대신에 transaction.commitAllowingStateLoss() 메소드를 사용한다.
- state 변경이 일어나지 않은 경우 commit()을 수행하고, 변경이 일어난 경우에는 commit()을 수행하지 않는 방식
예시 코드
FirstFragmentclass FirstFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return TextView(activity).apply { text = "first" }
}
}
SecondFragment
class SecondFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return TextView(activity).apply { text = "second" }
}
}
res/layout/activity_main.xml
<?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="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="click" />
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private val handler = Handler()
private val first = FirstFragment()
private val second = SecondFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setFragment(first)
}
fun onClick(view: View) {
// 1. onClick() 호출
// 2. onSaveInstanceState() 호출 (ex. Activity 회전 이벤트 발생)
// 3. transaction.commit() 호출시 오류 발생 (java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState)
handler.postDelayed({
setFragment(second)
}, 3000)
}
private fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout, fragment)
transaction.addToBackStack(null)
transaction.commit()
// transaction.commitAllowingStateLoss()
}
}
참고
반응형
'Development > Android' 카테고리의 다른 글
[Android] DialogFragment (0) | 2021.02.09 |
---|---|
[Android] ListFragment (0) | 2021.02.09 |
[Android] DatePicker (0) | 2021.02.09 |
[Android] ListDialog (0) | 2021.02.09 |
[Android] ProgressDialog (0) | 2021.02.09 |