我有一个自定义视图,绘制一个可滚动的位图到屏幕。为了初始化它,我需要传入父布局对象的像素大小。但是在onCreate和onResume函数期间,布局还没有绘制,因此Layout . getmeasuredheight()返回0。

作为一种变通方法,我添加了一个处理程序来等待一秒钟,然后进行测量。这是工作,但它草率,我不知道多少我可以修剪的时间之前,我结束之前的布局得到绘制。

我想知道的是,我如何检测当一个布局被绘制?是否有事件或回调?


当前回答

当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();
    }
}

您可以在布局中添加一个树形观察器。这将返回正确的宽度和高度。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(); 

        } 
    });

使用kotlin扩展函数会更好

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)
            }
        }
    })
}

当onMeasure被调用时,视图得到它测量的宽度/高度。在此之后,你可以调用layout.getMeasuredHeight()。

androidx。Core-ktx已经有了

/**
 * 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)
        }
    }
}