본문 바로가기

카테고리 없음

#5.4 뷰 사용하기 2021-03-13

View는 화면을 구성하는 최소 단위의 컴포넌트라고 할 수 있습니다. 계층 구조로 나타낸다면 앱 > 액티비티 > 뷰그룹 > 뷰로 표시할 수 있습니다. (뷰 : 위젯, 뷰그룹 : 레이아웃이라고 할 수 있습니다. :))

TextView로 예를 들어보면 레이아웃 편집기에 <TextView>, <Button>같은 태그들은 태그 이름과 동일한 클래스들이 이미 안드로이드에 있습니다.
ex) open class TextView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : View(context, attrs, defStyleAttr) {  }인데 AttrivuteSet은 텍스트뷰 속성들을 의미하고 open키워드는 상속으로 확장 가능을 의미합니다. 또한 View클래스를 상속하기에 View를 직접 사용해보겠습니다.

 

4.1 뷰 클래스 다루기

위젯과 레이아웃의 최상위 클래스인 View는 화면에 그림을 그리기 위한 메서드를 가지고 있습니다.
텍스트뷰 위젯의 text 속성에 'hello'라고 입력하면 TextView는 부모 클래스인 View에 입력된 문자열을 전달하고, View는 문자열을 받아서 글자 크기, 색상, 위치 등을 결정하고 onDraw() 메서드를 사용해서 화면에 그려줍니다.
onDraw() 메서드의 사용법만 정확하게 이해한다면 원하는 위젯이 없어도 직접 만들어서 사용할 수 있습니다.

 

텍스트에 사용하는 Paint의 프로퍼티
color: 대상의 색상, 글자나 도형의 색상을 정의합니다.
textSize: 글자의 크기 drawText() 메서드일 경우만 사용합니다.

View에 텍스트 출력하기

[MainActivity.kt] (activity_main.xml에는 FrameLayout을 하나 생성하고, id는 frameLayout)

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

        val  customView: CustomView =  CustomView("안녕 코틀린!",this)
        var frameLayout: FrameLayout = findViewById<FrameLayout>(R.id.frameLayout)

        frameLayout.addView(customView)

    }
}

class CustomView(text: String, context: Context) : View(context) {
    val text: String
    init {
        this.text = text
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        // 페인트 변수 생성
        val paint = Paint()

        // paint 프로퍼티 색상, 글자 크기
        paint.color = Color.BLACK
        paint.textSize = 200f

        // drawText() 메서드
        canvas?.drawText(text, 0f, 500f, paint)

    }
}

 

VIew에 그림 그리기

  • color: 대상의 색상, 도형의 색상을 정의합니다.
     
  • style: 도형의 형태, 외곽선을 그리거나 면을 채우는 등의 모양을 정의합니다. 색상이 Color 클래스에 정의되어 있는 것처럼 사용할 스타일이 Style 클래스에 상수로 미리 정의되어 있습니다. Style.STROKE, Style.FILL, Style.STROKE_AND_FILL

 

1. drawCircle() : 원 그리기

val blue = Paint()
blue.style = Patin.Style.FILL
blue.color = Color.BLUE

// drawCirecle(x, y, radius, paint)
canvas?.drawCircle(150f, 300f, 100f, blue)

 

2. drawArc() : 원호 그리기

var red = Paint()
red.style = Paint.Style.STROKE
red.color = Color.RED

// drawArc(x, y, radius, paint)
canvas?.drawArc(400f, 300f, 100f, red)

 

3.  drawRect() : 사각형 그리기

val green = Paint()
green.style = Paint.Style.STROKE
green.color = Color.GREEN

// Rect(start_x, start_y, end_x, end_y)
val rect = Rect(50, 450, 250, 650)
canvas?.drawRect(rect, green)

 

4. drawRoundRect() : 라운드 사각형 그리기 (4개의 꼭짓점이 둥근 사각형)

val cyan = Paint()
cyan.style = Paint.Style.FILL
cyan.color = COlor.CYAN
val rectF = RectF(300f, 450f, 500f, 650f)

// drawRoundRect(RectF, radius_x, raduis_y, paint)
canvas?.drawRoundRect(RectF, 50f, 100f, cyan)

 

4.2 커스텀 위젯 만들기

보통 기업에서는 기본 위젯을 상속받아 접두어(prefix)를 붙여서 커스텀 위젯을 사용하는데, 커스터 마이징은 크게 세 단계로 진행됩니다.

 

1. attrs.xml 파일 생성

새로운 위젯을 생성하고 사용할 때 위젯 이름뿐만 아니라 속성의 이름과 입력되는 값의 타입을 정의하고 사용할 수 있도록 해줍니다.

<declare-styleable name="CustomWidget">
    <attr name="새로운 속성" format="string"/>
</declare-styleable>
<CustomWidget
    android:id="@+id/button"
    custom:새로운 속성="값"
    android:text="새로 만든 위젯"/>

 

2. 커스텀 위젯 클래스 생성

커스터마이징을 하기 위한 위젯 클래스를 상속받아 클래스를 생성하고 위에서 새롭게 정의한 속성을 처리하는 코드를 작성합니다.

