Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 커스텀 버튼 제작 #467

Merged
merged 21 commits into from
Nov 8, 2023
Merged

feat: 커스텀 버튼 제작 #467

merged 21 commits into from
Nov 8, 2023

Conversation

briandr97
Copy link
Collaborator

📌 관련 이슈

🛠️ 작업 내용

  • 커스텀 버튼 제작
  • 버튼 적용

🎯 리뷰 포인트

만든 버튼에 대해 설명 드리겠습니다.
제작한 커스텀 버튼은 presentation 하위의 custom 패키지를 만들고 그 곳에 두었습니다.

[버튼 색 추가하는법]

현재 노란색과 파란색만 존재해 두 가지만 넣어 놨습니다.
만일 다른 색을 추가하고 싶으시다면 두 가지 작업을 해주셔야 합니다.

  1. 아래 enum 클래스에 색을 추가합니다.
package com.now.naaga.presentation.custom

enum class GameButtonColor(
    val mainColor: String,
    val firstShadowColor: String,
    val middleColor: String,
    val secondShadowColor: String,
    val bottomColor: String,
) {
    YELLOW(
        "#FFD50C",
        "#E3A40A",
        "#FFB70A",
        "#FFEE9F",
        "#B68A21",
    ),
    BLUE(
        "#1BCCFF",
        "#009DDE",
        "#0CB4F9",
        "#AFEDFF",
        "#0D3A85",
    ), ;

    companion object {
        fun getColor(ordinal: Int): GameButtonColor {
            return values().find { it.ordinal == ordinal } ?: YELLOW
        }
    }
}
  1. attrs에 추가해줘야합니다
    res 하위의 values 패키지에 attrs 파일이 생겼습니다 해당 파일을 보면 아래와 같은 xml 코드가 존재합니다.
    새로 제작된 커스텀 버튼인 GameButton의 속성입니다.
    아래 예시처럼 새로운 색상을 넣어주시면 되겠습니다. (value에는 enum의 ordinal을 넣어주시면 됩니다!)
<declare-styleable name="GameButton">
    <attr name="radius" format="dimension" />
    <attr name="buttonColor" format="enum">
        <enum name="yellow" value="0" />
        <enum name="blue" value="1" />
        <enum name="새로운색상" value="2" />
    </attr>
</declare-styleable>

[버튼 속성]

버튼의 커스텀 속성으로는 radiusbuttonColor가 있습니다. nameSpace는 app입니다.
radius는 ??dp로 넣으시면 되고 buttonColor는 위의 방식으로 지정해줬던 enum을 입력하시면 됩니다. (enum이 자동완성에 뜹니다)

<com.now.naaga.presentation.custom.GameButton
    android:id="@+id/btn_beginAdventure_myPage"
    style="@style/BeginActivity.Text"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/beginAdventure_my_page"
    android:textSize="24sp"
    android:paddingVertical="20dp"
    app:radius="8dp"
    app:buttonColor="blue"
    app:layout_constraintStart_toEndOf="@id/btn_beginAdventure_upload"
    app:layout_constraintEnd_toEndOf="@id/btn_beginAdventure_begin"
    app:layout_constraintTop_toTopOf="@id/btn_beginAdventure_upload"
    app:layout_constraintBottom_toBottomOf="@id/btn_beginAdventure_upload" />

⏳ 작업 시간

추정 시간: 5h
실제 시간: 8h

Copy link
Collaborator

@krrong krrong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빅스 정말 고생많았습니다!
커스텀으로 만든 버튼 예쁘네요, 특히 클릭했을 때 명시적으로 눌렸다는 포인트를 준 것이 인상 깊었습니다. 수업에서 배운 것을 활용해본 것 대단하네요.
몇 가지 코멘트를 달아두었으니 확인해주세요!

  • 추가
    사용하지 않는 drawable 파일을 삭제해주세요!

