코틀린(Kotlin) CustomView

elice dev
5 min readJan 6, 2018

custom view를 개발 할 때, 안드로이드 framework에서는 view가 언제, 어떻게 생성되는지를 정의하기 위한 여러개의 constructor 를 필요로 한다. 그래서 View를 상속받는 class는 constructor 를 갖지 않으면 컴파일 에러가 난다. 그래서 아래와 같이 만들 수 있다.

public class UserProfileView extends LinearLayout {
public UserProfileView(Context context) {
this(context, null);
}

public UserProfileView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public UserProfileView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}

위의 코드를 그대로 kotin으로 바꿔보자.

class UserProfileView : View {constructor(context: Context) : this(context, null)constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {   }
}

this 를 사용해서 같은 클래스 내에서 하나의 생성자만 호출하도록 했다. 하지만 java와 kotlin으로 작성한게 크게 차이는 없어보인다. 그렇지만 kotlin으로는 생성자를 더 간결하게 작성할 수 있는데, @JvmOverloads annotation을 통해서 이를 해결 할 수 있다.

class UserProfileView @JvmOverloads 
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr){
...
}

annotation을 통해 3개의 생성자를 모두 작성하지 않아도 깔끔하게 작성할 수 있게 된다. @JvmOverloads 내부 코드를 보면 다음과 같이 설명되어있다.

Instructs the Kotlin compiler to generate overloads for this function that substitute default parameter values.

If a method has N parameters and M of which have default values, M overloads are generated: the first one takes N-1 parameters (all but the last one that takes a default value), the second takes N-2 parameters, and so on.

즉, 생성자의 parameter가 기본값으로 대체하도록 컴파일러에 지시한다는 의미이다.

하지만 TextView와 같은 경우를 커스텀뷰로 개발하게 되면, @JvmOverloads 로 인해서 기본값으로 대체되기 때문에 지정한 style이 적용되지 않는다. 따라서 TextView나 EditText를 customView로 개발하면 annotation을 사용하지 않으며, 아래와 같이 super를 사용하도록 한다.

class MyEditText : TextView{constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
}

그 외에도 코틀린에서는 init{ …} 을 통해서 레이아웃을 inflate할 수 있고, 예를 들어 R.laoyut.item_profile 와 같은 레이아웃자체를 import 함으로써 아래와 같은 view binding을 아래와 같이 별도의 바인딩 없이 작성할 수 있다.

//java코드로 작성된 뷰 바인딩
ImageView userProfileImage = findViewById(R.id.userProfileImage);
userProfileImage.setVisibility(View.GONE);
//코틀린에서는 별도의 바인딩 없이 작성할 수 있다.
userProfileImage.visibility = View.GONE

--

--