관리 메뉴

나만을 위한 블로그

[Manifest-Android] 40. 커스텀 뷰 생성자에서 @JvmOverloads 사용 시 주의점 본문

스터디

[Manifest-Android] 40. 커스텀 뷰 생성자에서 @JvmOverloads 사용 시 주의점

참깨빵위에참깨빵_ 2025. 7. 29. 23:17
728x90
반응형

코틀린의 @JvmOverloads는 함수 or 클래스에서 오버로드된 여러 메서드, 생성자를 자동 생성해서 코틀린, 자바 간 상호 운용성을 단순화하는 기능이다. 자바가 기본 인수를 기본적으로 지원하지 않아서 코틀린의 기본 인수가 관련된 경우 유용하다.

@JvmOverloads를 사용하면 코틀린 컴파일러는 컴파일된 바이트코드에서 기본값을 가진 매개변수의 모든 가능한 조합을 나타내기 위해 여러 메서드 또는 생성자 시그니처를 컴파일 타임에 자동적으로 생성한다.

하지만 커스텀 뷰를 구현할 때 @JvmOverloads를 신중하게 사용하지 않으면 의도치 않게 기본 뷰 스타일을 재정의해서 커스텀 뷰에서 의도했던 스타일이 손실될 수 있다. Button, TextView 같이 미리 정의된 스타일이 있는 안드로이드 뷰를 상속한 커스텀 뷰를 만들 때 특히 문제가 된다.

예를 들어 커스텀 TextInputEditText를 구현할 때 다음과 같이 정의할 수 있다.

 

class ElasticTextInputEditText @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : TextInputEditText(context, attrs, defStyle) {
    // ...
}

 

위에서 ElasticTextInputEditText를 일반 TextInputEditText처럼 쓰면 예기치 않은 동작이나 스타일링에 잠재적인 손상이 발생할 수 있다. defStyle 값이 0으로 재정의되서 커스텀 뷰가 의도한 스타일링을 잃을 수 있기 때문이다.

defStyle은 커스텀 구현에서 0으로 설정하는 경우가 많다. 그러나 3가지 생성자 매개변수의 목적은 디벨로퍼에 아래처럼 설명돼 있다.

 

XML에서 인플레이션을 수행하고 테마 속성에서 클래스별 기본 스타일을 적용한다. 이 View 생성자를 사용하면 하위 클래스가 인플레이션될 때 자체 기본 스타일을 사용할 수 있다. 예를 들어 Button 클래스의 생성자는 이 버전의 상위 클래스 생성자를 호출하고  defStyleAttr에 R.attr.buttonStyle을 제공한다.
이를 통해 테마의 버튼 스타일이 모든 기본 뷰 속성(특히 배경)뿐만 아니라 Button 클래스의 속성도 수정할 수 있다

 

적절한 defStyleAttr 값(ElasticTextInputEditText의 경우 R.attr.editTextStyle)을 생략하면 커스텀 뷰가 상속된 스타일 구성을 잃어 XML 인플레이션 중에 일관성 없거나 깨진 동작이 발생할 수 있다.

TextInputEditText의 내부 구현을 살펴보면 아래 코드에서 볼 수 있듯이 내부적으로 R.attr.editTextStyle을 defStyleAttr로 사용한다는 것을 알 수 있다.

 

public class TextInputEditText extends AppCompatEditText {

  // ... 필드 정의 ...

  public TextInputEditText(@NonNull Context context) {
    this(context, null);
  }

  public TextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
    // 기본 스타일 속성으로 R.attr.editTextStyle 사용
    this(context, attrs, R.attr.editTextStyle);
  }

  public TextInputEditText(
      @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          // ... 나머지 생성자 로직 ...
      }
}

 

TextInputEditText의 구현에서 세 번째 매개변수(defStyleAttr)로 androidx.appcompat.R.attr.editTextStyle을 전달하는 것을 어떤 방법(AOSP에서 검색하든 IDE에서 클래스를 타고 올라가든)으로든 알아야 한다. 테마 스타일을 제공하는 AppCompat 라이브러리나 안드로이드 SDK에서 기본적으로 제공하는 여러 커스텀 뷰마다 완전히 다른 스타일 값을 사용하고 있다.

ElasticTextInputEditText의 경우 올바른 스타일을 보장하기 위해 커스텀 뷰 생성자에서 defStyleAttr 매개변수의 기본값으로 R.attr.editTextStyle을 설정할 수 있다.

 

class ElasticTextInputEditText @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle
) : TextInputEditText(context, attrs, defStyleAttr) {
    // Custom implementation
}

 

반응형
Comments