Beeeam

Power Menu 본문

Android

Power Menu

Beamjun 2023. 6. 27. 18:15

Power Menu 라이브러리는 메뉴나 팝업을 개발자가 원하는 대로 편리하게 커스텀하여 보여줄 수 있게하는 라이브러리이다. 밑의 링크에 들어가면 더 자세히 확인할 수 있다.

 

https://github.com/skydoves/PowerMenu

 

GitHub - skydoves/PowerMenu: :fire: Powerful and modernized popup menu with fully customizable animations.

:fire: Powerful and modernized popup menu with fully customizable animations. - GitHub - skydoves/PowerMenu: :fire: Powerful and modernized popup menu with fully customizable animations.

github.com

이번에 이 라이브러리를 사용했었고, 좋다고 느꼈기 때문에 정리해봤다.

 

라이브러리

먼저 외부 라이브러리이기 때문에 app단의 build gradle에 라이브러리를 추가해줘야 한다.

implementation "com.github.skydoves:powermenu:2.2.3"

PowerMenu.Factory()

안드로이드 기본 옵션 메뉴를 사용할 때 처럼 menu xml 을 만들지 않아도 된다. 대신 PowerMenu.Factory() 를 상속 받는 클래스를 만들고, 여기서 보여질 옵션들의 속성들을 정의 한다.

class MoreMenuFactory : PowerMenu.Factory() {

    override fun create(context: Context, lifecycle: LifecycleOwner): PowerMenu {
        return createPowerMenu(context) {
            addItem(PowerMenuItem("최신", false))
            addItem(PowerMenuItem("최근 인기", false))
            addItem(PowerMenuItem("best", false))
            setWidth(350) 
            setMenuRadius(8f)
            setLifecycleOwner(lifecycle)
            setAnimation(MenuAnimation.SHOWUP_TOP_RIGHT)
            setTextColor(ContextCompat.getColor(context, R.color.black))
            setTextSize(12)
            setTextGravity(Gravity.LEFT)
            setMenuColor(Color.WHITE)
            setInitializeRule(Lifecycle.Event.ON_CREATE, 0)
        }
    }
}

addItem() : 보여줄 아이템 항목 추가

setWidth() : 메뉴 창의 width를 정의

setMenuRadius() : 메뉴 창의 Radius를 정의 (끝에 모서리 각도?)

setTextGravity() : 메뉴 창의 텍스트 정렬 기준 (LEFT이면 왼쪽을 기준으로 나옴)

setLifecycleOwner() : 메뉴를 보여주는 Activity나 Fragment에 생명주기를 맞춰서 소멸되면 함께 해제 되게 함 이를 통해서 메모리 누수 문제를 해결할 수 있음

Activity

메뉴를 보여줄 Activity나 Fragment에서는 위에서 정의한 클래스를 활용하여 메뉴를 보여주는 동작을 정의하면 된다.

class MainActivity : AppCompatActivity() {

    private val moreMenu by powerMenu<MoreMenuFactory>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val text1 = findViewById<TextView>(R.id.text1)

        text1.setOnClickListener {
            moreMenu.showAsDropDown(it, -300, 0)
        }

        moreMenu.setOnMenuItemClickListener { position, item ->
            moreMenu.selectedPosition = position
            Toast.makeText(this, item.title, Toast.LENGTH_SHORT).show()
        }
    }
}

private val moreMenu by powerMenu<MoreMenuFactory>() 이 부분을 통해서 위에서 정의한 클래스를 변수화 한다.

(확실하지 않음 본인은 위에서 만든 factory를 상속 받는 클래스를 이 변수에 담았다고 이해하였음)

그리고 .showAsDropDown() 함수를 호출하여 메뉴 창을 화면에 보여준다.

.showAsDropDown() 함수는 클릭 된 아이템의 바로 밑에 메뉴 창을 보여주는 함수이다. 이것 말고도 .showAtCenter() 등 여러 함수들이 있는데 각각의 차이점은 메뉴 창을 어느 위치에 보여주는지에 있다.

이는 맨 위에 첨부한 깃 링크를 보면서 직접 테스트 해보면 이해하기 편한 것 같다. (본인 경우)

