# Sliding up Panel Layout
요즘 나온 앱들 중 꽤나 UI 측면에 신경을 쓴 앱들은 대부분 이용하는 레이아웃이 아닐까 싶다.
SlidingUpPanel Layout은 스와이프를 통해 숨겨져 있던 레이아웃을 펼치는 기능이 있다는 점에서 Drawer Layout이랑 비슷한데, AndroidX 에서 기본적으로 제공하는 Drawer Layout은 화면 좌측, 혹은 우측에서만 스와이프가 가능한 반면, SlidingUpPanel Layout을 이용하면 화면 하단이나 상단에서도 스와이프하여 숨겨진 레이아웃을 나타내는 것이 가능하다.
본 포스팅에서는 umano의 AndroidSlidingUpPanel 라이브러리를 이용하여 이를 구현하고자 한다.
#Dependency
umano 깃헙 으로 들어가서, 안드로이드 스튜디오 프로젝트의 gradle:app 파일에 라이브러리 경로를 추가해준다.
본 포스팅을 작성하는 시간 기준으로는 아래의 코드를 추가하면 된다.
dependencies{
...
implements 'com.sothree.slidinguppanel:library:3.4.0'
}
( 옛날 방식인 compile 대신 implements 를 쓸 것을 권장한다. 사실 저 라이브러리가 나온지 좀 되어서 그렇다)
#Apply
편리한 점은 xml 파일에만 작성을 해 두면, java 코드 없이도 잘 작동한다는 점이다.
물론, 커스텀 및 스와이프 이벤트를 통해 무언가를 하고 싶을 때 java 코드를 이용해서 프로그래밍 역시 가능하다.
필자가 심심풀이로 만든 앱 '발자취'의 xml 파일을 예제로 첨부해 보겠다.
<?xml version="1.0" encoding="utf-8"?>
<com.sothree.slidinguppanel.SlidingUpPanelLayout
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:id="@+id/main_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:gravity="bottom" // 어떤 방향에서부터 스와이프 할 건지?
android:background="#00FFFFFF"
app:umanoDragView="@id/drawer" // 어떤 id의 레이아웃에 적용할 것인지?
app:umanoPanelHeight="125dp" // 얼만큼 남기고 레이아웃을 숨길 것인지?
app:umanoOverlay="true" // 필자의 경우 true를 해야 했음(부연설명 참조)
app:umanoShadowHeight="0dp"> // 그림자 효과 얼마나 줄 것인지?
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_list"
android:background="@drawable/button_list_background"
android:text="목록"
android:textColor="@color/colorWhite"
android:textSize="15sp"
android:textStyle="bold"
android:layout_width="70dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="30dp"
android:layout_marginTop="40dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:background="@color/colorTransparent"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="600dp"
android:orientation="vertical">
<View
android:id="@+id/swipe"
android:background="@drawable/swipe_tip_background"
android:layout_width="60dp"
android:layout_height="5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_gravity="center_horizontal"/>
<RelativeLayout
android:background="@drawable/drawer_background"
android:layout_width="match_parent"
android:layout_height="600dp">
<EditText
android:id="@+id/et_placeName"
android:background="@drawable/edittext_background"
android:hint="그곳은 어떤 장소인가요?"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:padding="10dp"/>
<EditText
android:id="@+id/et_placeFeel"
android:background="@drawable/edittext_background"
android:layout_below="@id/et_placeName"
android:layout_width="match_parent"
android:layout_height="150dp"
android:hint="그곳에서의 추억을 적어주세요"
android:layout_marginTop="30dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginBottom="10dp"
android:padding="10dp"/>
<GridView
android:id="@+id/gv_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/et_placeFeel"
android:layout_alignLeft="@id/et_placeFeel"
android:layout_alignRight="@id/et_placeFeel"
android:horizontalSpacing="5dp"
android:verticalSpacing="10dp"
android:numColumns="4"/>
<Button
android:id="@+id/btn_stamp"
android:background="@drawable/button_stamp_background"
android:text="남기기"
android:textStyle="bold"
android:textSize="15sp"
android:textColor="@color/colorWhite"
android:layout_width="70dp"
android:layout_height="40dp"
android:layout_below="@id/gv_image"
android:layout_marginTop="50dp"
android:layout_alignParentRight="true"
android:layout_marginRight="30dp"
android:layout_marginBottom="60dp"/>
</RelativeLayout>
</LinearLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
자, 보면 가장 Parent 레이아웃을 SlidingUpPanel Layout으로 설정하였고, 몇가지 옵션들을 추가로 작성하였다.
SlidingUpPanel Layout은 적어도 두 개 이상의 child를 가져야 하며, 그 중 하나는 스와이프 팝업을 적용할 레이아웃이다.
필수적인 옵션에 해당하는 코드에다가 별도로 주석을 작성하였으니 참고하면 좋을 것이고, 개중에 unamoOverlay 라는 옵션이 있는데, 저 옵션을 false 로 설정하면 스와이프 했을 때 배경 레이아웃이 같이 밀려 움직인다. 또한 스와이프 할 레이아웃에다가 background 로 round shape을 적용했을 때 스와이프 시 음영에 의해 꼭짓점 부분이 없어지지 않고 흰색으로 남아있는 단점이 있다.
#Result
Parent Layout을 SlideingUpPanel Layout으로 설정하고, 적어도 두 개의 Child 레이아웃을 구현한 후, 개중 하나를 DragView로 설정하였다. 나머지 주석이 달린 필수 옵션들을 작성하면 이제 완성된 것이다.
참고로 해당 레이아웃을 구현한 activity 혹은 fragment에서 스와이프 이벤트를 처리하려면 SlidingUpPanel Layout 자체에 id를 설정한 후 findViewById() 를 통해 연동시킨 후 setPanelState()함수를 통해 DragView의 스와이프 상태를 결정할 수 있으며, addPanelSlideListener(new SlidingPanelLayout.PanelSlideListener(){}; ) 리스너를 통해서 스와이프 되었을 경우, 스와이프 상태 변경이 되었을 경우 이벤트 처리를 해줄 수 있다.
필자는 위의 레이아웃을 이용해서 메인 화면을 작성하였는데, 결과는 다음과 같다.
데모영상도 있다.
https://www.youtube.com/watch?v=oU8-EiFkAs8
'Android' 카테고리의 다른 글
[Android] Shared Preference 총정리 - 배열, 비트맵 까지 (0) | 2020.08.07 |
---|---|
[Android] [Tip] SwipeRefreshLayout 스와이프 민감도 설정 (2) | 2020.07.30 |
첫번째 글 - UI UX 디자인 하며 느낀 점 (0) | 2020.07.29 |
댓글