Android - View.getWidth() 和 View.getHeight() 方法返回不正确的值

Android - View.getWidth() and View.getHeight() methods returning incorrect values

我的布局上有一个自定义视图,我将其宽度和高度设置为 300dp。

经过一些研究 (Determining the size of an Android view at runtime),我找到了一种以编程方式获取自定义视图的宽度和高度的方法。

问题是我以编程方式获得的尺寸与我在布局上设置的尺寸不同。

显然(经过一些测试)有一种模式,我以编程方式获得的尺寸比布局上设置的尺寸大 1.5。

示例:

android:layout_width="270dp"   >>  myView.getWidth() returns 405
android:layout_width="300dp"   >>  myView.getWidth() returns 450

这是代码。

有什么想法吗?

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">

<com.examples.danilofernandes.housemap.ViewForLayout
    android:id="@+id/layout"
    android:layout_width="270dp"
    android:layout_height="270dp" />

<Button
    android:id="@+id/button"
    android:text="hello"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/layout"/>

</RelativeLayout>

class:

public class ViewForLayout extends View {

boolean DEBUG_TAG = ActivityForLayout.DEBUG_TAG;

// To use with the Toasts on this Activity.
Context context;

// To use with the Canvas.
Paint paint;

// To advise display orientation.
boolean displayInPortraitMode;

// The plant (bitmap) to be displayed.
int myHousePlant;

// ---

int myDisplayWidth;
int myDisplayHeight;
float myDisplayRatio;

// ---

int myLayoutViewWidth;
int myLayoutViewHeight;
float myLayoutViewRatio;

// ---

float differenceInHeight;
float differenceInWidth;

float scaledPhotoHeight_1;
float scaledPhotoWidth_1;

float scaledPhotoHeight_2;
float scaledPhotoWidth_2;

// ---

Bitmap originalPhoto;
Bitmap scaledPhoto;

float originalPhotoRatio;
float scaledPhotoRatio;

// ---

Rect motionRect;

float motionRectLeft;
float motionRectTop;
float motionRectBottom;
float motionRectRight;

boolean drawMotionRect;

// ---

Rect room1;
Rect room2;
Rect looby;
Rect terrace;
Rect kitchen;
Rect bathroom;
Rect livingRoom;
Rect diningRoom;
Rect accessHall;
Rect serviceArea;

Rect room1Adjunct;
Rect kitchenAdjunct;
Rect serviceAreaAdjunct;

// ---

int drawRoom1;
int drawRoom2;
int drawLooby;
int drawTerrace;
int drawKitchen;
int drawBathroom;
int drawLivingRoom;
int drawDiningRoom;
int drawAccessHall;
int drawServiceArea;

// ---

public ViewForLayout(Context context, AttributeSet attrs) {

    super(context, attrs);

    // Bind the context to the activity.
    this.context = context;

    // Makes all connections.
    initializeAllVariables();

    // The background color of the view
    setBackgroundColor(Color.BLACK);

    // Resize the picture so that all of it will be visible.
    resizePictureToFitIntoScreen();

}

public void initializeAllVariables(){

    // Paint setting up
    paint = new Paint();
    paint.setColor(Color.BLACK);

    // Motion rect information
    drawMotionRect = false;

    // Display data

    myDisplayWidth = ActivityForLayout.myDisplayWidth;
    myDisplayHeight = ActivityForLayout.myDisplayHeight;

    myDisplayRatio = (float) myDisplayHeight / myDisplayWidth;

    displayInPortraitMode = ActivityForLayout.displayInPortraitMode;

    // Layout date

    ViewTreeObserver viewTreeObserver = this.getViewTreeObserver();
    if (viewTreeObserver.isAlive()) {
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onGlobalLayout() {
                ViewForLayout.this.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                myLayoutViewWidth = ViewForLayout.this.getWidth();
                myLayoutViewHeight = ViewForLayout.this.getHeight();
            }
        });
    }

    myLayoutViewRatio = (float) myLayoutViewHeight / myLayoutViewWidth;

    // Photo data

    myHousePlant = R.drawable.ilha_de_malaga_transparente;

    originalPhoto = BitmapFactory.decodeResource(getResources(), myHousePlant);
    originalPhotoRatio = (float) originalPhoto.getHeight() / originalPhoto.getWidth();

    // None room will be 'lighted up' at the first place

    drawRoom1 = -1;
    drawRoom2 = -1;
    drawLooby = -1;
    drawTerrace = -1;
    drawKitchen = -1;
    drawBathroom = -1;
    drawLivingRoom = -1;
    drawDiningRoom = -1;
    drawAccessHall = -1;
    drawServiceArea = -1;

    // The boundaries for all rooms in the house.

    room1 = new Rect(64 ,224,265,467);
    room2 = new Rect(146, 12,376,211);
    looby = new Rect(595, 12,736,94);
    terrace = new Rect(389,424,595,468);
    kitchen = new Rect(607,104,736,340);
    bathroom = new Rect(275,308,376,467);
    livingRoom = new Rect(389,215,595,410);
    diningRoom = new Rect(389, 12,595,215);
    accessHall = new Rect(296,224,389,295);
    serviceArea = new Rect(607,362,736,468);

    room1Adjunct = new Rect(265,224,283,296);
    kitchenAdjunct = new Rect(607,340,670,352);
    serviceAreaAdjunct = new Rect(607,352,670,362);

}

