탭 레이아웃 (Tab Layout)
안드로이드에서 가장 많이 쓰이는 UI 가 있다면 단연코 탭 레이아웃(Tab Layout) 을 뽑을 수 있습니다. 토스, 카카오톡을 비롯한 많은 기업들의 앱에서도 채용하고 있는데요. 화면을 크게 방해하지 않으면서도 최대 4 ~ 5개 가량의 메뉴를 가장 직관적으로 보여줄 수 있기 때문입니다.
시작하기 전에
안드로이드에서 탭 레이아웃(Tab Layout)을 구성하는 방법은 꽤 다양합니다. 탭 버튼을 각각 만들어 배치/구성 하는 방법(이건 진짜 옛날 방식이고 아주아주 피곤한 방법이에요.), 탭 레이아웃(Tab Layout) 을 이용하여 구성하는 방법, 네비게이션을 이용하여 구성하는 방법 등 여러가지가 있습니다. 하지만 별별코딩에서는 가장 기본이 되는 탭 레이아웃(Tab Layout)을 이용해서 UI 를 만들어볼 생각입니다.
그리고 이 탭 레이아웃으로 구성된 화면을 좌우로 밀어서도 화면을 전환할 수 있도록 뷰페이저2(View Pager2)를 더해보겠습니다.
탭 레이아웃 앱을 만들어볼 환경입니다.
언어 : 코틀린(Kotlin)
IDE : 안드로이드 스튜디오 4.1.2
Minimu SDK : Android 5.0 (Lollipop, API 21)
시작은 XML 편집부터
탭 레이아웃 배치
탭 레이아웃(Tab Layout) 을 만들기 위해 XML 편집으로 와 팔레트(Palette)에서 레이아웃(Layout)을 보면 우리가 찾고 있는 탭 레이아웃은 없습니다. 사실 탭 레이아웃은 레이아웃이 아니기 때문이지요.
네? 탭 레이아웃이라면서 레이아웃이 아니면 뭐냐구요? 따지고보면 레이아웃은 하위 위젯등 뷰들을 배치하고 그리는, 하나의 큰 도화지입니다. 하지만 탭 레이아웃은 각 탭을 상징하는 버튼을 나열할 뿐 마음대로 배치하는 등 포지셔닝을 할 수 없습니다. 그래서 저도 왜 레이아웃이라는 이름이 붙었는지 궁금하네요.
어쨌든, 탭 레이아웃은 그 아래의 컨테이너(Containers) 에서 찾을 수 있습니다.
네, 탭 레이아웃은 어쩌면 Tab Item 들을 그저 '감싸고만' 있는 컨테이너에 가깝습니다. 그런데 레이아웃 카테고리에 있었어도 상관없었을 것 같은데, 뭐.. 이건 구글의 마음이니까요. 이제 탭 레이아웃을 화면으로 끌어와 배치해줍니다.
탭 레이아웃은 상/하단에 끝에 배치하는게 일반적이므로 하단에 배치했습니다. 기본적으로 탭의 자식 뷰인 탭 아이템(TabItem)은 3개가 들어가 있습니다. 코드에서도 3개의 탭 아이템이 들어가 있는 것을 확인할 수 있지요. 코드에서 복붙으로 탭 개수를 늘리거나 줄일 수 있습니다. 그런데 처음 이렇게 배치하고나면 글씨가 빨갛게 되어있는 것을 볼 수 있습니다. 또한 디자인 화면에서도 느낌표로 무언가 더 해야할 것이 있음을 알 수 있지요.
이는 상위 레이아웃이 ConstraintLayout 이기 때문입니다. 여기서는 자세하게 설명할 수 없어서 간단하게 말하면 우리는 탭 레이아웃이 어디에 배치되는지 눈으로 보고 알 수 있지만 0과 1밖에 모르는 똑똑하지만 멍청한 기계 안드로이드는 그 위치가 어딘지 모르기 때문입니다.
즉, 우리는 탭 레이아웃의 위치를 잡아주어야 하고, 오른쪽에 있는 Attributes 영역에서 지정해 줄 수 있습니다.
아직 레이아웃에 대한 내용은 별별코딩에 없기 때문에 다른 분의 글을 참고하시면 되고, 최소 상하/좌우 각 한 곳의 위치를 잡아주면 됩니다.
화면으로 사용할 프레그먼트(Fragment) 만들기
탭 레이아웃을 배치했다면, 각 탭에 맞는 화면 또한 만들어야 합니다. [패키지명] -> [New] -> [Fragment] -> [Fragment (Blank)] 를 만들어주면 됩니다. 이렇게 만들어진 프레그먼트는 각 탭의 화면이 됩니다.
별별코딩에서는 기본인 3개의 탭 아이템과 프레그먼트를 만들었습니다만, 원하는 개수에 맞춰 탭 아이템(Tab Item) 과 프레그먼트(Fragment) 를 만들면 됩니다.
이제 프레그먼트는 취향에 맞게 잘 꾸며주면 됩니다. 그런데 한가지 주의하셔야 할 점이 있습니다. 이렇게 만들어진 프레그먼트의 최상위 레이아웃은 프레임 레이아웃(FrameLayout) 으로 되어 있습니다. 만약, 프레임 레이아웃이 필요하다면 상관없지만 다른 레이아웃으로 바꿔서 사용하시길 추천드리겠습니다.
프레그먼트(Fragment)가 들어갈 프레임 레이아웃(Frame Layout) 배치하기
다시 탭 레이아웃이 있는 화면으로 돌아와 프레그먼트가 들어갈 자리를 만들어 줍니다. 간단하게 팔레트(Palette)에서 프레임 레이아웃(FrameLayout) 을 끌어와 배치합니다. 파란색 배경이 프레임 레이아웃입니다.
아이디(ID) 부여
각 탭 아이템(TabItem) 을 눌렀을 때 화면이 바뀌도록 하려면 탭의 아이디가 필요합니다. 선택된 탭이 무엇인지 구분할 수 있어야 하기 때문이죠. 다행인 것은 모든 탭 아이템에 아이디를 부여할 필요는 없습니다. 단 하나, 탭 레이아웃(Tab Layout)에만 부여하면 됩니다.
위에서 배치한 프레임 레이아웃(Frame Layout) 역시 아이디를 부여합니다. 각 탭의 화면이 되는 프레그먼트가 어디에 들어갈지 안드로이드도 알아야 하기 때문이죠.
코틀린(Kotlin) 으로 코딩
이제 코딩만하면 끝입니다. 코드는 직관적이며 간단하고 짧습니다. 하지만 먼저! 모듈단의 [build.gradle] 에서 플러그인(Plugins) 을 추가합니다. id 'kotlin-android-extensions' 는 코딩을 더욱 쉽게 만들어줍니다. 대표적으로 뷰(View) 를 연결하기 위해서 findViewById() 를 사용할 필요가 없습니다. XML 에서 부여한 아이디를 그대로 사용할 수 있습니다.
이제 메인 액티비티로 오셔서 코딩을 합니다. 아래 코드를 입력하시는데, 각 프레그먼트는 본인이 만든 클래스명을 입력해야 합니다. 저 따라입력하시면 안되요~
class MainActivity : AppCompatActivity() {
lateinit var tab1:Tab1 //프레그먼트 1
lateinit var tab2:Tab2 //프레그먼트 2
lateinit var tab3:Tab3 //프레그먼트 3
override fun onCreate(savedInstanceState: Bundle?) {
.
.
.
}
}
각 프레그먼트를 담을 변수 선언을 했다면 onCreate() 에서 객체로 만듭니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tab1 = Tab1() //프레그먼트 1 객체화
tab2 = Tab2() //프레그먼트 2 객체화
tab3 = Tab3() //프레그먼트 3 객체화
.
.
.
}
앱이 시작되었을 때 보여줄 화면을 지정합니다. 보여주고 싶은 탭을 지정하면 됩니다. supportFragmentManager 는 프레그먼트를 관리/컨트롤하는 객체로써 탭 레이아웃뿐만이 아니라 프레그먼트를 사용하는 모든 부분에서 사용됩니다.
supportFragmentManager.beginTransaction().add(R.id.frameLayout, tab1).commit()
이제 앱을 실행하면 위에서 지정한대로 시작과 함께 지정한 그 화면이 나타납니다. 하지만 아직 탭을 눌러도 동작하지 않죠. 이제 탭을 작동하게 만들어줍니다. 탭 레이아웃의 addOnTabSelectedListener() 메서드를 이용해서 리스너를 만듭니다. 이것으로 모든 탭의 동작을 감지/처리할 수 있습니다.
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
//여기에 작성
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
onTabSelected(tab: TabLayout.Tab?) { } 에 Tab 을 When() 으로 구분하여 처리합니다. tab의 파라미터로 전달되는 position 으로 각 탭을 구별합니다. 가장 왼쪽부터 0, 1, 2 번째의 탭이 됩니다.
when(tab?.position) {
0 -> {
//Tab1
replaceView(tab1)
}
1 -> {
//Tab2
replaceView(tab2)
}
2 -> {
//Tab3
replaceView(tab3)
}
}
반복되는 부분이므로 별별코딩에서는 replaceView(tab:Fragment) 라는 메서드를 만들었습니다. 별도의 처리를 원한다면 그에 맞게 코딩하면 됩니다.
private fun replaceView(tab: Fragment) {
//화면 변경
var selectedFragment: Fragment? = null
selectedFragment = tab
selectedFragment?.let {
supportFragmentManager.beginTransaction()
.replace(R.id.frameLayout, it).commit()
}
}
자, 이제 앱을 실행하면 시작과 함께 지정된 화면이 나타남은 당연하고 탭을 누를때마다 화면이 전환됩니다. 여기까지가 기본적인 탭 레이아웃(Tab Layout) 을 이용한 UI 를 구성한 앱입니다. 추가 포스팅으로 이 탭 레이아웃이 적용된 앱에 뷰 페이저2 를 더해서 좌우로 슬라이드하면 전환되도록 만들어볼 예정입니다.
감사합니다. 잘못된 부분이 있거나 궁금한 사항은 언제든지 댓글 달아주세요.