Activity를 여러 개 만드는 것보다
하나의 Activity와 여러 개의 Fragment로 만들면 좋은 점
👍 화면전환 navigation이 처리해줘서 편리하다.
👍 구글이 밀고 있다.
기존의 화면 전환은 FragmentManager를 이용해서 트랜잭션 add,replace,commit 를 통해 이루어졌지만, Jetpack의 navigation을 이용하도록 권장했다.
GUI 한 눈에 확인 가능
3에서 만든 네브리소스파일을 app:navGraph="@navigation/nav_graph" 로 연결
에뮬레이터 새로깔기 귀찮아서 xml 대충 맞췄으니 못본척하기..
Xcode 스토리보드처럼 한 눈에 보이는 기능이 있었다니...내졸작다시할래요....
<fragment
android:id="@+id/mainFragment"
android:name="com.example.lovetest.Fragment.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_mainFragment_to_questionFragment"
app:destination="@id/questionFragment" />
프래그먼트에 action이 들어간 것을 확인할 수 있다.
액션 id 생성과 목적지는 다음 프래그먼트라는 것을 지정해준다.
One or more issues found when checking AAR metadata values:
The minCompileSdk (33) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-32).
Dependency: androidx.core:core:1.9.0.
AAR metadata file: C:\Users\minju.gradle\caches\transforms-3\3a73d4c1cdf65c14c4dc712518275464\transformed\core-1.9.0\META-INF\com\android\build\gradle\aar-metadata.properties.
Build.gradle 에서 compileSdk 와 targetSdk를 32로 높여주도록 하자.
class MainActivity : AppCompatActivity() {
//지금 아니라 나중에 정의할 것임 lateinit
lateinit var navController : NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostController = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostController.navController
}
}
lateinit : 지금 아니라 나중에 정의하겠다는 예약어
꼭 타입을 명시해주어야 한다!
알고보니 Fragment는 주석처리된 문장이 잘 작동하지만
androidx.fragment.app.FragmentContainerView 는
supportFragmentManager의 findFragmentById 함수를 통해 id를 지정해줘야했다
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//뷰가 만들어지고 나서 생성되는 함수
super.onViewCreated(view, savedInstanceState)
//navController = Navigation.findNavController(view)
val navHostFragment =
requireActivity().supportFragmentManager.
findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
}
이렇게 supportFragmentManager를 통해 id를 typecasting 하고 연결시켜준다.
왜인지 support가 뜨지 않아 액티비티가 있다는 것을 보장해주는
requireActivity() 를 적어주었다.
Build.gradle에서 buildFeatures 안에 뷰 바인딩 true 후 Sync.
lateinit var binding : FragmentMainBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//바인딩 초기화
binding = FragmentMainBinding.inflate(inflater, container,false)
// 원래 레이아웃뷰 반환은 이거지만 바인딩 사용하므로 바꿔줌
//return inflater.inflate(R.layout.fragment_main, container, false)
return binding.root
}
프래그먼트이름Binding.inflate 함수를 통해 Fragment에서의 바인딩 초기화
뷰바인딩으로 버튼 접근하여 버튼에 navController 액션 이동달기
그냥 프래그먼트가 전환되면 너무 인위적이니까 애니메이션을 추가해주자
nav_graph에서 화살표누르고 애니메이션들을 추가해줌
그냥 객체의 setOnClickListener 함수를 이용해도 되지만,
Activity에 View.OnClickLister 인터페이스를 상속받아 사용하면
여러 개의 버튼들도 한 번에 처리할 수 있고 훨씬 간편해진다🥰
class SelectionFragment : Fragment() , View.OnClickListener{
프래그먼트에 상속을 받으면,
override fun onClick(v: View?) {
함수를 오버라이딩 하라고 나온다.
R.id.btn_pre ->{
navController.popBackStack()
}
Fragment는 이동할 때마다 Back stack에 쌓인다.
⬅️ 뒤로가기를 누를 시 하나씩 pop 시키는 것이므로 popBackStack 메소드를 이용한다.
Bundle 클래스
번들은 Map형태의 데이터 묶음. Key 값은 String, value는 Any? 이다.
- bundleOf()는 Bundle을 만들어서 리턴해주는 함수
fun navigateWithIndex(idx: Int) {
// val bundle2:Bundle= bundleOf("index" to i)
val bundle = Bundle()
bundle.putInt("index",idx)
navController.navigate(R.id.action_selectionFragment_to_resultFragment, bundle)
}
index를 번들로 담아 result프래그먼트에게 이동 시 함께 전달한다.
to가 자꾸 빨간색떠서 다들 잘 되는데 왜 나만...?
putInt 함수로 넣어주었다!!^^
😓추가 : anko 라이브러리 설치안해서 그런거였음...!
..근데 19년도에 없어졌다고 한다
그러면 data를 받아야하는 ResultFragment에서는
class ResultFragment : Fragment() {
var option = -1
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
option = arguments?.getInt("index")?:-1 //만약null이 전달되면 -1
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_result, container, false)
}
}
arguments로 key값 인덱스를 통해 getInt 함수로 value를 받아오면 된다.
엘비스 연산자를 통해 null일 경우를 대비하자
끝!