와챠의 우당탕탕 코딩 일기장

[Android/Kotlin]Custom View 만들기/Spinner처럼 생긴 TextView 만들기/ClickListener 추가 본문

코딩 일기장/Android(Kotlin)

[Android/Kotlin]Custom View 만들기/Spinner처럼 생긴 TextView 만들기/ClickListener 추가

minWachya 2022. 3. 20. 16:47
반응형

아래 UI는 "동네 고영희" 앱 UI입니다!

선택 전: 힌트 보이기
선택 후

1, CustomView의 layout 생성

res>layout>custom_spinner_text_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/custom_text_view"
        style="@style/Widget.AppCompat.EditText"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:textSize="16sp"
        android:fontFamily="@font/spoqa_han_sans_neo_regular"
        android:backgroundTint="@color/beige_E3DECF"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_spinner_drop_down_arrow"
        android:layout_marginEnd="26dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

2, res>values>attrs.xml(없으면 생성)

내가 필요한 속성은 TextView에서 사용할 hint와

스피너(처럼 생긴 TextView)에서 선택한 값을 보이기 위한 text 속성이었다.

 

나머지 글씨 크기니 폰트니 하는 속성은 공통적이라 위 xml에서 지정해줌.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--Spinner 처럼 생긴 TextView-->
    <declare-styleable name="CustomSpinnerTextView">
        <attr name="text" format="reference|string" />
        <attr name="hint" format="reference|string" />
    </declare-styleable>
</resources>

 

3, CustomView를 생성할 Class 만들기

package com.example.dongnaegoyang.custom

import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.example.dongnaegoyang.R

// CatAdd2, 3에 쓰이는 Spinner 처럼 생긴 TextView
class CustomSpinnerTextView : ConstraintLayout {
    // 커스텀 뷰 안에 들어가는 아이템
    lateinit var textView : TextView

    // 생성자
    constructor(context: Context?) : super(context!!){
        init(context)
    }
    constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs){
        init(context)
        getAttrs(attrs)
    }

    // 초기화
    private fun init(context:Context?) {
        val view = LayoutInflater.from(context).inflate(R.layout.custom_spinner_text_view,this,false)
        addView(view)
        textView = view.findViewById(R.id.custom_text_view)
    }

    // 속성 가져오기
    private fun getAttrs(attrs: AttributeSet?){
        val typedArray = context.obtainStyledAttributes(attrs,
            R.styleable.CustomSpinnerTextView)
        setTypeArray(typedArray)
    }

    // 속성 사용하기
    private fun setTypeArray(typedArray : TypedArray) {
        // 텍스트 내용: CustomSpinnerTextView 이름으로 만든 attrs.xml 속성중 text 참조
        val text = typedArray.getText(R.styleable.CustomSpinnerTextView_text)
        textView.text = text

        // 텍스트 힌트: CustomSpinnerTextView 이름으로 만든 attrs.xml 속성중 hint 참조
        val hint = typedArray.getText(R.styleable.CustomSpinnerTextView_hint)
        textView.hint = hint

        typedArray.recycle()
    }
}

완성~~~~~^___________________^

 

4, CustomView 사용하기!

나는 CustomSpinnerTextView를 custom 폴더 안에서 만들어서 class 명 앞에 custom이 붙은 거다!!

내가 만든 속성을 사용하고 싶으면 app:속성명 <이렇게 사용하면 된다.

<com.example.dongnaegoyang.custom.CustomSpinnerTextView
    android:id="@+id/foodSpinner"
    app:hint="@string/cat_add_food_hint"
    android:layout_column="1"
    android:layout_row="1"
    android:layout_gravity="fill_horizontal"
    android:layout_height="55dp"/>

class 안에서 커스텀 속성을 사용하고 싶으면...그냥 view.속성명 <이렇게 접근하면 된다.

요로코롬

binding.foodSpinner.textView.setOnClickListener { foodBottomSheetDialog.show() }

 

(+4. ClickListener 추가)

클릭 리스너를 위와 같이 추가해줘도 동작은 되지만,,, 다른 방법도 소개하려 한다.

CustomSpinnerTextView,kt

위와 달라진 점은 

  1. View.OnClickListener 상속
  2. onCustomSTViewClick 함수를 포함한 OnCustomSTViewClickListener 인터페이스 추가
  3. 위 인터페이스 타입의 변수 myOnCustomSTViewClickListener 추가
  4. 초기화 시 클릭 리스너 달기
  5. OnClick 오버라이드

이다.

package com.example.dongnaegoyang.custom

