getWidth()如果由android:layout_width="match_parent"设置,则返回0。

16

我有一个继承自ImageView的类叫做FractalView。我的目标是使用该类绘制一个尺寸为整个屏幕的分形图案。它是我的活动布局文件中唯一的视图,除了顶级LinearLayout之外:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
    android:background="#FFFFFFFF">

    <com.antonc.fractal_wallpaper.FractalView
        android:id="@+id/fractal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>
</LinearLayout>

可以看到,我正在使用"match_parent"将FractalView和LinearLayout的layout_width和layout_height都设置为相同值。此时,我假设FractalView的大小已经设置为一定的值,因为它与其父布局匹配,而父布局又与其父布局(整个屏幕)匹配。 接下来,我尝试使用getWidth()和getHeight()来检测可用于FractalView的大小:

public class FractalView extends ImageView {

private Context mContext;
private Handler mHandler;

private int mScrWidth;
private int mScrHeight;

public FractalView(Context context) {
    super(context);
    mContext = context;
    init();
}

private void init() {

    mScrWidth = getWidth();
    mScrHeight = getHeight();
    // Breakpoint
}

@Override
protected void onDraw(Canvas canvas) {
    [...]
}

}
但是当我的代码到达断点时,调试器显示mScrWidth和mScrHeight为零。我尝试使用getMeasuredWidth()和getMaxWidth(),但它们也返回不正确的值。我读了几个类似问题的答案,比如这个,它们都解释了getWidth()返回图像绘制后的大小,而实际上我需要的是该视图可用宽度,在开始绘制之前。

有没有一种方法可以检索宽度和高度的这些值?


2
覆盖 onMeasure 方法。https://dev59.com/42s05IYBdhLWcg3wIehj - Simon
由于您愿意使用整个屏幕,因此可以查看获取设备宽度和高度(这不是建议性的)。如果getMeasuredWidth()返回错误值,则应等待其测量并再次调用该函数。例如,在另一个Activity生命周期方法中调用该函数(例如,在onResume而不是onCreate中),希望这可以帮助到您。 - Tobrun
另外一件你可以做的事情,因为你正在使用ImageView,就是覆盖setImageBitmap()方法。 - Simon
我已经找到了一种方法并将其作为答案发布了出来。目前我不会接受自己的答案,因为也许有人知道更好的方法。Simon, user1281750 - 谢谢,我会查看你建议的方法。 - Anton Cherkashyn
2个回答

32

onMeasure()之后,视图的大小才可用,特别是当其设置为wrap_contentfill_parent时。

您应该在视图代码中在onMeasure()之后访问大小,或者在布局树观察器中访问。

LinearLayout layout = (LinearLayout)findViewById(R.id.mylayout);
ViewTreeObserver vto = layout.getViewTreeObserver(); 
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
    @Override 
    public void onGlobalLayout() { 
        this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
        int width  = layout.getMeasuredWidth();
        int height = layout.getMeasuredHeight(); 

    } 
});

要使第二个LinearLayout工作,您还需要向LinearLayout中添加android:id="@+id/mylayout"


1
我最终覆盖了onMeasure()方法,并在调用super.onMeasure(widthMeasureSpec,heightMeasureSpec)后立即调用了getMeasuredWidth()getMeasuredHeight()。这似乎解决了问题。 - Anton Cherkashyn

0

当我在输入问题时,我想出了一种方法来解决这个问题。 不是尝试在构造函数中检索大小,而是将代码移动到onDraw()方法中,像这样:

private void init() {

}

@Override
protected void onDraw(Canvas canvas) {
    mScrWidth = canvas.getWidth();
    mScrHeight = canvas.getHeight();
    [...]
}

这将返回正确的尺寸。


7
看看Raghav的回答(和我的评论)。任何不需要放在onDraw方法中的代码都是不好的代码,因为它会在每次绘制视图时执行。如果你不经常更新视图,这可能无关紧要,但这不应该成为在错误位置执行操作的借口。 - Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接