비비디바비비부
프로그래밍저장소
비비디바비비부
전체 방문자
오늘
어제
  • 프로그래밍 (72)
    • 안드로이드 (5)
      • 잡다한 지식 (40)
      • Compose (2)
      • Design (3)
      • Project (6)
    • 리액트 (4)
      • 프로젝트 (1)
      • 잡다한 지식 (1)
    • 알고리즘 (3)
      • 알고리즘 문제 (3)
    • AI (4)
      • 딥러닝 (4)
    • CS (2)
    • 잡동사니 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
비비디바비비부

프로그래밍저장소

안드로이드/Design

안드로이드 BottomNavigationView 커스텀하기

2022. 10. 7. 13:40

CustomBottomNav

최종 이미지

image

 

코드


import com.google.android.material.bottomnavigation.BottomNavigationView
import android.content.Context
import android.util.AttributeSet
import androidx.core.content.ContextCompat
import android.graphics.*
import com.telefield.iot_user_app.R

class CustomBottomNavigationView : BottomNavigationView {
    private var mPath: Path = Path()
    private var mPaint: Paint = Paint()

    private val CURVE_CIRCLE_RADIUS = 190 / 2

    private val mFirstCurveStartPoint = Point()
    private val mFirstCurveEndPoint = Point()
    private val mFirstCurveControlPoint1 = Point()
    private val mFirstCurveControlPoint2 = Point()

    private var mSecondCurveStartPoint = Point()
    private val mSecondCurveEndPoint = Point()
    private val mSecondCurveControlPoint1 = Point()
    private val mSecondCurveControlPoint2 = Point()
    private var mNavigationBarWidth: Int = 0
    private var mNavigationBarHeight: Int = 0

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init()
    }

    constructor(context: Context) : super(context) {
        init()
    }

    private fun init() {
        mPaint.style = Paint.Style.FILL_AND_STROKE
        mPaint.color = ContextCompat.getColor(context, R.color.gray_100)
        mPaint.setShadowLayer(12F, 0F, 0F, Color.BLACK)
        setBackgroundColor(Color.TRANSPARENT)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        mNavigationBarWidth = width
        mNavigationBarHeight = height

        mFirstCurveStartPoint.set(
            mNavigationBarWidth / 2 - CURVE_CIRCLE_RADIUS * 2 - CURVE_CIRCLE_RADIUS / 3,
            0
        )
        mFirstCurveEndPoint.set(
            mNavigationBarWidth / 2,
            CURVE_CIRCLE_RADIUS + CURVE_CIRCLE_RADIUS / 4
        )
        mSecondCurveStartPoint = mFirstCurveEndPoint
        mSecondCurveEndPoint.set(
            mNavigationBarWidth / 2 + CURVE_CIRCLE_RADIUS * 2 + CURVE_CIRCLE_RADIUS / 3,
            0
        )

        mFirstCurveControlPoint1.set(
            mFirstCurveStartPoint.x + CURVE_CIRCLE_RADIUS + CURVE_CIRCLE_RADIUS / 4,
            mFirstCurveStartPoint.y
        )

        mFirstCurveControlPoint2.set(
            mFirstCurveEndPoint.x - CURVE_CIRCLE_RADIUS * 2 + CURVE_CIRCLE_RADIUS,
            mFirstCurveEndPoint.y
        )

        mSecondCurveControlPoint1.set(
            mSecondCurveStartPoint.x + CURVE_CIRCLE_RADIUS * 2 - CURVE_CIRCLE_RADIUS,
            mSecondCurveStartPoint.y
        )
        mSecondCurveControlPoint2.set(
            mSecondCurveEndPoint.x - (CURVE_CIRCLE_RADIUS + CURVE_CIRCLE_RADIUS / 4),
            mSecondCurveEndPoint.y
        )

        mPath.reset()
        mPath.moveTo(0F, 0F)
        mPath.lineTo(mFirstCurveStartPoint.x.toFloat(), mFirstCurveStartPoint.y.toFloat())

        mPath.cubicTo(
            mFirstCurveControlPoint1.x.toFloat(), mFirstCurveControlPoint1.y.toFloat(),
            mFirstCurveControlPoint2.x.toFloat(), mFirstCurveControlPoint2.y.toFloat(),
            mFirstCurveEndPoint.x.toFloat(), mFirstCurveEndPoint.y.toFloat()
        )

        mPath.cubicTo(
            mSecondCurveControlPoint1.x.toFloat(), mSecondCurveControlPoint1.y.toFloat(),
            mSecondCurveControlPoint2.x.toFloat(), mSecondCurveControlPoint2.y.toFloat(),
            mSecondCurveEndPoint.x.toFloat(), mSecondCurveEndPoint.y.toFloat()
        )

        mPath.lineTo(mNavigationBarWidth.toFloat(), 0F)
        mPath.lineTo(mNavigationBarWidth.toFloat(), mNavigationBarHeight.toFloat())
        mPath.lineTo(0F, mNavigationBarHeight.toFloat())
        mPath.close()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawRect(20F, 20F, 100F, 100F, mPaint)
        canvas.drawPath(mPath, mPaint)
    }
}

xml에서는 BottomNavigationView를 CustomBottomNavigationView로 변경하면 된다.

그림자를 제거하고 싶으면 init 함수에서 mPaint.setShadowLayer()과 onDraw 함수에서 canvas.drawRect() 부분을 지우면 된다.

 

참고로 가운데 버튼은 FloatingActionButton으로 만들었습니다.

저작자표시 비영리 동일조건 (새창열림)

'안드로이드 > Design' 카테고리의 다른 글

Figma로 앱 설계 (다크모드)  (0) 2023.03.02
android shared elements transition  (0) 2022.10.20
    '안드로이드/Design' 카테고리의 다른 글
    • Figma로 앱 설계 (다크모드)
    • android shared elements transition
    비비디바비비부
    비비디바비비부
    안드로이드 기술 블로그, 코딩 공부, 프로그래머

    티스토리툴바