class CustomView: Text {
	construction(context: Context, attrs: AttributeSet?, defStyleAttr: Int) 
    				: super(context, attrs, defSyyleAttr) {
    }
}

 

3. 레이아웃에 태그 적용

생성된 커스텀 클래스를 레이아웃 파일에 태그로 적용합니다. 커스텀 위젯은 컨스트레인트 레이아웃처럼 위젯 클래스의 패키지 경로면도 함께 입력해서 사용합니다.

<패키지명.CustomWidget
    android:id="@+id/button"
    custom:새로운 속성="값"
    android:text="새로 만든 위젯"/>

 

커스텀 TextView의 설계

text속성에 날짜입력 시 연월일을 구분('-'하이픈)하여 출력하는 위젯 생성해봅시다.

[attrs.xml]
[app] - [res] - [value] 마우스 우측 클릭 - [New] - [Value Resource File]

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomText">
        <attr name="delimeter" format="string"/>
    </declare-styleable>
</resources>
        <com.hellow.customview_4.CustomText
            android:id="@+id/customText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="com.hellow.customview_4.CustomText" />

(만약 custom 입력후 자동 완성 코드가 노출되지 않으면 안드로이드 스튜디오를 종료했다가 다시 시작하면 나옵니다 :))

 

[CustomText.kt]
[app] - [java] - [패키지명] 마우스 우측 클릭 - [New] - [Kotlin File/Class]

class CustomText : AppCompatTextView {
// 생성자 정의
    constructor(context: Context) : super(context) {
    }
    
    constructor(context: Context, attrs: AttributeSet)
            : super(context, attrs) {
        val typed = context.obtainStyledAttributes(attrs, R.styleable.CustomText)
        val size = typed.indexCount
        
        for (i in 0 until size) {
            when(typed.getIndex(i)) {
                R.styleable.CustomText_delimeter -> {
                    val delimeter = typed.getString(typed.getIndex(i)) ?: "-"
                    process(delimeter)
                }
            }
        }
    }
    
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) 
            : super(context, attrs, defStyleAttr) {
    }
    
    // process() 메서드
    fun process(delimeter: String) {
        var one = text.substring(0, 4)
        var two = text.substring(4, 6)
        var three = text.substring(6)
        
        setText("$one $delimeter $two $delimeter $three")
    }
}

 

[실행]

View : 화면에 보이는 모든 요소의 최상위 클래스입니다. 화면ㅇ에 무엇인가를 그리기 위해서는 View 클래스가 상속받아져 있어야 합니다.
onDraw() 메서드 : View 클래스가 화면에 텍스트를 출력하거나 그림을 그릴 때 호출하는 메서드입니다.
Canvas : onDraw() 메서드를 통해 전달되는 그리기 도구입니다. drawText(), drawCirecle(), 등의 메서드를 사용해서 화면에 그릴 수 있습니다.
Paint : 화면에 그려지는 요소들의 색상, 스타일, 굵기 정보 등을 정의하는 클래스입니다.
attrs_xml : 내가 만든 위젯에 새로운 속성을 정의할 때 사용되는 리소스 파일입니다.
custom : attrs.xml에 정의한 새로운 속성을 custom이라는 prefix로 레이아웃에 사용할 수 있습니다.

 

- 미니 퀴즈 5-4 -

1. 화면에서 보이는 위젯의 최상위 클래스는 무엇인가요?

답 : View

 

2. 컨스트레인트와 같은 뷰그룹의 최상위 클래스는 무엇인가요?

답 : View

 

3.  View 클래스에서 화면에 그림을 그릴 때 호출되는 메서드는 무엇인가요?

답 : onDraw( ) 메서드

 

4. 커스텀뷰 클래스를 하나 만들고 테두리는 빨간색, 배경색이 파란색인 라운드 사각형을 그려보세요.

5. 커스텀뷰 클래스를 하나 만들고 빨간색 도넛 모양을 STROKE 스타일을 사용하지 않고 만들어보세요.

답 : 

[MainActivity.kt]

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

        var layout = findViewById<LinearLayout>(R.id.linearLayout)
        layout.addView(CustomView(this))


    }
}


class CustomView(context: Context) : View(context) {
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

     // 페인트 변수 생성 및 빨간색 테두리 설정
        val paint = Paint()
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 20f
        paint.color = Color.RED

        // 빨간색 테두리 사각형 생성
        val rectf = RectF(50f, 300f, 400f, 450f)
        canvas?.drawRoundRect(rectf, 50f, 100f, paint)

        paint.style = Paint.Style.FILL
        paint.color = Color.BLUE

        // 파란색 배경의 사각형 생성
        val rectf2 = RectF(50f, 300f, 400f, 450f)
        canvas?.drawRoundRect(rectf2, 50f, 100f, paint)



        // 빨간색으로 채운 반지름 100f인 원 생성
        paint.color = Color.RED
        canvas?.drawCircle(500f, 500f, 100f, paint)

        // 하얀색으로 채운 반지름 50f인 원 생성
        paint.color = Color.WHITE
        canvas?.drawCircle(500f, 500f, 50f, paint)
    }
}