import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.example.dongnaegoyang.R

// CatAdd2, 3에 쓰이는 Spinner 처럼 생긴 TextView
class CustomSpinnerTextView : ConstraintLayout, View.OnClickListener  {
    // 커스텀 뷰 안에 들어가는 아이템
    lateinit var textView : TextView
    // 믈릭 리스너
    private var myOnCustomSTViewClickListener: OnCustomSTViewClickListener? = null
    
    // 클릭 리스너를 전달할 함수를 담은 인터페이스
    interface OnCustomSTViewClickListener { fun onCustomSTViewClick(view: View?) }
    // 전달받은 클릭 리스너 달기
    fun setOnCustomSTViewClickListener(mListener: OnCustomSTViewClickListener) {
        myOnCustomSTViewClickListener = mListener
    }

    // 생성자
    constructor(context: Context?) : super(context!!){
        init(context)
    }
    constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs){
        init(context)
        getAttrs(attrs)
    }

    // 초기화
    private fun init(context:Context?) {
        val view = LayoutInflater.from(context).inflate(R.layout.custom_spinner_text_view,this,false)
        addView(view)
        textView = view.findViewById(R.id.custom_text_view)

        textView.setOnClickListener(this@CustomSpinnerTextView)
    }

    // 속성 가져오기
    private fun getAttrs(attrs: AttributeSet?){
        val typedArray = context.obtainStyledAttributes(attrs,
            R.styleable.CustomSpinnerTextView)
        setTypeArray(typedArray)
    }

    // 속성 사용하기
    private fun setTypeArray(typedArray : TypedArray) {
        // 텍스트 내용: CustomSpinnerTextView 이름으로 만든 attrs.xml 속성중 text 참조
        val text = typedArray.getText(R.styleable.CustomSpinnerTextView_text)
        textView.text = text

        // 텍스트 힌트: CustomSpinnerTextView 이름으로 만든 attrs.xml 속성중 hint 참조
        val hint = typedArray.getText(R.styleable.CustomSpinnerTextView_hint)
        textView.hint = hint

        typedArray.recycle()
    }

    // 클릭 효과 방샐
    override fun onClick(v: View?) {
        myOnCustomSTViewClickListener!!.onCustomSTViewClick(v)
    }
}

 

아까의 쿨릭 리스너를 적용한 코드가 이렇게 변한다.

binding.genderSpinner.setOnCustomSTViewClickListener(object : CustomSpinnerTextView.OnCustomSTViewClickListener {
    override fun onCustomSTViewClick(view: View?) { genderBottomSheetDialog.show() }
})

드뎌드뎌 CstomView를 만들어서 사용해봤다.

내가 만들어야 하는 view는 위와 같았다.

 

밑줄이 있고 + spinner의 삼각형 부분만 색이 다르고 + hint가 있는 스피너 부분...!!!

 

그냥 냅다 Spinner로 만들었더니 생긴 문제점

  • Spinner에는 hint 속성이 없음
  • spinner array를 보여주는 부분을 기존 spinner에서 제공해주는 것을 사용하지 않음
    • (BottomSheetDialog로 spinner array를 보여야 했다.)

 

그래서 그냥 TextView로 만들었더니 생긴 문제점

  • TextView에 underline + spinner drop down arrow button 필요
    • =>style="@style/Widget.AppCompat.Spinner.Underlined" 사용해서 해결
  • Spinner drop down arrow button 색만 변경해야 하는데 "android:backgroundTint="@color/~" 방식을는 underline과 down button 모두의 색을 바꿈

그래서 어떻게 만들까 하다가 어짜피 다른 곳에도 사용되는 View이니 결국 Custom 하게 됐다.

 

TextView에 underline은

style="@style/Widget.AppCompat.EditText"

이거 써서 해결

 

drop down arrow button color는 그냥 이미지 사용해서 해결^_______________^


참고

https://leejieun1121.github.io/android/Android-CustomView-%EB%A7%8C%EB%93%A4%EA%B8%B0(kotlin)/ 

 

Android CustomView 만들기(kotlin)

Android CustomView

leejieun1121.github.io

https://gun0912.tistory.com/38

 

[안드로이드/Android]CustomView를 만들어서 재사용하기

이전 포스팅에서 Style테마를 이용하여 일정한 레이아웃의 속성을 만들고 이를 재사용하는 방법에 대해서 알아 보았습니다. [안드로이드]style테마 활용으로 노가다코딩 줄이는 방법 이 방법보다

gun0912.tistory.com

 

 

반응형
Comments