Android 사용자 정의보기를 위해 세 생성자가 모두 필요합니까?
사용자 정의보기를 만들 때 많은 사람들이 다음과 같이하는 것으로 나타났습니다.
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 속성)
Used by the LayoutInflater
to apply xml attributes. If one of this attribute is named style
, attributes will be looked up the the style before looking for explicit values in the layout xml file.
MyView(Context context, AttributeSet attrs, int defStyleAttr)
Suppose you want to apply a default style to all widgets without having to specify style
in each layout file. For an example make all checkboxes pink by default. You can do this with defStyleAttr and the framework will lookup the default style in your theme.
Note that defStyleAttr
was incorrectly named defStyle
some time ago and there is some discussion about whether this constructor is really needed or not. See https://code.google.com/p/android/issues/detail?id=12683
MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
The 3rd constructor works well if you have control over the base theme of the applications. That is working for google because they ship their widgets along side the default Themes. But suppose you're writing a widget library and you want a default style to be set without your users needing to tweak their theme. You can now do this using defStyleRes
by setting it to the default value in the 2 first constructors:
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();
}
All in all
If you're implementing your own views, only the 2 first constructors should be needed and can be called by the framework.
If you want your Views to be extensible, you might implement the 4th constructor for children of your class to be able to use global styling.
I don't see a real use case for the 3rd constructor. Maybe a shortcut if you don't provide a default style for your widget but still want your users to be able to do so. Shouldn't happen that much.
Kotlin seems to take away a lot of this pain:
class MyView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: View(context, attrs, defStyle)
@JvmOverloads will generate all required constructors (see that annotation's documentation), each of which presumably calls super(). Then, simply replace your initialization method with a Kotlin init {} block. Boilerplate code gone!
The third constructor is much more complicated.Let me hold an example.
Support-v7 SwitchCompact
package supports thumbTint
and trackTint
attribute since 24 version while 23 version does not support them.Now you want to support them in 23 version and how will you do to achieve this?
We assume to use 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();
}
It's a traditional code style.Note we pass 0 to the third param here. When you run the code, you will find getThumbDrawable()
always return null how strange it is because the method getThumbDrawable()
is its super class SwitchCompact
's method.
If you pass R.attr.switchStyle
to the third param, everything goes well.So why?
The third param is a simple attribute. The attribute points to a style resource.In above case, the system will find switchStyle
attribute in current theme fortunately system finds it.
In frameworks/base/core/res/res/values/themes.xml
, you will see:
<style name="Theme">
<item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>
If you have to include three constructors like the one under discussion now, you could do this too.
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();
}
'Programing' 카테고리의 다른 글
getOne 및 findOne 메소드를 사용하는 경우 Spring Data JPA (0) | 2020.06.26 |
---|---|
mysql에서 문자열을 날짜로 변환하는 방법은 무엇입니까? (0) | 2020.06.26 |
KnockoutJS에 의해 잡히지 않는 jQuery UI 날짜 선택기 변경 이벤트 (0) | 2020.06.26 |
정렬 뒤의 구문 (key = lambda :…) (0) | 2020.06.26 |
Bootstrap 3의 탐색 표시 줄에 아이콘이있는 검색 상자를 추가하는 방법은 무엇입니까? (0) | 2020.06.26 |