.showAsDropDown(view, x-off, y-off) 에서 x-off는 -값을 넣으면 뷰가 기존 위치에서 해당 값만큼 왼쪽에서 보이게 되고, y-off는 -를 넣으면 해당 값만큼 기존 위치에서 위쪽에서 보이게 된다.

 

 

여기까지는 공식 깃 링크를 보고 따라 만든 것이다. 근데 위의 방법을 사용하면 각 메뉴의 아이템들을 Factory class에서 정의 해주기 때문에 다른 메뉴를 보여줘야 하는 경우에는 다른 Factory class를 만들어줘야 하는 단점이 있다. 이렇게 되면 불필요한 코드들만 늘어날 뿐이다. 그래서 이러한 단점을 보완하는 방법을 찾아봤다.

 

차이점

팩토리 클래스를 object로 선언하였고, PowerMenu.Factory()를 상속하지 않았다. 그리고 함수의 인자로 보여줄 아이템 리스트를 받았다. 이렇게 하면 함수를 호출할 때 보여 줄 리스트를 넣어서 메뉴를 보여줄 수 있다.

object PowerMenuUtil {

    fun getPowerMenu(
        context: Context,
        lifecycleOwner: LifecycleOwner,
        items: List<PowerMenuItem>
    ): PowerMenu {
        return createPowerMenu(context) {
            addItemList(items)
            setWidth(350)
            setMenuRadius(8f)
            setLifecycleOwner(lifecycleOwner)
            setAnimation(MenuAnimation.SHOWUP_TOP_RIGHT)
            setTextColor(ContextCompat.getColor(context, R.color.black))
            setTextSize(12)
            setTextGravity(Gravity.LEFT)
            setMenuColor(Color.WHITE)
            setInitializeRule(Lifecycle.Event.ON_CREATE, 0)
        }
    }
}

PowerMenu.Factory()를 상속받으면 create 될 때 초기화가 되는데 위와 같이 선언하면 함수가 호출될 때 메뉴가 생성되는 차이점이 있다.

Activity

class MainActivity : AppCompatActivity() {

    private val moreMenu by powerMenu<MoreMenuFactory>()

    private val menuItems1 = listOf(PowerMenuItem("코"), PowerMenuItem("틀"), PowerMenuItem("린"))
    private val menuItems2 = listOf(PowerMenuItem("안"), PowerMenuItem("드"), PowerMenuItem("로"), PowerMenuItem("이"), PowerMenuItem("드"))

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val text1 = findViewById<TextView>(R.id.text1)
        val text2 = findViewById<TextView>(R.id.text2)
        val text3 = findViewById<TextView>(R.id.text3)

        text1.setOnClickListener {
            moreMenu.showAsDropDown(it, -300, 0)
        }

        text2.setOnClickListener {
            PowerMenuUtil.getPowerMenu(
                this,
                this,
                menuItems1
            ).showAsDropDown(text2, 0, 150)
        }

        text3.setOnClickListener {
            PowerMenuUtil.getPowerMenu(
                this,
                this,
                menuItems2
            ).showAsDropDown(text3, 0, 400)
        }
    }
}

위의 코드와 차이점은 메뉴가 생성되는 시점이다.

처음 방식을 사용하면 private val moreMenu by powerMenu<MoreMenuFactory>() 시점에서 생성이 되는데 두 번째 방식을 사용하면 PowerMenuUtil.getPowerMenu() 함수의 동작이 끝나는 시점에서 생성이 된다.

 

 

후기

기본적으로 제공되는 옵션 메뉴보다 좋다고 생각하였는데 이유는 다음과 같다. 

1. object로 선언하면 불필요하게 xml 파일들을 만들지 않아도 된다. (함수를 호출할 때 보여줄 리스트들만 바꿔서 넣어주면 되기 때문)

2. 보여지는 메뉴 창의 위치, 메뉴 창의 보여지는 애니메이션 효과 등 다양한 옵션들을 편리하게 정의할 수 있다. (커스텀 하기 더 편한거 같다!)

 

'Android' 카테고리의 다른 글

무한 스크롤  (0) 2023.09.18
RecyclerView 오류 해결 과정..  (0) 2023.08.08
Bottom Navigation View  (0) 2023.06.27
Timber Library  (1) 2023.06.04
Splash screen api  (0) 2023.06.01