안드로이드/이론

[ 안드로이드 ] 외부 라이브러리 커스텀하기

dongx._.2 2022. 9. 26. 02:26

 

https://github.com/tlaabs/TimetableView

 

GitHub - tlaabs/TimetableView: Android Library that creates simple timetable.

Android Library that creates simple timetable. Contribute to tlaabs/TimetableView development by creating an account on GitHub.

github.com

시간표를 구현하기 위해 위의 라이브러리를 선택 했으나, 위의 라이브러리에는 몇 가지 지원 안되는 기능이 있었다.

  1. 테이블 헤더 높이 조절 불가
  2. 폰트 및 글자 크기 조절 불가
  3. 시간표 색상 선택 불가 (기본 컬러 조합으로 세팅 되어있음)

 위의 기능들을 추가하기 위해 라이브러리 클래스를 상속받은 후 구현해보려고 했지만, 주요 메소드들이 private로 선언 되어있어서 상속으론 해결 불가

 

라이브러리 코드가 별로 길지 않아서 복사해서 새로 클래스를 만들기로 결정

 

수정 코드

 

1. 테이블 헤더 높이 조절

/** 테이블 헤더(맨 윗 줄) 생성 메소드 */
    private fun createTableHeader() {
        val tableRow = TableRow(context)
        tableRow.layoutParams = createTableLayoutParam()

        for (i in 0 until columnCount) {
            val tv = TextView(context)
            if (i == 0) { // 제일 첫 번째 칸은 모서리칸
                tv.layoutParams = createTableRowParam(sideCellWidth, LayoutParams.WRAP_CONTENT)  // -> 수정 1
            } else {
                tv.layoutParams = createTableRowParam(LayoutParams.WRAP_CONTENT)                 // -> 수정 2
            }

            tv.setTextColor(resources.getColor(R.color.colorHeaderText))
            tv.setTextSize(
                TypedValue.COMPLEX_UNIT_DIP,
                DEFAULT_HEADER_FONT_SIZE_DP.toFloat()
            )
            tv.text = headerTitle[i]
            tv.gravity = Gravity.CENTER

            tableRow.addView(tv)
        }
        tableHeader!!.addView(tableRow)
    }

 

테이블의 헤더는 createTableHeader() 라는 메소드에서 생성되도록 되어있었다. 구조를 보니 TableRow에다가 TextView를 삽입하는 방식이었다.

 

즉, TextView의 높이에 따라 테이블 헤더의 높이가 결정되는 것

 

기존엔 cellHeight로 제목이 아닌 다른 칸들의 높이와 동일하게 생성하도록 되어 있었다. 이를 WRAP_CONTENT로 바꿔서 테이블 헤더의 높이만 TextView의 높이에 맞추도록 변경

 

2. 폰트 및 글자 크기 조절

@SuppressLint("ResourceAsColor")
    private fun add(schedules: ArrayList<Schedule>, specIdx: Int) {
        val count = if (specIdx < 0) ++stickerCount else specIdx
        val sticker = Sticker()
        for (schedule in schedules) {
            val tv = TextView(context)
            val param = createStickerParam(schedule)

            tv.layoutParams = param
            tv.setPadding(10, 0, 10, 0)

            /**
             * TextView의 BufferType를 SPANNABLE로 설정
             * 미리 text를 지정해놓고 그 후에 SpannableStringBUilder로 바꿔줘야 스타일이 바뀜
             * */

            val str = """
                ${schedule.classTitle}
                ${schedule.classPlace}                                
            """.trimIndent()

            tv.setText(str, TextView.BufferType.SPANNABLE)    // 중요 !!

            val builder = SpannableStringBuilder(str)
            builder.setSpan(StyleSpan(Typeface.BOLD), 0, schedule.classTitle.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            builder.setSpan(AbsoluteSizeSpan(dp2Px(10)), schedule.classTitle.length+1, str.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

            tv.text = builder

            tv.setTextColor(com.example.lab.R.color.black_gray)
            tv.setTextSize(
                TypedValue.COMPLEX_UNIT_DIP,
                DEFAULT_STICKER_FONT_SIZE_DP.toFloat()
            )

            tv.setOnClickListener {
                if (stickerSelectedListener != null) stickerSelectedListener!!.OnStickerSelected(
                    count,
                    schedules
                )
            }

            sticker.addTextView(tv)
            sticker.addSchedule(schedule)
            stickers[count] = sticker
            stickerBox!!.addView(tv)
        }
        setStickerColor()
    }

위의 메소드는 시간표에 수업(스티커)를 추가하는 메소드다. 수업의 제목과 장소가 TextView 하나에 들어가는 구조여서 폰트나 크기를 따로 변경할 수가 없었다.

 

TextView의 일부분만 변경할 땐 SpannableStringBuilder를 많이 사용한다.

 

SpannableStringBuilder로 TextView의 텍스트를 변경할 땐 TextView의 buffertype 속성이 spannable로 되어있어야하는데, 동적으로 생성하다보니 xml 상에서 지정할 수 없는 상황 TextView의 속성 메소드로 buffertype을 지정할 수 있을 줄 알고 찾아봤는데 없었다.

 

따로 지정 메소드가 있는게 아니라 setText에서 파라미터로 bufferType을 전달받는 형태로 되어있었다.

 

임의의 텍스트를 할당해주고, bufferType을 지정해준다.

val builder = SpannableStringBuilder(str)
builder.setSpan(StyleSpan(Typeface.BOLD), 0, schedule.classTitle.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
builder.setSpan(AbsoluteSizeSpan(dp2Px(10)), schedule.classTitle.length+1, str.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

tv.text = builder

 

위와 같이 bufferType을 먼저 지정하고 그 후 SpannableStringBuilder로 변경해줘야한다