Android, iOS

[안드로이드] Expandable layout을 만드는 3가지 방법

미스터머글 2021. 4. 18. 23:54
728x90
반응형

 

Expandable layout이 무엇인가. 위 이미지를 보면 리스트뷰에서 다른 화면으로 전환하지 않고 리스트 내부의 뷰를 확장시키면서 현재 화면을 유지하고 있다. 이런 형태를 Expandable layout 혹은 Expandable list라고 부른다. 흔하게 보이는 이 위젯을 만드는 방법이 다양한데 간단한 방법부터 외부 라이브러리를 쓰는 방법까지 살펴볼 예정이다.

 

아래 샘플 코드가 사용된 사례가 보고 싶다면 필자의 github를 참고하시라.

 

conquerex/WhatTheMvvm

우헤헿헤헤. 이게 뭐당가????? Contribute to conquerex/WhatTheMvvm development by creating an account on GitHub.

github.com

 

 

🎀 1. animateLayoutChanges를 사용

제일 간단한 사례부터 살펴보자. animateLayoutChanges는 똑똑한 옵션이다. 아무런 애니메이션 효과를 넣지 않은 상황에서 왠지 애니메이션 효과가 나올 것같은 레이아웃을 만들어두면 알아서 보여주거나 숨겨주는 애니메이션 효과를 나타내어준다. 아래 예시를 살펴보자.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:animateLayoutChanges="true"
    android:layout_marginTop="22dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/parent1"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize" >
        
    <!-- 생략 -->

    <LinearLayout
        android:id="@+id/layout_expand1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF6A9"
        android:orientation="vertical"
        android:visibility="gone">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="15dp"
            android:text="Sample Sample Sample Sample" />

        <!-- 생략 -->

최상위 LinearLayout을 보면 animateLayoutChanges가 true임을 볼 수 있다. 이제 이 아래의 자식뷰는 기대되는 애니메이션 처리가 된 셈이다. 하위 ConstraintLayout은 일종의 타이틀 레이아웃이다. 타이틀 레이아웃을 클릭하면 아래 "layout_expand1"이라고 되어 있는 레이아웃이 바로 아래 열리게 된다. 이를 기대할 수 잇는 이유가 ConstraintLayout(parent1)과 같은 레벨에 존재하는 layout_expand1이 보이지 않기 때문이다. (android:visibility="gone") 

 

override fun onCreate(savedInstanceState: Bundle?) {

  // 일부 생략

  binding.imgMore1.setOnClickListener {
      if (binding.layoutExpand1.visibility == View.VISIBLE) {
          binding.layoutExpand1.visibility = View.GONE
          binding.imgMore1.animate().setDuration(200).rotation(180f)
      } else {
          binding.layoutExpand1.visibility = View.VISIBLE
          binding.imgMore1.animate().setDuration(200).rotation(0f)
      }
  }

물론 위와 같이 클릭 이벤트가 들어가서 원하는 레이아웃의 visibility는 조절해줘야 한다. 이렇게 보여주고 숨기고만 구분해줘도 애니메이션 효과를 볼 수 있다. 오직 이것만으로 레이아웃을 열고 닫는 것이 가능하다. (Wow)

 

 

 

🎀 2. Custom class - ToggleAnimation

이번에는 커스텀 클래스를 만들어서 Expandable layout을 만들어보자. 1번의 경우보다 까다로운 조건으로 애니메이션 효과 혹은 확장 효과를 얻고 싶다면 아무래도 커스텀 클래스를 만들 수 밖에 없다. 상단 필자의 github에 들어가서 ToggleAnimation.kt 코드를 살펴보면 된다.

fun toggleArrow : 화살표시 회전 효과
fun expand : 레이아웃 확장 효과
fun collapse : 레이아웃 축소 효과

이렇게 만들어진 커스텀 클래스를 사용할 때는 아래와 같이 사용한다.

// PracticeActivity
private fun toggleLayout(isExpanded: Boolean, view: View, layoutExpand: LinearLayout): Boolean {
    ToggleAnimation.toggleArrow(view, isExpanded)
    if (isExpanded) {
        ToggleAnimation.expand(layoutExpand)
    } else {
        ToggleAnimation.collapse(layoutExpand)
    }
    return isExpanded
}

override fun onCreate(savedInstanceState: Bundle?) {

  // 일부 생략

  binding.parent2.setOnClickListener {
      val show = toggleLayout(!isExpanded, binding.imgMore2, binding.layoutExpand2)
      isExpanded = show
  }

그런데 이렇게 직접 만들어서 쓸려면 시간이 많이 걸리고 다른 개발자의 코드를 참고해야하는 경우가 있을 수 있다. 그럴거면 차라리 외부 라이브러리를 쓰는 것이 좋을 수 있다.

 

 

🎀 3. 외부 라이브러리 - com.github.skydoves:expandablelayout

이 라이브러리는 여러 개의 Expandable layout 라이브러리 중 하나일 뿐이다. 이를 사용한 Expandable layout을 필자의 github에 넣어 두었다. 직접 만들었을 때보다 훨씬 수려한(?) 모습으로 레이아웃을 구성할 수 있다. (물론 본인 역량이 우수하다면 필자의 예상과 다를 수 있다.) 실제 사용방법은 해당 라이브러리 가이드와 필자의 github를 참고하면 될 것이다. 일반적인 외부 라이브러리 사용과 크게 다르지 않아 별도의 사용법은 남기지 않는다.

 

skydoves/ExpandableLayout

🦚 An expandable layout that shows a two-level layout with an indicator. - skydoves/ExpandableLayout

github.com

 

 

 

참고자료
- View Expand Animation Affects Other Views by Using “animateLayoutChanges” in Nested Layout
- 레이아웃 업데이트 자동 애니메이션 처리
- 안드로이드 Expandable RecyclerView 만들기

 

728x90
반응형