View의 getWidth() 및 getHeight()는 0을 반환합니다.
안드로이드 프로젝트의 모든 요소를 역동적으로 만들고 있습니다.나는 그 단추를 돌리기 위해 단추의 폭과 높이를 파악하려고 한다.저는 안드로이드 언어로 작업하는 방법을 배우려고 합니다.단, 0이 반환됩니다.
'아까보다'가 '아까보다'가 더 한 것 요.onCreate()
of if.예를 들어 주시면 감사하겠습니다.
현재 코드는 다음과 같습니다.
package com.animation;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.LinearLayout;
public class AnimateScreen extends Activity {
//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(30, 20, 30, 0);
Button bt = new Button(this);
bt.setText(String.valueOf(bt.getWidth()));
RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2);
ra.setDuration(3000L);
ra.setRepeatMode(Animation.RESTART);
ra.setRepeatCount(Animation.INFINITE);
ra.setInterpolator(new LinearInterpolator());
bt.startAnimation(ra);
ll.addView(bt,layoutParams);
setContentView(ll);
}
어떤 도움이라도 감사합니다.
는 실제 wrap_content
★★★★★★★★★★★★★★★★★」match_parent
단계는 않습니다 、 , 、 ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ.onResume()
따라서 이 단계를 대기하기 위한 회피책이 필요합니다.여기에는 다음과 같은 다양한 해결책이 있습니다.
1. 추첨/레이아웃 이벤트 듣기:View Tree Observer
ViewTreeObserver는 다른 도면 이벤트에 대해 부팅됩니다.일반적으로 는 측정을 얻기 위해 필요한 것이므로, 레이아웃 단계 후에 수신기의 코드가 호출되므로 측정이 준비됩니다.
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
주의: 청취자는 즉시 삭제됩니다.그렇지 않으면 모든 레이아웃이벤트에서 재생됩니다.SDK Lvl < 16을 지원해야 하는 경우 다음을 사용하여 청취자의 등록을 취소합니다.
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. 레이아웃 큐에 실행 가능 추가:View.post()
잘 알려지지 않았고 내가 가장 좋아하는 해결책이야.기본적으로 View의 Post 메서드를 사용자 고유의 실행 파일과 함께 사용합니다.이것은 기본적으로 Romain Guy가 말한 뷰의 측정, 레이아웃 등에 따라 코드를 큐잉합니다.
UI 이벤트 큐는 이벤트를 순서대로 처리합니다.setContentView()가 호출된 후 이벤트큐에는 레이아웃 통과 후 큐에 투고할 수 있도록 레이아웃을 요청하는 메시지가 포함됩니다.
예:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
★★★★★★★에 대한 장점ViewTreeObserver
:
- 코드가 한 번만 실행되며 실행 후 Observer를 비활성화할 필요가 없습니다.이것은 번거로울 수 있습니다.
- 보다 상세한 구문
참고 자료:
3. 뷰의 onLayout 메서드 덮어쓰기
이것은 뷰 자체에 로직을 캡슐화할 수 있는 특정 상황에서만 실용적입니다.그렇지 않으면 상당히 장황하고 번거로운 구문입니다.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
또한 onLayout은 여러 번 호출되므로 메서드에서 무엇을 하는지 주의하거나 처음 실행한 후 코드를 비활성화하십시오.
4. 배치 단계를 거쳤는지 확인합니다.
UI를 생성하는 동안 여러 번 실행되는 코드가 있는 경우 다음 지원 v4 lib 방법을 사용할 수 있습니다.
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
뷰가 창에 마지막으로 연결되거나 창에서 분리된 이후 하나 이상의 레이아웃을 거친 경우 true를 반환합니다.
추가:정적으로 정의된 측정값 가져오기
정적으로 정의된 높이/폭만 얻어도 충분할 경우 다음과 같이 수행할 수 있습니다.
그러나 그림 그리기 후 실제 너비/높이와 다를 수 있습니다.javadoc에서는 그 차이에 대해 자세히 설명합니다.
뷰의 크기는 너비와 높이로 표시됩니다.뷰에는 실제로 두 쌍의 너비와 높이 값이 있습니다.
첫 번째 쌍은 측정된 폭과 측정된 높이로 알려져 있습니다.이러한 치수는 상위 뷰 내에서 뷰의 크기를 정의합니다(자세한 내용은 레이아웃 참조).측정된 치수는 getMeasuredWidth() 및 getMeasured를 호출하여 얻을 수 있습니다.높이().
두 번째 쌍은 단순히 너비와 높이 또는 때로는 도면 너비와 도면 높이로 알려져 있습니다.이러한 치수는 화면, 그리기 시간 및 레이아웃 후 뷰의 실제 크기를 정의합니다.이러한 값은 측정된 폭 및 높이와 다를 수 있지만 반드시 다를 필요는 없습니다.폭과 높이는 getWidth()와 getHeight()를 호출하여 얻을 수 있습니다.
사용할 수 있습니다.
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//Here you can get the size!
}
전화하고 요.getWidth()
되지 않았습니다.UI의 사이즈나 레이아웃은 아직 화면에 표시되지 않았습니다.
어쨌든, 당신이 하고 있는 일을 하고 싶은 것은 아닐 것입니다.애니메이션 되고 있는 위젯은 클릭 가능한 영역을 변경하지 않기 때문에, 버튼은 회전 방법에 관계없이 원래의 방향의 클릭에 응답합니다.
즉, 치수 리소스를 사용하여 버튼 크기를 정의한 다음 레이아웃 파일과 소스 코드에서 해당 치수 리소스를 참조하여 이 문제를 방지할 수 있습니다.
저는 이 솔루션을 사용했습니다.이 솔루션은 on Window Focus Changed()보다 좋다고 생각합니다.Dialog Fragment를 열고 전화기를 회전시키면 사용자가 대화상자를 닫았을 때만 onWindowFocusChanged가 호출됩니다).
yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Ensure you call it only once :
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Here you can get the size :)
}
});
Edit : removeGlobalOnLayoutListener가 권장되지 않으므로 다음 작업을 수행해야 합니다.
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Ensure you call it only once :
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
else {
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// Here you can get the size :)
}
위젯이 화면에 표시되기 전에 너비를 얻으려면 getMeasuredWidth() 또는 getMeasuredWidth()를 사용할 수 있습니다.높이().
myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();
Ian은 이 Android Developers 스레드에 다음과 같이 기술하고 있습니다.
어쨌든 창의 콘텐츠 레이아웃은 모든 요소가 구성되고 상위 뷰에 추가된 후에 이루어집니다.View에 포함된 구성 요소 및 포함된 구성 요소 등을 알 때까지 View를 배치할 수 있는 합리적인 방법이 없기 때문입니다.
결론적으로 컨스트럭터에서 getWidth() 등을 호출하면 0이 반환됩니다.이 절차에서는 컨스트럭터에 뷰 요소를 모두 작성한 후 View의 onSizeChanged() 메서드가 호출될 때까지 기다립니다.이때 처음 실제 크기를 알게 되므로 GUI 요소의 크기를 설정할 수 있습니다.
onSizeChanged()는 파라미터가 0인 채로 호출되는 경우도 있습니다.이 경우 체크하고 즉시 반환됩니다(그래서 레이아웃 계산 시 0으로 나누지 않습니다).잠시 후 실제 값을 사용하여 호출됩니다.
addOnGlobalLayoutListener()가 아닌 OnPreDrawListener()를 사용하는 것이 좋습니다.이것은 다른 청취자보다 조금 빨리 호출되기 때문입니다.
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
if (view.getViewTreeObserver().isAlive())
view.getViewTreeObserver().removeOnPreDrawListener(this);
// put your code here
return true;
}
});
@Pang의 코멘트에 따라 코드를 조정했습니다.onPreDraw 메서드는 true를 반환해야 합니다.
작업을 지원하는 여러 AndroidX 내부에는 이러한 작업을 지원합니다.androidx.core.view
이건 코틀린을 써야 돼.
여기에 가장 잘 맞는 것은doOnLayout
:
이 뷰가 배치될 때 지정된 작업을 수행합니다.뷰가 레이아웃되어 있고 레이아웃을 요청하지 않은 경우 작업이 즉시 수행되며, 그렇지 않은 경우 뷰가 다음에 레이아웃된 후에 작업이 수행됩니다.
이 작업은 다음 레이아웃에서 한 번만 호출된 후 제거됩니다.
이 예에서는 다음과 같습니다.
bt.doOnLayout {
val ra = RotateAnimation(0,360,it.width / 2,it.height / 2)
// more code
}
★★★★★★★★★★★★★★★★:androidx.core:core-ktx:1.0.0
Kotlin Extension은 글로벌 레이아웃을 관찰하고 높이가 동적으로 준비되면 지정된 작업을 수행합니다.
사용방법:
view.height { Log.i("Info", "Here is your height:" + it) }
구현:
fun <T : View> T.height(function: (Int) -> Unit) {
if (height == 0)
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
function(height)
}
})
else function(height)
}
RxJava & RxBindings 를 사용하는 경우는, 1 개의 라이너.보일러 플레이트 없이 비슷한 방법으로 접근합니다.이것은 또한 Tim Autin의 답변에서와 같이 경고를 억제하기 위한 해킹을 해결합니다.
RxView.layoutChanges(yourView).take(1)
.subscribe(aVoid -> {
// width and height have been calculated here
});
이게 그거다.전화를 안 했더라도 구독을 취소할 필요는 없습니다.
뷰가 부풀어 오르는 데 시간이 더 필요하기 때문에 발생합니다. 전화하는 게 view.width
★★★★★★★★★★★★★★★★★」view.height
에서는 "Main Thread"를 사용해야 .view.post { ... }
view
이미 부풀려진 상태입니다.Kotlin kot kot :
view.post{width}
view.post{height}
, Java, Java, Java, Java, Java, Java, Java, Java를 호출할 도 있습니다.getWidth()
★★★★★★★★★★★★★★★★★」getHeight()
의 Runnable
을 하다Runnable
로로 합니다.view.post()
★★★★★★ 。
view.post(new Runnable() {
@Override
public void run() {
view.getWidth();
view.getHeight();
}
});
이게 도움이 될 수도 있어요
View 클래스에 대한 확장 함수를 만듭니다.
파일 이름:ViewExt.kt
fun View.afterLayout(what: () -> Unit) {
if(isLaidOut) {
what.invoke()
} else {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
what.invoke()
}
})
}
}
그러면 다음 항목과 함께 모든 보기에서 사용할 수 있습니다.
view.afterLayout {
do something with view.height
}
높이와 너비는 0입니다. 사용자가 원하는 높이와 너비까지 보기가 생성되지 않았기 때문입니다. 가장 간단한 해결책은 다음과 같습니다.
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
view.getWidth(); //width is ready
}
});
이 방법은 짧고 바삭바삭해서 다른 방법에 비해 좋습니다.
post
사이즈가 재계산되지 않을 수 있기 때문에 올바르지 않습니다.
또 하나 중요한 것은 조상과 조상이 모두 보여야 한다는 것이다.그 때문에 나는 부동산을 사용한다.View.isShown
.
유틸리티에 배치할 수 있는 코틀린 기능은 다음과 같습니다.
fun View.onInitialized(onInit: () -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (isShown) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
onInit()
}
}
})
}
사용법은 다음과 같습니다.
myView.onInitialized {
Log.d(TAG, "width is: " + myView.width)
}
Kotlin을 사용하는 경우
customView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
customView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
else {
customView.viewTreeObserver.removeGlobalOnLayoutListener(this)
}
// Here you can get the size :)
viewWidth = customView.width
}
})
그럼 '아', '아까', '아까보다' 이렇게 쓸 수 요.addOnLayoutChangeListener
해서 '어디서나 쓸 수 '에서 쓸 수 있어요.onCreate
Activity
★★★★★★★★★★★★★★★★★」onCreateView
Fragment
@Edit은 무한 루프를 트리거하므로 삭제하는 것을 잊지 마십시오.
myView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener{
override fun onLayoutChange(
v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int
) {
if (v?.width > 0 && v?.height > 0){
// do something
Log.i(TAG, "view : ${view.width}")
// remove after finish
v?.removeOnLayoutChangeListener(this)
}
}
})
사라진 보기는 앱이 백그라운드에 있는 경우 높이로 0을 반환합니다.이것은 내 코드입니다(1oo%가 동작합니다).
fun View.postWithTreeObserver(postJob: (View, Int, Int) -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
val widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
val heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
measure(widthSpec, heightSpec)
postJob(this@postWithTreeObserver, measuredWidth, measuredHeight)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
@Suppress("DEPRECATION")
viewTreeObserver.removeGlobalOnLayoutListener(this)
} else {
viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}
})
}
시야가 확보될 때까지 기다려야 합니다.이를 위해 OnPreDrawListener를 사용합니다.Kotlin의 예:
val preDrawListener = object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
view.viewTreeObserver.removeOnPreDrawListener(this)
// code which requires view size parameters
return true
}
}
view.viewTreeObserver.addOnPreDrawListener(preDrawListener)
Kotlin의 경우:
사용으로 인해 생산 중단에 직면했습니다.view.height
view.width
은 lead그로 이어진다.NaN
View.post()
으 0 으 、 em em em 、 em em em em 、 em em em em em을 em em em 。
그렇게,
view.doOnPreDraw { // your action here}
'먹다', '먹다', '먹다'입니다.
OneShotPreDrawListener
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★- ★★
OnPreDrawListener
.
이것은 조금 낡았지만, 스스로는 곤란했습니다(작성할 때 오브젝트에 애니메이션을 넣어야 합니다).이 해결책은 나에게 효과가 있었고, 나는 그것이 스스로 설명된다고 믿는다.
class YourFragment: Fragment() {
var width = 0
var height = 0
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val root = inflater.inflate(R.layout.fragment_winner_splash, container, false)
container?.width.let {
if (it != null) {
width = it
}
}
container?.height.let {
if (it != null) {
height = it
}
}
return root
}
onDraw 메서드의 과부하가 우려되는 경우, 구성 중에 치수를 항상 null로 설정한 다음 null인 경우에만 onDraw 내부 치수를 설정할 수 있습니다.
이렇게 하면 실제로 온드로 안에서 작업을 할 필요가 없습니다.
class myView(context:Context,attr:AttributeSet?):View(context,attr){
var height:Float?=null
override fun onDraw(canvas:Canvas){
if (height==null){height=this.height.toFloat()}
}
}
언급URL : https://stackoverflow.com/questions/3591784/views-getwidth-and-getheight-returns-0
'programing' 카테고리의 다른 글
단일 곱셈으로 비트 추출 (0) | 2022.10.22 |
---|---|
다중 열 외부 키: 단일 열을 모두가 아닌 Null "ON DELETE"로 설정합니다. (0) | 2022.10.22 |
MongoDB vs MySQL (0) | 2022.10.21 |
MariaDB에서 MySQL의 JSONOBJECTAGG()와 동등한 방법이 있습니까? (0) | 2022.10.21 |
EC2 인스턴스에서 RDS 인스턴스에 연결할 수 없습니다. (0) | 2022.10.21 |