사용자 정의보기를 만들 때 많은 사람들이 다음과 같이하는 것으로 나타났습니다.
public MyView(Context context) {
super(context);
// this constructor used when programmatically creating view
doAdditionalConstructorWork();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// this constructor used when creating view through XML
doAdditionalConstructorWork();
}
private void doAdditionalConstructorWork() {
// init variables etc.
}
내 첫 번째 질문은 생성자는 MyView(Context context, AttributeSet attrs, int defStyle)
어떻습니까? 어디에 사용되는지 잘 모르겠지만 수퍼 클래스에서 볼 수 있습니다. 필요합니까, 어디에 사용됩니까?
답변
다음 과 같이 사용자 정의 View
를 추가하는 경우 xml
:
<com.mypack.MyView
...
/>
당신은 생성자가 필요합니다 public MyView(Context context, AttributeSet attrs)
. 그렇지 않으면 Exception
안드로이드가 당신을 팽창 시키려고 할 때 얻을 것 View
입니다.
View
from 을 추가하고 다음 xml
과 android:style
같은 속성을 지정하면 :
<com.mypack.MyView
style="@styles/MyCustomStyle"
...
/>
MyCustomStyle
명시적인 XML 속성을 적용 하기 전에 두 번째 생성자가 호출되고 스타일의 기본값이 설정 됩니다.
세 번째 생성자는 일반적으로 응용 프로그램의 모든 뷰가 동일한 스타일을 갖기를 원할 때 사용됩니다.
답변
세 생성자를 모두 재정의하는 경우 CASCADE this(...)
CALLS를 호출 하지 마십시오 . 대신이 작업을 수행해야합니다.
public MyView(Context context) {
super(context);
init(context, null, 0);
}
public MyView(Context context, AttributeSet attrs) {
super(context,attrs);
init(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
// do additional work
}
그 이유는 부모 클래스가 실수로 재정의 할 수있는 자체 생성자에 기본 속성을 포함 할 수 있기 때문입니다. 예를 들어, 이것은 다음의 생성자입니다 TextView
.
public TextView(Context context) {
this(context, null);
}
public TextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.textViewStyle);
}
public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
에 전화하지 않으면 스타일 속성으로 super(context)
올바르게 설정되지 않은 것 R.attr.textViewStyle
입니다.
답변
MyView (컨텍스트 컨텍스트)
프로그래밍 방식으로 뷰를 구성 할 때 사용됩니다.
MyView (컨텍스트 컨텍스트, AttributeSet 속성)
LayoutInflater
xml 속성을 적용 하기 위해 사용 합니다. 이 속성 중 하나의 이름이 style
이면 레이아웃 xml 파일에서 명시 적 값을 찾기 전에 속성이 스타일을 찾습니다.
MyView (컨텍스트 컨텍스트, AttributeSet 속성, int defStyleAttr)
style
각 레이아웃 파일에서 지정할 필요없이 모든 위젯에 기본 스타일을 적용한다고 가정 하십시오. 예를 들어 기본적으로 모든 확인란을 분홍색으로 만듭니다. defStyleAttr을 사용하여이 작업을 수행 할 수 있으며 프레임 워크는 테마에서 기본 스타일을 조회합니다.
참고 defStyleAttr
잘못 선정되었습니다 defStyle
몇 시간 전에이 생성자가 정말 필요 여부에 대한 논의가있다. https://code.google.com/p/android/issues/detail?id=12683을 참조 하십시오.
MyView (컨텍스트 컨텍스트, AttributeSet 속성, int defStyleAttr, int defStyleRes)
응용 프로그램의 기본 테마를 제어 할 수 있으면 세 번째 생성자가 잘 작동합니다. 기본 테마와 함께 위젯을 제공하기 때문에 Google에서 작동합니다. 그러나 위젯 라이브러리를 작성 중이고 사용자가 테마를 조정할 필요없이 기본 스타일을 설정하려고한다고 가정하십시오. defStyleRes
두 개의 첫 생성자에서 기본값으로 설정 하여이 작업을 수행 할 수 있습니다 .
public MyView(Context context) {
super(context, null, 0, R.style.MyViewStyle);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs, 0, R.style.MyViewStyle);
init();
}
전부
자체 뷰를 구현하는 경우 두 개의 첫 번째 생성자 만 필요하며 프레임 워크에서 호출 할 수 있습니다.
뷰를 확장 가능하게하려면 클래스의 하위 항목에 전역 스타일을 사용할 수 있도록 네 번째 생성자를 구현할 수 있습니다.
세 번째 생성자에 대한 실제 사용 사례는 보이지 않습니다. 위젯에 기본 스타일을 제공하지 않지만 사용자가 여전히 그렇게 할 수있게하려면 바로 가기 일 수 있습니다. 그렇게 많이 일어나서는 안됩니다.
답변
코 틀린은이 고통을 많이 없애는 것 같습니다.
class MyView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: View(context, attrs, defStyle)
@JvmOverloads는 필요한 생성자를 모두 생성합니다 (주석의 설명서 참조 ). 각각은 아마도 super ()를 호출합니다. 그런 다음 초기화 방법을 Kotlin init {} 블록으로 바꾸십시오. 상용구 코드가 사라졌습니다!
답변
세 번째 생성자는 훨씬 더 복잡합니다. 예를 들어 보겠습니다.
Support-v7 SwitchCompact
패키지는 24 버전부터 지원 thumbTint
및 trackTint
속성을 제공하지만 23 버전은 지원하지 않습니다. 이제 23 버전에서 지원하려면 어떻게해야합니까?
우리는 custom View SupportedSwitchCompact
extends 를 사용한다고 가정합니다 SwitchCompact
.
public SupportedSwitchCompat(Context context) {
this(context, null);
}
public SupportedSwitchCompat(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SupportedSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mThumbDrawable = getThumbDrawable();
mTrackDrawable = getTrackDrawable();
applyTint();
}
전통적인 코드 스타일입니다. 여기서 우리는 세 번째 매개 변수에 0을 전달합니다 . 코드를 실행할 때 getThumbDrawable()
메소드 getThumbDrawable()
가 수퍼 클래스 의 메소드이기 때문에 얼마나 이상한지 항상 null을 리턴합니다 SwitchCompact
.
R.attr.switchStyle
세 번째 매개 변수에 합격 하면 모든 것이 잘 진행됩니다.
세 번째 매개 변수는 간단한 속성입니다. 이 속성은 스타일 리소스를 가리 킵니다. 위의 경우, 시스템은 switchStyle
현재 테마에서 속성을 찾게됩니다.
에서가 frameworks/base/core/res/res/values/themes.xml
, 당신은 볼 것이다 :
<style name="Theme">
<item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>
답변
지금 논의중인 것과 같은 세 개의 생성자를 포함해야하는 경우에도이를 수행 할 수 있습니다.
public MyView(Context context) {
this(context,null,0);
}
public MyView(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
doAdditionalConstructorWork();
}