0,
).apply {
radius = getDimensionPixelSize(R.styleable.GameButton_radius, 0).toFloat()
val gameButtonColor = GameButtonColor.getColor((getInteger(R.styleable.GameButton_buttonColor, 0)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3]
괄호 하나를 줄여도 되겠네요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 줄였습니다! 이걸 어떻게 보셨대 ㅋㅋ

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼼꼼히 리뷰합니다😎

middleColor = Color.parseColor(gameButtonColor.middleColor)
secondShadowColor = Color.parseColor(gameButtonColor.secondShadowColor)
bottomColor = Color.parseColor(gameButtonColor.bottomColor)
recycle()
Copy link
Collaborator

@krrong krrong Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P5]
recycle() 메서드는 어떤 역할을 하나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 자세히 알아보고 쓰진 않았습니다. 공식 문서 및 대부분의 레퍼런스에서 이렇게 사용하고 있습니다.

TypedArray 객체는 공유 리소스이며 사용 후 재활용해야 합니다.

}

private val ripplePaint = Paint().apply {
this.color = Color.parseColor("#4D000000")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2]
눌렸을 때의 색상이 변경되도록 만든 것이 더 게임틱하게 만들어준 것 같네요!
어떤 색상인지 숫자를 보고 알기는 어려워서 색상을 colors 로 옮기는 것도 좋아보입니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리소스화 했습니다.


class GameButton(context: Context, attrs: AttributeSet? = null) : AppCompatButton(context, attrs) {
private val radius: Float
private var clicked: Boolean = false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3]
Boolean 타입을 저장하는 변수라면 변수명을 isClicked로 변경하는 것은 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변경했습니다.

Comment on lines 82 to 87
canvas.drawRoundRect(getBottomRect(), radius, radius, getPaint(bottomColor))
canvas.drawRoundRect(getSecondShadowRect(), radius, radius, getPaint(secondShadowColor))
canvas.drawRoundRect(getMiddleRect(), radius, radius, getPaint(middleColor))
canvas.drawRoundRect(getFirstShadowRect(), radius, radius, getPaint(firstShadowColor))
canvas.drawRoundRect(getMainRect(), radius, radius, getPaint(mainColor))
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P4]
함수의 호출 순서대로 아래 함수들을 정렬해수시면 리뷰하는데 조금 더 수월할 것 같네요 👍
추가로 Main, FirstShadow, MiddleRect, SecondShadowRect 가 어느 부분인지 알려주시면 좋을 것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

호출 순서대로 변경하였습니다.
호출 순서대로 아래부터 쌓이게 되는데요, 이는 그림을 보면서 이해하는 것이 좋을 것 같아서 피그마에서 각 컴포넌트 네이밍을 함수 네이밍과 일치시켜놓았습니다!
더 좋은 변수 및 함수명이 있다면 추천해주시면 감사하겠습니다.

Copy link
Collaborator Author

@briandr97 briandr97 Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 확실히 호출 순서와 그림을 첨부해주시니 이해가 바로바로 되네요 :)
저는 변수명을 짓는데 큰 어려움을 겪는 한 사람으로서.. 빅스의 네이밍이 맘에 듭니다!

Comment on lines 11 to 16
"#FFD50C",
"#E3A40A",
"#FFB70A",
"#FFEE9F",
"#B68A21",
),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3]
Colors로 빼는 것 보다는 여기에 둔 이유가 있을 것 같은데, 그 이유가 궁금합니다.
추가로 String이 아닌 Int를 갖도록 하고 @ColorInt 애노테이션을 추가하여 어떤 값이 들어갈지 예상할 수 있도록 만들어보는 것은 어떨까요?
Int값을 그대로 갖는다면 GameButton에서 사용하고 있는 Color.parseColor() 메서드를 사용하지 않아도 될 것 같아요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리소스화 하지 않았던 것은 한 버튼에 다섯 가지 색이 들어가는데 대부분 프로젝트의 다른 컴포넌트에서는 사용하지 않을 것 같았기 때문입니다. 저는 개인적으로 뭐든 상관 없다고 생각하기에 크롱은 리소스화를 원하는 것 같아 그렇게 변경하였습니다. (다크 모드 대응 시 버튼 색도 변경된다면 리소스화가 필요하긴 하겠네요!)

