我正在动态地创建我的android项目中的所有元素。我试图获得一个按钮的宽度和高度,以便我可以旋转该按钮。我只是想学习如何使用android语言。但是,它返回0。

我做了一些研究,我看到它需要在其他地方而不是在onCreate()方法中完成。如果有人能给我一个如何做这件事的例子,那就太好了。

这是我当前的代码:

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

任何帮助都是感激的。


当前回答

public final class ViewUtils {

    public interface ViewUtilsListener {
        void onDrawCompleted();
    }

    private ViewUtils() {
    }

    public static void onDraw(View view, ViewUtilsListener listener) {
        view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (view.getHeight() != 0 && view.getWidth() != 0) {
                    if (listener != null) {
                        listener.onDrawCompleted();
                    }
                    view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            }
        });
    }
}

你可以这样用;

ViewUtils.onDraw(view, new ViewUtils.ViewUtilsListener() {
                @Override
                public void onDrawCompleted() {
                    int width = view.getWidth();
                    int height = view.getHeight();
                }
            });

其他回答

如果app在后台,消失的视图返回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)
            }
        }
    })
}

正如Ian在这篇Android开发者文章中所述:

Anyhow, the deal is that layout of the contents of a window happens after all the elements are constructed and added to their parent views. It has to be this way, because until you know what components a View contains, and what they contain, and so on, there's no sensible way you can lay it out. Bottom line, if you call getWidth() etc. in a constructor, it will return zero. The procedure is to create all your view elements in the constructor, then wait for your View's onSizeChanged() method to be called -- that's when you first find out your real size, so that's when you set up the sizes of your GUI elements. Be aware too that onSizeChanged() is sometimes called with parameters of zero -- check for this case, and return immediately (so you don't get a divide by zero when calculating your layout, etc.). Some time later it will be called with the real values.

在我的例子中,我不能通过post或addOnGlobalLayoutListener获得视图的高度,它总是0。因为我的视图在一个片段中,而这个片段是MainActivity中的第二个选项卡。当我打开MainActivity时,我输入第一个选项卡,所以第二个选项卡不会显示在屏幕上。但是onGlobalLayout()或post()函数仍然有一个回调。

当第二个片段在屏幕上可见时,我得到了视图的高度。这次我得到了正确的高度。

这是一个有点旧,但我自己有麻烦(需要在一个片段中创建动画对象)。这个解决方案对我来说很有效,我相信这是不言自明的。

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
}
 

用法:

imageView.size { width, height ->
            //your code
        }

延伸:


fun <T : View> T.size(function: (Int, Int) -> Unit) {
    if (isLaidOut && height != 0 && width != 0) {
        function(width, height)
    } else {
        if (height == 0 || width == 0) {
            var onLayoutChangeListener: View.OnLayoutChangeListener? = null
            var onGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null

            onGlobalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    if (isShown) {
                        removeOnLayoutChangeListener(onLayoutChangeListener)
                        viewTreeObserver.removeOnGlobalLayoutListener(this)
                        function(width, height)
                    }
                }
            }

            onLayoutChangeListener = object : View.OnLayoutChangeListener {
                override fun onLayoutChange(
                    v: View?,
                    left: Int,
                    top: Int,
                    right: Int,
                    bottom: Int,
                    oldLeft: Int,
                    oldTop: Int,
                    oldRight: Int,
                    oldBottom: Int
                ) {
                    val width = v?.width ?: 0
                    val height = v?.height ?: 0
                    if (width > 0 && height > 0) {
                        // remove after finish
                        viewTreeObserver.removeOnGlobalLayoutListener(onGlobalLayoutListener)
                        v?.removeOnLayoutChangeListener(this)
                        function(width, height)
                    }
                }
            }

            viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
            addOnLayoutChangeListener(onLayoutChangeListener)
        } else {
            function(width, height)
        }
    }
}