@Override
protected void onDraw(Canvas canvas) {

    // Whenever onDraw starts, paint color is set to black.
    paint.setColor(Color.BLACK);

    // Makes the picture to be draw on the center of the view.
    float drawInTheMiddleOfTheScreen_Width = (myDisplayWidth - scaledPhotoWidth_2)/2;
    float drawInTheMiddleOfTheScreen_Height = (myDisplayHeight - scaledPhotoHeight_2) /2;

    // Draw the picture
    canvas.drawBitmap(scaledPhoto, drawInTheMiddleOfTheScreen_Width, drawInTheMiddleOfTheScreen_Height, paint);

    // To makes the text (for debug info) more visible.
    paint.setColor(Color.RED);
    paint.setTextSize(25.0f);

    // Debug information.
    if(DEBUG_TAG) {
        canvas.drawText("Device Height: " + myDisplayHeight, 0, 25, paint);
        canvas.drawText("Device Width: " + myDisplayWidth, 0, 50, paint);
        canvas.drawText("Device Ratio is: " + myDisplayRatio, 0, 75, paint);

        canvas.drawText("Original Photo Height: " + originalPhoto.getHeight(), 0, 125, paint);
        canvas.drawText("Original Photo Width: " + originalPhoto.getWidth(), 0, 150, paint);
        canvas.drawText("Original Photo Ratio is: " + originalPhotoRatio, 0, 175, paint);

        canvas.drawText("Scaled Photo Height: " + scaledPhoto.getHeight(), 0, 225, paint);
        canvas.drawText("Scaled Photo Width: " + scaledPhoto.getWidth(), 0, 250, paint);
        canvas.drawText("Scaled Photo Ratio is: " + scaledPhotoRatio, 0, 275, paint);

        canvas.drawText("View Height: " + myLayoutViewHeight, 0, 325, paint);
        canvas.drawText("View Width: " + myLayoutViewWidth, 0, 350, paint);
        canvas.drawText("View Ratio is: " + myLayoutViewRatio, 0, 375, paint);
    }
    // Set the color to a transparent yellow
    paint.setColor(Color.argb(100,255,255,0));

    // Check which room was clicked by the user
    //     > 1st click - turns the light ON
    //     > 2nd click - turns the light OFF

    if(drawRoom1 > 0) {
        canvas.drawRect(room1, paint);
        canvas.drawRect(room1Adjunct, paint);
    }
    if(drawRoom2 > 0) {
        canvas.drawRect(room2, paint);
    }
    if(drawLooby > 0) {
        canvas.drawRect(looby, paint);
    }
    if(drawTerrace > 0) {
        canvas.drawRect(terrace, paint);
    }
    if(drawKitchen > 0) {
        canvas.drawRect(kitchen, paint);
        canvas.drawRect(kitchenAdjunct, paint);
    }
    if(drawBathroom > 0){
        canvas.drawRect(bathroom,paint);
    }
    if(drawLivingRoom > 0) {
        canvas.drawRect(livingRoom, paint);
    }
    if(drawDiningRoom > 0) {
        canvas.drawRect(diningRoom, paint);
    }
    if(drawAccessHall > 0) {
        canvas.drawRect(accessHall, paint);
    }
    if(drawServiceArea > 0) {
        canvas.drawRect(serviceArea, paint);
        canvas.drawRect(serviceAreaAdjunct, paint);
    }

    // The Rect that is drawn if the user click and drag the finger on the screen.
    if(drawMotionRect) {

        canvas.drawRect(motionRect, paint);

        // Makes the drawn motion rect to be erased from the screen on next onDraw call.
        drawMotionRect = false;

    }

}

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            motionRectLeft = event.getX();
            motionRectTop = event.getY();

            float xUserTouch = event.getX();
            float yUserTouch = event.getY();

            if(DEBUG_TAG) {
                Toast.makeText(context, "x = " + xUserTouch + ", y = " + yUserTouch, Toast.LENGTH_SHORT).show();
            }

            if (kitchen.contains((int)event.getX(), (int)event.getY()) || kitchenAdjunct.contains((int)event.getX(), (int)event.getY()) ) {
                drawKitchen = drawKitchen * (-1);

                // Call onDraw method
                invalidate();
            }

            if (room2.contains((int)event.getX(), (int)event.getY())) {
                drawRoom2 = drawRoom2 * (-1);

                // Call onDraw method
                invalidate();
            }

            if (room1.contains((int)event.getX(), (int)event.getY()) || room1Adjunct.contains((int)event.getX(), (int)event.getY()) ) {
                drawRoom1 = drawRoom1 * (-1);

                // Call onDraw method
                invalidate();
            }

            if (livingRoom.contains((int)event.getX(), (int)event.getY())) {
                drawLivingRoom = drawLivingRoom * (-1);

                // Call onDraw method
                invalidate();
            }

            if (diningRoom.contains((int)event.getX(), (int)event.getY())) {
                drawDiningRoom = drawDiningRoom * (-1);

                // Call onDraw method
                invalidate();
            }

            if (accessHall.contains((int)event.getX(), (int)event.getY())) {
                drawAccessHall = drawAccessHall * (-1);

                // Call onDraw method
                invalidate();
            }

            if (serviceArea.contains((int)event.getX(), (int)event.getY()) || serviceAreaAdjunct.contains((int)event.getX(), (int)event.getY()) ) {
                drawServiceArea = drawServiceArea * (-1);

                // Call onDraw method
                invalidate();
            }

            if (terrace.contains((int)event.getX(), (int)event.getY())) {
                drawTerrace = drawTerrace * (-1);

                // Call onDraw method
                invalidate();
            }

            if (looby.contains((int)event.getX(), (int)event.getY())) {
                drawLooby = drawLooby * (-1);

                // Call onDraw method
                invalidate();
            }

            if(bathroom.contains((int)event.getX(), (int)event.getY())){
                drawBathroom = drawBathroom * (-1);

                // Call onDraw method
                invalidate();
            }

            break;

        case MotionEvent.ACTION_MOVE:

            // Update the motionRect coordinated at every move.
            motionRectRight = event.getX();
            motionRectBottom = event.getY();

            // Create a new motion Rect to be draw at every move.
            motionRect = new Rect((int) motionRectLeft, (int) motionRectTop, (int) motionRectRight, (int) motionRectBottom);

            // Permission to draw the motion Rect
            drawMotionRect = true;

            // Call onDraw method
            invalidate();

            break;

        case MotionEvent.ACTION_UP:

            // Do nothing.

    }

    return true;

}

