관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] BorderEditText 커스텀 EditText 라이브러리 배포 본문

안드로이드/오픈소스 컨트리뷰션

[안드로이드] BorderEditText 커스텀 EditText 라이브러리 배포

막무가내막내 2021. 2. 3. 22:34
728x90

 

 

[BorderEditText 라이브러리 저장소]

github.com/mtjin/BorderEditText

 

mtjin/BorderEditText

It is an Android Custom EditText Library that allows you to easily set the background color of EditText, the color of the border, the thickness, the radius, and the state when it is focused - mtjin...

github.com

 

 

[내용] 

youngest-programming.tistory.com/250?category=940679

 

[코틀린] 안드로이드 JITPACK 에 오픈소스 라이브러리(DrawView) 배포 & ChocoBar 컨트리뷰션 경험

1. 오픈소스 DrawView 배포 경험 라이브러리를 한번 배포해보고 싶다고 예전부터 생각했었는데 드디어 배포 경험을 했봤네요. ㅎㅎ 졸업 프로젝트에도 필요한 기능이라 커스텀뷰를 구현하고 모듈

youngest-programming.tistory.com

이전의 오픈소스 컨트리뷰션에 이어서 이번에 안드로이드 BorderEditText 라는 EditText를 커스텀한 라이브러리를 만들어서 배포해 봤습니다. 

 

평소 안드로이드 개발을 할 때 shape, selector 같은 drawable 리소스들을 만들텐데 프로젝트 규모가 커지면 다수의 색, radius, 테두리두께 등으로 파일명 짓기도 힘들고 drawable xml 파일들이 많아져 리소스관리가 힘들어진다는 단점이 있었습니다.

 

그래서 selector, shape와 같은 drawable 리소스를 따로 만들지 않고 xml이나 코드로 처리할 수 있게 하는 라이브러리를 만들면 좋을 것 같아 개발해봤습니다. 

