티스토리 뷰
앱개발 숙련 1주차 정리 - 2
프래그먼트
프래그먼트란?
프래그먼트는 액티비티 위에서 동작하는 모듈화된 인터페이스이다.
프래그먼트를 사용하면 한 개의 액티비티 화면 안에서 특정 영역만 교체가 가능하다.
액티비티와 프래그먼트의 차이
액티비티는 인텐트를 통해서 데이터를 전달하지만,
프래그먼트는 메소드를 호출시켜 다른 화면에 데이터를 전달한다.
프래그먼트 사용이유
액티비티로 화면을 계속 넘기는 것보다, 프래그먼트를 이용하여
화면의 일부만 바꾸는 것이 자원의 이동량이 적어 속도가 더 빠르다.
또한 액티비티를 적게 만들게 되어 액티비티의 복잡도가 줄어든다.
프래그먼트 전환 함수
private fun setFragment(frag : Fragment) {
// 프래그먼트 트랜잭션 시작
supportFragmentManager.commit {
replace(R.id.frameLayout, frag) // 프래그먼트 교체
setReorderingAllowed(true) // 프래그먼트 재정렬 허용
addToBackStack("") // 트랜잭션을 백스택에 추가
}
}
프래그먼트를 인자로 받아 프레임 레이아웃에 할당시키는 방식으로 프래그먼트를 전환한다.
프래그먼트 재정렬을 허용함으로써 트랜잭션의 성능을 최적화한다.
트랜잭션을 백스택에 추가하게 되면 사용자가 디바이스의 뒤로가기 버튼을
눌렀을 때 이전 프래그먼트로 돌아갈 수 있도록 한다.
프래그먼트 예제
implementation("androidx.fragment:fragment-ktx:1.8.1")
gradle파일에 의존성을 추가한다.
임의의 빈 프래그먼트 2개를 만들어준다.
각 프래그먼트와 메인화면의 레이아웃을 만들어준다.
메인의 빈공간에는 FrameLayout이 들어간다.
setFragment(FirstFragment())
binding.apply {
fragment1Btn.setOnClickListener{
setFragment(FirstFragment())
}
fragment2Btn.setOnClickListener {
setFragment(SecondFragment())
}
}
setFragment를 호출해 초기에 띄울 프래그먼트를 설정한다.
각 버튼을 눌렀을 때 해당하는 프래그먼트를 띄우도록 동작을 정의한다.
프래그먼트의 데이터 전달
Activity → Fragment
binding.apply {
fragment1Btn.setOnClickListener{
val dataToSend = "First Fragment"
val fragment = FirstFragment.newInstance(dataToSend)
setFragment(fragment)
}
fragment2Btn.setOnClickListener {
val dataToSend = "Second Fragment"
val fragment = SecondFragment.newInstance(dataToSend)
setFragment(fragment)
}
액티비티에서 프래그먼트로 데이터를 전달할 때는,
프래그먼트의 newInstance 메소드를 통해 데이터를 전달한다.
private const val ARG_PARAM1 = "param1" // 키네임 정의
class FirstFragment : Fragment() {
private var param1: String? = null // 넘겨받을 문자열 데이터
private val binding by lazy { FragmentFirstBinding.inflate(layoutInflater) }
// null체크 후 파라미터를 넘겨받은 데이터로 초기화
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
}
}
// 인자로 받은 데이터를 텍스트뷰에 설정
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvFragText1.text = param1
}
// 프래그먼트 뷰 생성
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
companion object {
@JvmStatic
// 전달받은 데이터를 Bundle에 담고, 프래그먼트의 인자로 설정
fun newInstance(param1: String) =
FirstFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
}
Fragment의 함수들을 오버라이딩하여 데이터를 넘겨받는다.
Fragment → Fragment
첫번째 프래그먼트에 두번째 프래그먼트로 이동하는 버튼을 하나 추가한다.
binding.btnMoveFrag2.setOnClickListener {
val dataToSend = "Move Fragment2"
val fragment2 = SecondFragment.newInstance(dataToSend)
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.frameLayout, fragment2).addToBackStack(null).commit()
}
첫번째 프래그먼트의 onViewCreated 메소드에 데이터 전달 로직을 추가한다.
Fragment → Activity
프로젝트 폴더 우클릭 > New > Kotlin Class/File > Interface
interface FragmentDataListener {
fun onDataReceived(data: String)
}
인터페이스에 받아온 데이터를 처리할 추상메소드를 하나 추가한다.
override fun onDataReceived(data: String) {
Toast.makeText(this, data, Toast.LENGTH_SHORT).show()
}
메인에서 해당 인터페이스를 상속하여 데이터를 어떤식으로 처리할지 정의한다.
private var listener:FragmentDataListener?= null // 리스너 정의
// 프래그먼트가 처음 액티비티에 연결될 때 호출
override fun onAttach(context: Context) {
super.onAttach(context)
// 메인 액티비티에 프래그먼트 리스너가 있는지 확인
if (context is FragmentDataListener) {
listener = context
} else {
throw RuntimeException("$context must implement FragmentDataListener")
}
}
정의한 인터페이스를 타입으로 가지는 리스너 변수를 하나 선언하고
onAttach()에서 인터페이스 구현 여부에따라 리스너를 초기화한다.
binding.btnSendActivity.setOnClickListener {
val dataToSend = "Frag to Main"
listener?.onDataReceived(dataToSend)
}
마찬가지로 두 번째 프래그먼트에도 버튼 하나를 만들고
버튼 누르면 리스너의 onDataReceived를 호출해서 데이터를 실어보낸다.
'내일배움캠프 > Android 국비지원' 카테고리의 다른 글
TIL 46일차 (챌린지반 4주차 세션 정리 및 첫번째 과제) (0) | 2024.07.29 |
---|---|
TIL 45일차 (앱개발 숙련 1주차 정리 - 3) (0) | 2024.07.23 |
TIL 43일차 (앱개발 숙련 1주차 정리 - 1) (0) | 2024.07.13 |
TIL 42일차 (챌린지반 3주차 세션 과제) (0) | 2024.07.12 |
TIL 41일차 (소수 찾기 - Kotiln | 코드카타 잠시 쉽니다) (0) | 2024.07.10 |