Java 根据屏幕大小调整自定义视图的大小

Java 根据屏幕大小调整自定义视图的大小,java,android,android-layout,drawing,Java,Android,Android Layout,Drawing,我一直在试图找到一个解决方案,但也许我不明白“onMeasure()”方法在Android中是如何工作得这么好的 这是我第一次在Android中创建自定义视图“动态”,因此我了解到需要重写“onMeasure()”方法,以便根据屏幕大小调整视图大小。我希望我的视图是屏幕宽度的一半,再加上一点额外的宽度(这个数字是任意的,只要它相对较小,介于3和5之间),因此我为onMeasure方法编写了以下代码: @Override public void onMeasure(int widthMeasure

我一直在试图找到一个解决方案,但也许我不明白“onMeasure()”方法在Android中是如何工作得这么好的

这是我第一次在Android中创建自定义视图“动态”,因此我了解到需要重写“onMeasure()”方法,以便根据屏幕大小调整视图大小。我希望我的视图是屏幕宽度的一半,再加上一点额外的宽度(这个数字是任意的,只要它相对较小,介于3和5之间),因此我为onMeasure方法编写了以下代码:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    int halfWidth = (MeasureSpec.getSize(widthMeasureSpec) / 2) - 5;

    this.setMeasuredDimension((int) halfWidth, (int) halfWidth);
}
我确信这是一种糟糕的方式,因为我在网上发现的任何地方都有比我在尝试完成类似任务时多得多的代码

当我在XML中将这些视图相邻放置时,第一个视图的大小正确(它实际上是宽度的一半减去多一点),但第二个视图小得多,可能是最后一个视图宽度的一半减去多一点!(我会贴一张照片,但不幸的是,我没有足够的声誉这么做…)

应该发生的是,这两个框的大小应该相同,无论我将它们放在XML中的什么位置。它们都应该是屏幕宽度的一半,减去一点额外的尺寸


我知道这与我如何使用“setMeasuredDimension()”有关,但我不知道它是什么。我真的希望有人能为我澄清一些事情!谢谢!:)

我认为您需要阅读有关的文档,看看它是如何工作的

根据视图所在的布局容器的类型,它实际上会被多次调用,具体细节因视图组而异。一般来说,尺寸在第一次时是最松散的,然后随着更多组件的布置而变得更细粒度

调用onMeasure时,您首先希望通过调用
MeasureSpec.getMode(widthmasurespec)
来查看收到了哪种度量。这将返回最多
MeasureSpec.
MeasureSpec.

如果返回的最大值为_,则表示此时视图可能填充的最大区域。在布置第一个视图时,可能会说您的第一个视图最多可以使用整个屏幕的宽度,因为还没有布置其他组件。将容器的整个宽度除以2,然后通过调用
setMeasuredDimension
告诉容器您对使用50%的水平布局感到满意

接下来,当为第二个视图调用
onMeasure
时,现在只有容器水平宽度的一半可用,因为您已经为第一个视图请求了屏幕的一半

然后将该数字除以2,第二个视图仅为容器水平宽度的25%,而第一个视图为水平宽度的50%

我认为覆盖onMeasure并不是获得使用一半屏幕的视图的正确方法,尽管我想解释它是如何工作的。您是否有理由认为仅使用标准xml布局无法实现这一点


编辑:再次阅读您的问题,我认为您的问题在于您假设widthMeasureSpec与屏幕宽度的含义相同(事实并非如此)。您可以尝试正确地查询屏幕的宽度,并在此基础上调用
setMeasureDimension
,尽管它可能并不适用于所有情况。如果您不小心,您可能会要求宽度大于根据测量分配给您的宽度。或者,有时您会被称为
onMeasure
,使用
MeasureSpec.
,在这一点上,您别无选择,只能使用提供的宽度或高度。

我认为问题在于,根据您的说法,父视图的大小也减小了,可能是大小的一半左右。因此,我建议:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
   // Prevent reducing the size of the parent view
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);

   int halfWidth = (MeasureSpec.getSize(widthMeasureSpec) / 2) - 5;

   this.setMeasuredDimension((int) halfWidth, (int) halfWidth);
}
另外,您的XML布局是什么样的?这可能也需要解决,尽管有人怀疑这是个问题


我没有在我的Android SDK上尝试过这一点。

实际上,我是在Tim所说的基础上通过一点实验来完成这一点的。我不再使用“onMeasure()”,只为此编写了以下代码:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    // Call the super class.
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    // Set the dimensions of this view.
    this.setMeasuredDimension((int) width, (int) width);
}
宽度是一个全局浮动。宽度从何而来?我从我在视图中编写的用于调整大小的方法中导出宽度:

public void initSize(float size)
{
    width = size;
    this.invalidate();
}
我调用“invalidate()”来重新绘制视图。但是,必须调用此方法,所以我在活动中这样做。首先,我使用以下代码获取活动中的屏幕大小,而不是视图:

Display thisDisplay = this.getWindowManager().getDefaultDisplay();
Point desiredSize = new Point();
display.getSize(desiredSize);
int width = size.x;
您过去可以在“thisDisplay”上调用名为“getWidth()”的方法,但该方法现在已折旧,因此您应该改用“getSize()”。最后,在初始化构造函数之后,调用“initSize()”方法:


现在,所有视图的大小都将相同。我不知道这是否是最好的方法,但它现在起作用了,我想我应该把它贴在这里,让大家都知道。:)

老问题。。但这里有一个onMeasure,它使视图成为正方形,并且小于屏幕的一半,而不需要在活动中编写任何额外的代码。可以将其更改为生成任何其他尺寸比

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // get view dimensions suggested by layout
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    // width should never be more than half of a screen
    int displayWidth = getContext().getResources().getDisplayMetrics().widthPixels;
    width = Math.min(width, displayWidth/2);
    // always make it a square (use the smaller dimension of the two)
    if (width > height) {
        width = height;
    } else {
        height = width;
    }
    // use the values
    super.onMeasure(
            MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
            MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
    );
}

您好,看一下“布局重量”,您能准确地说出您认为调用
super.onMeasure
将在这里实现什么吗?它将只调用onMeasure上的unoverriden方法,该方法将设置测量的尺寸,在返回到Override函数后,该尺寸将立即再次被覆盖。你在那里所描述的对我来说毫无意义,不过如果你愿意的话,你可以试着解释你的答案。我知道给父母打电话是很费解的。但基本上我认为这将解决最初的问题“但是第二个视图要小得多,可能是最后一个视图宽度的一半……”,正如Thanizer所说。总之,我认为View.onMeasure应该以我们所有人的方式实现
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // get view dimensions suggested by layout
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    // width should never be more than half of a screen
    int displayWidth = getContext().getResources().getDisplayMetrics().widthPixels;
    width = Math.min(width, displayWidth/2);
    // always make it a square (use the smaller dimension of the two)
    if (width > height) {
        width = height;
    } else {
        height = width;
    }
    // use the values
    super.onMeasure(
            MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
            MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
    );
}