사용자 지정 구성 요소를 시도했습니다. View
클래스를 확장 하고 onDraw
재정의 된 메소드로 그리기를 수행했습니다 . 대체해야하는 이유는 무엇 onMeasure
입니까? 내가하지 않으면 모든 것이 옳은 것으로 나타났습니다. 누군가 설명해 주시겠습니까? 내 onMeasure
방법을 어떻게 작성해야 합니까? 몇 가지 자습서를 보았지만 각 자습서는 서로 약간 다릅니다. 때때로 그들은 super.onMeasure
마지막에 전화 를하고 때로는 사용 setMeasuredDimension
하고 호출하지 않았습니다. 차이점은 어디에 있습니까?
결국 나는 정확히 동일한 구성 요소를 여러 개 사용하고 싶습니다. 해당 구성 요소를 XML
파일에 추가 했지만 그 구성 요소의 크기를 모릅니다. 나는 (내가에 설정된 크기로해야하는 이유 나중에 그 위치와 크기를 설정할 onMeasure
의 경우 onDraw
내가 그것을 그릴 때뿐만 아니라, 노력) 사용자 정의 컴포넌트 클래스. 정확히 언제해야합니까?
답변
onMeasure()
부모가 제공하는 레이아웃 제약 조건에 따라 사용자 정의보기가 얼마나 큰지 Android에 알릴 수있는 기회입니다. 또한 레이아웃 제약 조건이 무엇인지 배울 수있는 사용자 정의보기의 기회이기도합니다 ( match_parent
상황과 상황 에 따라 다르게 행동하려는 wrap_content
경우). 이러한 제약 조건은 MeasureSpec
메서드에 전달 된 값 으로 패키지됩니다 . 모드 값의 대략적인 상관 관계는 다음과 같습니다.
- 정확하게 는
layout_width
또는layout_height
값이 특정 값으로 설정 되었음을 의미합니다 . 당신은 아마이 크기로 볼 수 있습니다.match_parent
크기를 부모 뷰로 정확하게 설정하기 위해 사용될 때 트리거 될 수도 있습니다 (프레임 워크에 따라 레이아웃에 따라 다름). - AT_MOST는 일반적으로
layout_width
또는layout_height
값이 설정match_parent
되었거나wrap_content
최대 크기가 필요한 위치 (프레임 워크에 따라 레이아웃에 따라 다름)를 의미하며 부모 차원의 크기는 값입니다. 이 크기보다 크지 않아야합니다. - UNSPECIFIED 전형적 수단
layout_width
또는layout_height
값으로 설정된wrap_content
제한없이. 당신은 당신이 원하는 어떤 크기가 될 수 있습니다. 일부 레이아웃은이 콜백을 사용하여 원하는 크기를 파악하기 전에 두 번째 측정 요청에서 실제로 다시 전달할 사양을 결정합니다.
존재 계약 onMeasure()
IS setMeasuredDimension()
해야 당신이보기 싶습니다 크기에 끝에서 호출 될 수있다. 이 메소드는의 기본 구현을 포함하여 모든 프레임 워크 구현에서 View
호출 super
되므로 사용 사례에 맞는 경우 대신 호출하는 것이 안전합니다 .
프레임 워크가 기본 구현을 적용하기 때문에이 방법을 재정의 할 필요는 없지만 뷰 공간이 컨텐츠보다 작거나 그렇지 않은 경우보기 공간이 작은 경우 클리핑이 나타날 수 있습니다. wrap_content
프레임 워크가 얼마나 큰지 알지 못하므로 양방향으로 사용자 정의보기를 사용 하면보기가 전혀 표시되지 않을 수 있습니다!
일반적으로 View
기존 위젯이 아닌 재정의 하는 경우 다음과 같이 단순하더라도 구현을 제공하는 것이 좋습니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
도움이 되길 바랍니다.
답변
실제로 값은 포장 용기에 따라 다르므로 답은 완전하지 않습니다. 상대 또는 선형 레이아웃의 경우 값은 다음과 같이 동작합니다.
- 정확히 match_parent는 정확히 + 부모의 크기입니다
- AT_MOST wrap_content 결과 AT_MOST MeasureSpec
- 지정 되지 않음
가로 스크롤보기의 경우 코드가 작동합니다.
답변
측정 값을 변경할 필요가없는 경우이를 무시할 필요가 없습니다.
Devunwired 코드 (여기서 선택되고 가장 투표가 많은 답변)는 SDK 구현이 이미 수행 한 것과 거의 동일합니다 (2009 년 이후로 확인했습니다).
onMeasure 방법은 여기에서 확인할 수 있습니다 .
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
동일한 코드로 대체 할 SDK 코드를 재정의하는 것은 의미가 없습니다.
“기본 onMeasure ()는 항상 100×100의 크기를 설정합니다”라고 주장하는 이 공식 문서 는 잘못되었습니다.