protected void resizePictureToFitIntoScreen(){

    // O redimensionamento da foto é interessante, pois cada tela de celular
    // tem uma largura e altura, bem como cada foto. Dependendo das dimensões
    // da imagem, resizePictureToFitIntoScreen só um lado (e aplicar a razão largura/altura)
    // ao outro já dá certo. As vezes tem que resizePictureToFitIntoScreen duas vezes.

    differenceInHeight = originalPhoto.getHeight() - myDisplayHeight;
    differenceInWidth = originalPhoto.getWidth() - myDisplayWidth;

    // A largura e altura estão fora da tela.
    if(differenceInHeight > 0 && differenceInWidth > 0){

        // Começamos a resizePictureToFitIntoScreen pelo lado que está mais fora da tela, e depois
        // aplicamos ao outro, se necessário.
        if(differenceInHeight > differenceInWidth) {

            float ratio = (float) myDisplayHeight / originalPhoto.getHeight();

            scaledPhotoHeight_1 = ratio * originalPhoto.getHeight();
            scaledPhotoWidth_1 = ratio * originalPhoto.getWidth();

            // Neste ponto a altura da foto foi redimensionado para ser igual a altura da tela,
            // e a largura seguiu a proporção. Mas será que a largura ficou dentro da tela também?

            float difLargura_2 = scaledPhotoWidth_1 - myDisplayWidth;

            // A altura ficou fora da tela e tem que ser redimensionada
            if(difLargura_2 > 0){

                float ratio_2 = (float) myDisplayWidth / scaledPhotoWidth_1;

                scaledPhotoHeight_2 = ratio_2 * scaledPhotoHeight_1;
                scaledPhotoWidth_2 = ratio_2 * scaledPhotoWidth_1;

                // Fim, ambas as dimensões foram redimensionadas

            }

            else{

                scaledPhotoHeight_2 = scaledPhotoHeight_1;
                scaledPhotoWidth_2 = scaledPhotoWidth_1;

            }

        } else{

            float ratio = (float) myDisplayWidth / originalPhoto.getWidth();

            scaledPhotoHeight_1 = ratio * originalPhoto.getHeight();
            scaledPhotoWidth_1 = ratio * originalPhoto.getWidth();

            // Neste ponto a largura da foto foi redimensionado para ser igual a largura da tela,
            // e a altura seguiu a proporção. Mas será que a altura ficou dentro da tela também?

            float difAltura_2 = scaledPhotoHeight_1 - myDisplayHeight;

            // A altura ficou fora da tela e tem que ser redimensionada
            if(difAltura_2 > 0){

                float ratio_2 = (float) myDisplayHeight / scaledPhotoHeight_1;

                scaledPhotoHeight_2 = ratio_2 * scaledPhotoHeight_1;
                scaledPhotoWidth_2 = ratio_2 * scaledPhotoWidth_1;

                // Fim, ambas as dimensões foram redimensionadas

            }

            else{

                scaledPhotoHeight_2 = scaledPhotoHeight_1;
                scaledPhotoWidth_2 = scaledPhotoWidth_1;

            }

        }

        // Só 01 dimensão precisa ser ajustada
    } else if(differenceInHeight > 0 || differenceInWidth > 0){

        // Qual que tem que ser ajustada?
        if(differenceInHeight > 0) {

            float ratio = (float) myDisplayHeight / originalPhoto.getHeight();

            scaledPhotoHeight_1 = ratio * originalPhoto.getHeight();
            scaledPhotoWidth_1 = ratio * originalPhoto.getWidth();

        } else{

            float ratio = (float) myDisplayWidth / originalPhoto.getWidth();

            scaledPhotoHeight_1 = ratio * originalPhoto.getHeight();
            scaledPhotoWidth_1 = ratio * originalPhoto.getWidth();

        }

        scaledPhotoHeight_2 = scaledPhotoHeight_1;
        scaledPhotoWidth_2 = scaledPhotoWidth_1;

        // Nenhuma dimensão está fora da tela
    } else{

        scaledPhotoHeight_2 = originalPhoto.getHeight();
        scaledPhotoWidth_2 = originalPhoto.getWidth();

    }

    scaledPhoto = Bitmap.createScaledBitmap(originalPhoto, (int) scaledPhotoWidth_2, (int) scaledPhotoHeight_2, false);
    scaledPhotoRatio = (float) scaledPhoto.getHeight() / scaledPhoto.getWidth();

}

}

getWidth() 和 getHeight() returns 以像素为单位,但您输入了 dp。取决于设备分辨率,您可能会得到不同的值。

Difference between px and dp

我使用的基本计算

ldpi  : 0.75 x
mdpi  : 1x
hdpi  : 1.5x
xdpi  : 2x
xxdpi : 3x