일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- TEST
- tabbar
- 안드로이드
- drift
- 계측
- Button
- livedata
- scroll
- DART
- data
- android
- 앱
- ScrollView
- LifeCycle
- Coroutines
- textview
- appbar
- activity
- 앱바
- viewmodel
- Navigation
- 테스트
- Compose
- binding
- intent
- textfield
- Dialog
- Flutter
- Kotlin
- CustomScrollView
- Today
- Total
Study Record
[안드로이드] SlidingPaneLayout 살펴보기 본문
😶 SlidingPaneLayout 패턴
Android 가 사용되는 기기는 핸드폰뿐만 아니라 태블릿, 데스크톱 등에서 사용될 수 있다. 이에 기기에 맞게 화면을 재구성해야 할 때가 있다. SlidingPaneLayout 은 화면을 재구성하기 쉽게 도와주는 Layout 이다.
예를 들어, 목록 List View 가 있고 그 List 의 항목을 클릭하면 세부 정보를 보여주는 View 가 있을 수 있다. 이것을 화면이 작은 핸드폰과 같은 기기에서는 List 항목을 보여주는 화면과 세부 정보를 보여주는 화면으로 나눠 보여준다. 화면이 좀 큰 태블릿 같은 경우에는 두 분할로 나눠 한쪽에는 목록 정보를 보여주고 나머지 한쪽에는 그 목록의 세부 정보를 보여주도록 화면을 구성할 수 있다.
😶 창 분할 기준
화면이 작으면 2개의 창을 각각 하나씩 보여주고 2 개의 창의 최소 크기보다 크면 하나의 화면에 2개의 화면을 분할하여 보여준다. 장치의 표준이 되는 크기가 있는데 그건 다음 표와 같다.
너비(Width) | BreakPoint | 장치 표준 |
Compact Width | < 600dp | 핸드폰 세로 모드 |
Medium width | 600dp + | 테블릿의 세로모드 |
Expanded with | 840dp + | 테블릿의 가로모드 |
😶 Library Dependencies
dependencies {
...
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
}
😶 SlidingPaneLayout 배치하기
SlidingPaneLayout 를 부모로 창으로 사용할 2개의 View 혹은 ViewGruop 을 Child 로 둔다.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
android:id="@+id/sliding_pane_layout"
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=".SportsListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="550dp"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<androidx.fragment.app.FragmentContainerView
android:layout_width="300dp"
android:layout_height="match_parent"
android:id="@+id/detail_container"
android:layout_weight="1"
android:name="com.example.android.sports.NewsDetailsFragment"/>
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
목록 리스트를 보여주는 recycler_view 와 목록을 클릭하면 세부 사항을 보여주는 detail_container 를 SlidingPaneLayout 의 child 로 배치했다. 두 번째 창의 layout_weight 를 1로 준 이유는 현재 2개의 창은 880dp 를 차지한다. 880dp 보다 큰 너비를 가진 장치라면 남은 공간만큼 빈틈으로 보일 것이기 때문에 layout_weight = 1 로 하면 세부 사항 창이 나머지 공간을 전부 차지하면서 자연스럽게 2 분할 화면으로 보인다.
😶 창 전환
너비가 큰 태블릿 화면이면 한 화면에 2창 모두 배치된 상태이니 창 전환과 관련된 함수를 실행해도 영향을 받지 않는다. SlidingPaneLayout 안에 배치한 창 2개는 선언한 순서대로 왼쪽에서 오른쪽으로, 첫 번째 화면과 두 번째 화면으로 나뉜다.
너비가 작은 핸드폰 화면에는 첫 번째 화면이 먼저 차지하고 있을 것이다 여기서 두번째 화면으로 전환하고 싶다면 openPane() 함수를 실행하고 두번째 화면에서 첫번째 화면으로 돌아갈 땐, closePane() 함수를 실행한다.
binding.slidingPaneLayout.openPane()
binding.slidingPaneLayout.closePane()
함수를 실행하고 화면이 전환될 때 애니메이션 효과가 자동으로 설정되어 있다.
😶 뒤로 가기 혹은 Back button 관리
너비가 작은 핸드폰과 같은 기기는 첫 번째 창과 두번째 창이 다른 화면으로 존재하며 만약 두번째 화면에서 뒤로 가기 버튼을 누르면 첫번째 화면으로 돌아가는 것이 자연스럽다. 이와 관련해서 명시된 것이 없으면 두번째 화면이어도 뒤로 가기 버튼을 누르면 첫번째 화면으로 돌아가지 않는다. (back Stack 에 명시된 바가 없으면 종료되고 명시된 정보가 있다면 그곳으로 돌아간다.)
Back Button 을 관리하는 방법은 OnBackPressedCallback 를 사용한다.
먼저, OnBackPressedCallback 을 상속받는 Callback 클래스를 생성한다.
class SlidingPanelOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
) : OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen) {
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
}
OnBackPressedCallback 의 생성자의 slidingPaneLayout.isSlideable 의 의미는 창 전환을 할 수 있는지(true/false)를 의미하는데 핸드폰과 같은 너비가 작아 한 화면에 두 개의 창을 배치할 수 없는 경우에만 true 를 갖는다. slidingPaneLayout.isOpen 은 창전환이 가능할 때, 현재 창지 두 번째 창일 때 true 를 갖는다. 따라서, 창 전환을 할 수 있고 현재 화면이 두번째 창일 경우에만 callback 이 가능하다.
handleOnBackPressed() 함수는 뒤로 가기 버튼을 눌렀을 때 위의 생성자에서 CallBack 이 가능할 때 호출되는 함수로 여기서 첫 번째 화면으로 이동하는 함수(closePane())를 실행함으로써 두번째 화면에서 뒤로가기 버튼을 누르면 첫번째 화면으로 돌아간다.
SlidingPanelLayout.PanelSlideListener 를 상속받으면 open 될 때와 close 될 때를 호출받을 수 있는데 이때 isEnabled 를 true 로 하면 OnBackPressedCallback 의 callBack 을 가능(Enable)하고 false 로 하면 callBack 이 불가능하다.
class SlidingPanelOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
) : OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
SlidingPaneLayout.PanelSlideListener {
init {
slidingPaneLayout.addPanelSlideListener(this)
}
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
override fun onPanelSlide(panel: View, slideOffset: Float) {
}
override fun onPanelOpened(panel: View) {
isEnabled = true
}
override fun onPanelClosed(panel: View) {
isEnabled = false
}
}
OnBackPressedCallback 을 이제 Back Press 를 관리하는 OnBackPressedDispatcher 에 Callback 을 등록해야 한다.
OnBackPressedDispatcher 는 FragmentActivity 객체로 접근할 수 있다.
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
SlidingPanelOnBackPressedCallback(slidingPaneLayout)
)
첫 번째 인자로 받은 LifecycleOwner 로 Lifecycle.State.STARTED 인 경우에만 OnBackPressedDispatcher 에 callback 을 추하고 LifcycleOwner 가 파괴되면 등록된 callback 을 제거한다.
😶 Lock Mode
SlidingPaneLayout 은 너비가 작은 화면일 때 창 전환이 가능한 경우 따로 gesture navigation 을 사용하지 않아도 스와이프로 창 전환을 할 수 있다. 이것을 원치 않을 경우 다음과 같이 lockMode 값을 LOCK_MODE_LOCKED 로 설정하면 된다.
slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
'안드로이드' 카테고리의 다른 글
[안드로이드] binding Adapter (결합 어댑터) (0) | 2023.08.10 |
---|---|
[안드로이드] Retrofit 살펴보기 (ViewModel, Moshi, coroutines) (0) | 2023.08.09 |
[안드로이드] 단위 테스트 참고사항 (0) | 2023.08.03 |
[안드로이드] Task 와 Back Stack (0) | 2023.08.02 |
[안드로이드] LiveData 참고사항 (0) | 2023.08.02 |