이런 라이브러리가 있을 줄 알고 구글링 좀 했는데 없더라고요 (제가 못찾은거 일수도 있습니다 :(  )

 

요약...

평소 shape xml 리소스를 만들어 background로 xml을 세팅하던 것을 라이브러리로 간편하게 xml 이나 프로그래밍으로 기본적인 것들은 대체할 수 있고 selector xml 리소스의 focused 상태에 따른 분기처리도 대체할 수 있습니다 .

 

자세한 사항들은 라이브러리 README.md 에 적어놨습니다. 

 

P.S ...

하면서 시간을 좀 잡아먹었던 부분은 selector 를 대체하는 기능을 구현하는 것이었는데 스택오버플로우의 예제를 보고 밑과 같이 normal(기본) EditText는 intArrayOf()를 비워줘서 구현했는데 focused 상태가 계속 먹질 않았다.. Focused State와 순서를 바꿔보았지만 해결이 되지 않았다. 빈 intArrayOf가 범주가 다 차지해서 이걸로만 적용이 되는 것 같다.

 

저 normal state의 intArrayOf() 즉 속성 상태값(state) 을 StateSet.WILD_CARD 로 수정함으로 해결했다. 이 상태값의 의미는 와일드 카드의 의미는 다음과 같다. 모든 StateSet과 일치하는 상태 입니다.

 

 

나머지 전체 코드는 다음과 같습니다.

[BorderEditText]

class BorderEditText(context: Context, attrs: AttributeSet?) :
    androidx.appcompat.widget.AppCompatEditText(context, attrs) {
    private var mContext: Context = context
    private var mBorderEditState: BorderEditState = BorderEditState()
    private var mFocusedBorderEditState: FocusedBorderEditState = FocusedBorderEditState()

    init {
        attrs?.let { initBorderState(it) }
        initShape()
    }

    // init BorderState class
    private fun initBorderState(atr: AttributeSet) {
        val typedArray =
            mContext.theme.obtainStyledAttributes(atr, R.styleable.BorderEditText, 0, 0)
        typedArray.run {
            //normal state
            val borderWidth =
                getDimension(R.styleable.BorderEditText_border_stroke_width, 0f).toInt()
            val borderRadius = getDimension(R.styleable.BorderEditText_border_corner_radius, 0f)
            val borderColor = getString(R.styleable.BorderEditText_border_stroke_color)
            val backGroundColor =
                getString(R.styleable.BorderEditText_border_background_color)
            mBorderEditState = BorderEditState(
                borderStrokeWidth = borderWidth,
                borderCornerRadius = borderRadius,
                borderStrokeColor = borderColor,
                backGroundColor = backGroundColor
            )

            //pressed state
            val pressedBorderWidth =
                getDimension(R.styleable.BorderEditText_border_focused_stroke_width, 0f).toInt()
            val pressedBorderRadius =
                getDimension(R.styleable.BorderEditText_border_focused_corner_radius, 0f)
            val pressedBorderColor =
                getString(R.styleable.BorderEditText_border_focused_stroke_color)
            val pressedBackGroundColor =
                getString(R.styleable.BorderEditText_border_focused_background_color)
            val pressedState =
                getBoolean(R.styleable.BorderEditText_border_focused_activated, false)
            mFocusedBorderEditState = FocusedBorderEditState(
                borderStrokeWidth = pressedBorderWidth,
                borderCornerRadius = pressedBorderRadius,
                borderStrokeColor = pressedBorderColor,
                backGroundColor = pressedBackGroundColor,
                pressedState = pressedState
            )
        }
    }

    // init and set shape drawable
    private fun initShape() {
        //pressed state border color (selector drawable xml)
        val stateShape = StateListDrawable()
        //pressed state
        if (mFocusedBorderEditState.mIsFocusedActivated) {
            stateShape.addState(
                intArrayOf(
                    android.R.attr.state_focused
                ), createPressedBorderEditState()
            )
        }
        //normal state
        stateShape.addState(
            StateSet.WILD_CARD, createBorderEditState()
        )
        //apply
        this.background = stateShape
        invalidate()
    }

    //normal state drawable
    private fun createBorderEditState(): GradientDrawable {
        val shape = GradientDrawable()
        //shape shape
        shape.shape = GradientDrawable.RECTANGLE
        //shape corner radius
        mBorderEditState.mBorderCornerRadius.let {
            shape.cornerRadii = floatArrayOf(it, it, it, it, it, it, it, it)
        }
        //shape stroke
        shape.setStroke(
            mBorderEditState.mBorderStrokeWidth,
            mBorderEditState.mBorderStrokeColor
        )
        //shape background color
        shape.setColor(mBorderEditState.mBackGroundColor)
        return shape
    }

    //pressed state drawable
    private fun createPressedBorderEditState(): GradientDrawable {
        val shape = GradientDrawable()
        //shape shape
        shape.shape = GradientDrawable.RECTANGLE
        //shape corner radius
        mFocusedBorderEditState.mBorderCornerRadius.let {
            shape.cornerRadii = floatArrayOf(it, it, it, it, it, it, it, it)
        }
        //shape stroke
        shape.setStroke(
            mFocusedBorderEditState.mBorderStrokeWidth,
            mFocusedBorderEditState.mBorderStrokeColor
        )
        //shape background color
        shape.setColor(mFocusedBorderEditState.mBackGroundColor)
        return shape
    }

    fun setBorderRadius(radius: Float) {
        mBorderEditState.mBorderCornerRadius = radius
        initShape()
    }

    fun getBorderRadius() = mBorderEditState.mBorderCornerRadius


    fun setBackgroundColor(color: String) {
        mBorderEditState.mBackGroundColor = Color.parseColor(color)
        initShape()
    }

    fun getBackgroundColor() = mBorderEditState.mBackGroundColor

    fun setBorderStrokeWidth(width: Int) {
        mBorderEditState.mBorderStrokeWidth = width
        initShape()
    }

    fun getBorderStrokeWidth() = mBorderEditState.mBorderStrokeWidth

    fun setBorderStrokeColor(color: String) {
        mBorderEditState.mBorderStrokeColor = Color.parseColor(color)
        initShape()
    }

    fun getBorderStrokeColor() = mBorderEditState.mBorderStrokeColor

    fun setFocusedBorderRadius(radius: Float) {
        mFocusedBorderEditState.mBorderCornerRadius = radius
        initShape()
    }

    fun getFocusedBorderRadius() = mFocusedBorderEditState.mBorderCornerRadius


    fun setFocusedBackgroundColor(color: String) {
        mFocusedBorderEditState.mBackGroundColor = Color.parseColor(color)
        initShape()
    }

    fun getFocusedBackgroundColor() = mFocusedBorderEditState.mBackGroundColor

    fun setFocusedBorderStrokeWidth(width: Int) {
        mFocusedBorderEditState.mBorderStrokeWidth = width
        initShape()
    }

    fun getFocusedBorderStrokeWidth() = mFocusedBorderEditState.mBorderStrokeWidth

    fun setFocusedBorderStrokeColor(color: String) {
        mFocusedBorderEditState.mBorderStrokeColor = Color.parseColor(color)
        initShape()
    }

    fun getFocusedBorderStrokeColor() = mFocusedBorderEditState.mBorderStrokeColor

    fun setFocusedState(state: Boolean) {
        mFocusedBorderEditState.mIsFocusedActivated = state
        initShape()
    }

    fun getFocusedState() = mFocusedBorderEditState.mIsFocusedActivated
}

 

[FocusEditState] 

package com.mtjin.library

import android.graphics.Color

class FocusedBorderEditState() {
    var mBorderCornerRadius: Float = 0f
    var mBorderStrokeColor: Int = Color.parseColor("#00000000")
    var mBorderStrokeWidth: Int = 0
    var mBackGroundColor: Int = Color.parseColor("#00000000")
    var mIsFocusedActivated: Boolean = false // is user applied pressed state

    constructor(
        borderCornerRadius: Float,
        borderStrokeColor: String?,
        borderStrokeWidth: Int,
        backGroundColor: String?,
        pressedState: Boolean
    ) : this() {
        this.mBorderCornerRadius = borderCornerRadius
        borderStrokeColor?.let { this.mBorderStrokeColor = Color.parseColor(it) }
        this.mBorderStrokeWidth = borderStrokeWidth
        backGroundColor?.let { this.mBackGroundColor = Color.parseColor(it) }
        this.mIsFocusedActivated = pressedState
    }

}

 

 

[BorderEditState]

import android.graphics.Color

class BorderEditState() {
    var mBorderCornerRadius: Float = 0f
    var mBorderStrokeColor: Int = Color.parseColor("#00000000")
    var mBorderStrokeWidth: Int = 0
    var mBackGroundColor: Int = Color.parseColor("#00000000")

    constructor(
        borderCornerRadius: Float,
        borderStrokeColor: String?,
        borderStrokeWidth: Int,
        backGroundColor: String?
    ) : this() {
        this.mBorderCornerRadius = borderCornerRadius
        borderStrokeColor?.let { this.mBorderStrokeColor = Color.parseColor(it) }
        this.mBorderStrokeWidth = borderStrokeWidth
        backGroundColor?.let { this.mBackGroundColor = Color.parseColor(it) }
    }


}

 

나중에 토이프로젝트로 만든 충남대 컴공앱에 게시판 작성 EditText에 제가 만든 라이브러리를 적용해볼까 생각 중 이다. 둥글게 보이는 EditText 효과와 Focusing 줬을 때 하늘색 테두리 생기게 말이지 ..

==> [2021-02-04] 적용했습니다.

 

 

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!!

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
Comments