enum class에서 @ColorRes 형태로 갖게 하고, 버튼 내에서 @ColorInt 형태로 갖도록 했습니다!

Copy link
Collaborator

@hyunji1203 hyunji1203 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

버튼 입체갑 느껴지고 조은데요?
빅스 수제 버튼 제작 고생많았어요👍
크롱이 남긴 부분 제외하고 리뷰 남긴거라, 딱 1개의 리뷰만 추가했습니다!
이 부분도 확인 후 빅스가 반영하고 싶으면 하면 되는 부분이라 빅스의 결정에 맡길께요!

Comment on lines 82 to 86
canvas.drawRoundRect(getBottomRect(), radius, radius, getPaint(bottomColor))
canvas.drawRoundRect(getSecondShadowRect(), radius, radius, getPaint(secondShadowColor))
canvas.drawRoundRect(getMiddleRect(), radius, radius, getPaint(middleColor))
canvas.drawRoundRect(getFirstShadowRect(), radius, radius, getPaint(firstShadowColor))
canvas.drawRoundRect(getMainRect(), radius, radius, getPaint(mainColor))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P5]

Suggested change
canvas.drawRoundRect(getBottomRect(), radius, radius, getPaint(bottomColor))
canvas.drawRoundRect(getSecondShadowRect(), radius, radius, getPaint(secondShadowColor))
canvas.drawRoundRect(getMiddleRect(), radius, radius, getPaint(middleColor))
canvas.drawRoundRect(getFirstShadowRect(), radius, radius, getPaint(firstShadowColor))
canvas.drawRoundRect(getMainRect(), radius, radius, getPaint(mainColor))
with(canvas) {
drawRoundRect(getBottomRect(), radius, radius, getPaint(bottomColor))
drawRoundRect(getSecondShadowRect(), radius, radius, getPaint(secondShadowColor))
drawRoundRect(getMiddleRect(), radius, radius, getPaint(middleColor))
drawRoundRect(getFirstShadowRect(), radius, radius, getPaint(firstShadowColor))
drawRoundRect(getMainRect(), radius, radius, getPaint(mainColor))
}

with를 사용해서 반복을 줄일 수 있을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다.

}

private fun getMiddleRect(): RectF {
val middleWidth = (width * 0.987).toFloat()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 그 말로만 듣던 수제 계산 공식...👍

Copy link
Collaborator

@hyunji1203 hyunji1203 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빅스! 고생많았어요!
해당 PR에서는 더이상 수정할 사항이 없는 것 같아 이만 approve 하도록 하겠습니다!
수제 계산으로 제작된 커스텀 버튼 야무지네요👍

Comment on lines +91 to +95
private fun isClickInsideButton(point: Point): Boolean {
val isXInside = point.x in 0..this.width
val isYInside = point.y in 0..this.height
return isXInside && isYInside
}
Copy link
Collaborator

@hyunji1203 hyunji1203 Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

높이와 넓이 범위 안에 들어오는 것을 판별해 터치 영역 기능을 제한했군요?! 좋네요 👍👍
(이미 어프로브 한 상태고 더 리뷰할건 없어서 그대로 어프로브 갈깁니다!)

Copy link
Collaborator

@krrong krrong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커스텀 버튼 덕분에 더 게임틱해져서 좋은 것 같네요!!
고생했습니다! 빅스 :)

@krrong krrong merged commit 4a69bdf into dev_android Nov 8, 2023
3 checks passed
@krrong krrong deleted the feat/#466-custom_button branch November 8, 2023 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants