레이아웃이 그려졌을 때 어떻게 알 수 있습니까?
화면에 스크롤 가능한 비트맵을 그리는 사용자 정의 보기가 있습니다.초기화하기 위해서는 부모 레이아웃 객체의 크기를 픽셀 단위로 전달해야 합니다.그러나 onCreate(생성) 및 onResume(재개) 기능 중에는 Layout(레이아웃)이 아직 그려지지 않았기 때문에 layout.get Measured(레이아웃.측정됨)높이()는 0을 반환합니다.
해결 방법으로 핸들러를 추가하여 잠시 기다렸다가 측정했습니다.이것은 작동하지만, 엉성하고, 레이아웃이 그려지기 전에 끝날 때까지 시간을 얼마나 줄일 수 있을지 모르겠습니다.
제가 알고 싶은 것은 레이아웃이 그려질 때 어떻게 감지할 수 있을까 하는 것입니다.이벤트나 콜백이 있습니까?
레이아웃에 트리 관찰자를 추가할 수 있습니다.올바른 너비와 높이를 반환해야 합니다.onCreate()
하위 보기의 레이아웃이 완료되기 전에 호출됩니다.그래서 너비와 높이는 아직 계산되지 않았습니다.높이와 너비를 얻으려면, 이것을 위에 놓습니다.onCreate()
방법:
final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
layout.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
layout.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
정말 쉬운 방법은 간단히 전화하는 것입니다.post()
당신의 레이아웃에.보기를 이미 만든 후 다음 단계에서 코드를 실행합니다.
YOUR_LAYOUT.post( new Runnable() {
@Override
public void run() {
int width = YOUR_LAYOUT.getMeasuredWidth();
int height = YOUR_LAYOUT.getMeasuredHeight();
}
});
사용되지 않는 코드 및 경고를 방지하려면 다음을 사용할 수 있습니다.
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
view.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
yourFunctionHere();
}
});
Androidx.core-core는 이미 이것을 가지고 있습니다.
/**
* Performs the given action when this view is next laid out.
*
* The action will only be invoked once on the next layout and then removed.
*
* @see doOnLayout
*/
public inline fun View.doOnNextLayout(crossinline action: (view: View) -> Unit) {
addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
override fun onLayoutChange(
view: View,
left: Int,
top: Int,
right: Int,
bottom: Int,
oldLeft: Int,
oldTop: Int,
oldRight: Int,
oldBottom: Int
) {
view.removeOnLayoutChangeListener(this)
action(view)
}
})
}
/**
* Performs the given action when this view is laid out. If the view has been laid out and it
* has not requested a layout, the action will be performed straight away, otherwise the
* action will be performed after the view is next laid out.
*
* The action will only be invoked once on the next layout and then removed.
*
* @see doOnNextLayout
*/
public inline fun View.doOnLayout(crossinline action: (view: View) -> Unit) {
if (ViewCompat.isLaidOut(this) && !isLayoutRequested) {
action(this)
} else {
doOnNextLayout {
action(it)
}
}
}
코틀린 확장 기능으로 개선
inline fun View.waitForLayout(crossinline yourAction: () -> Unit) {
val vto = viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
when {
vto.isAlive -> {
vto.removeOnGlobalLayoutListener(this)
yourAction()
}
else -> viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}
})
}
일반적인 방법의 대안은 뷰 도면에 연결하는 방법이 있습니다.
OnPreDrawListener
뷰를 표시할 때 여러 번 호출되므로 뷰의 측정된 너비 또는 높이가 유효한 특정 반복은 없습니다.이를 위해서는 지속적으로 다음을 확인해야 합니다.view.getMeasuredWidth() <= 0
) 또는 확인 횟수에 대한 제한을 설정합니다.measuredWidth
0보다 큼
보기가 그려지지 않을 수도 있으며, 이는 코드의 다른 문제를 나타낼 수 있습니다.
final View view = [ACQUIRE REFERENCE]; // Must be declared final for inner class
ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (view.getMeasuredWidth() > 0) {
view.getViewTreeObserver().removeOnPreDrawListener(this);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
//Do something with width and height here!
}
return true; // Continue with the draw pass, as not to stop it
}
});
이를 위한 가장 우아한 방법은OneShotPreDrawListener
안OneShotPreDrawListener
뷰 트리가 그려지려고 할 때 호출될 콜백을 등록하고 하나가 지나면 콜백 자체를 제거합니다.OnPreDraw
불러.
OneShotPreDrawListener.add(view) {
view.doSomething();
}
또 다른 대답은 다음과 같습니다.
뷰 치수를 확인해 보십시오.onWindowFocusChanged
.
코틀린을 사용하는 경우 doOnLayout을 사용하는 것이 좋습니다.
doOnLayout {
doWhateverYouNeed()
}
문서: 이 보기가 배치될 때 지정된 작업을 수행합니다.
언제onMeasure
뷰가 측정된 너비/높이를 얻는다고 합니다.이 후에, 당신은 전화할 수 있습니다.layout.getMeasuredHeight()
.
레이아웃이 이미 그려졌는지 확인하기 위해 정적 변수를 만듭니다.생성된 경우 그리기 함수를 호출하면 됩니다.
static int firstAccess = 0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main8);
if (firstAccess==0) {
LAYOUT_YOU_DRAW.post(new Runnable() {
@Override
public void run() {
creatSpread();
firstAccess = 1;
}
});
}else{
creatSpread();
}
}
view.post {TODO("아직 구현되지 않음") }
언급URL : https://stackoverflow.com/questions/7733813/how-can-you-tell-when-a-layout-has-been-drawn
'programing' 카테고리의 다른 글
mysql 저장 프로시저의 테이블 이름에 변수 사용 (0) | 2023.07.31 |
---|---|
부트스트랩 사용자 지정 버튼으로 선택하고 즉시 새 값 추가 (0) | 2023.07.31 |
스타일 변경을 전파하기 위해 WebKit에서 다시 그리거나 다시 칠하도록 강제하려면 어떻게 해야 합니까? (0) | 2023.07.31 |
Oracle: 함수 기반 인덱스 선택적 고유성 (0) | 2023.07.31 |
보기에서 열을 삭제하는 방법 (0) | 2023.07.31 |