Подтвердить что ты не робот

Размер холста

У меня есть приложение для Android, которое имеет несколько фрагментов.

В одном из этих фрагментов есть

  • надпись,
  • пользовательский вид,
  • две панели с кнопками.

В пользовательском представлении (пункт 2) мне нужно нарисовать несколько цифр, один из которых привязан к размеру вида, т.е. е. должен быть прямоугольник с закругленными краями, размер которого равен размеру холста минус заполнение.

Чтобы сделать это, мне нужно получить ширину и высоту холста.

Я пробовал следующие вещи:

  • Получить размеры представления в методе onSizeChanged (новая ширина/высота).
  • Получить размеры представления в методе onLayout.
  • Получить размеры представления в методе onDraw (canvas.getWidth()/getHeight(), View.getMeasuredWidth()/getMeasuredHeight()).

Все три метода возвращают ту же ширину и высоту, и все они не работают - фигура слишком узкая (заполняет только около 60% доступного пространства вместо 100%) и слишком высока (нижняя часть рисунка не отображается).

Каков правильный способ определения размеров (RectF instance) пользовательского представления?

Обратите внимание, что я тестирую это приложение на эмуляторе Nexus 7 в ландшафтном режиме.

Обновление 1 (28.03.2013 21:42 MSK)

XML файл соответствующего фрагмента:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/simulation_fragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Simulation"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <co.mycompany.ccp.android.impl.simulationcanvas.SimulationCanvasView
        android:id="@+id/simulation_canvas_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.8" />

    <LinearLayout
        android:id="@+id/simulationExecutionPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.1" >

        <Button
            android:id="@+id/restartSimulationButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/restart_simulation" />

        <Button
            android:id="@+id/simulationStepButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/simulation_step" />

        <Button
            android:id="@+id/pauseButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/pause" />

        <Button
            android:id="@+id/continueButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/continue_button" />

        <Button
            android:id="@+id/simulateAdInfinitumButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/simulate_ad_infinitum" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/currentCycleLabel" />

        <TextView
            android:id="@+id/currentCycleIndicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cycle"
            android:textAppearance="?android:attr/textAppearanceMedium" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.1" >

        <Button
            android:id="@+id/addCompanyButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/add_company2" />

        <Button
            android:id="@+id/removeCompanyButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/remove_company" />

        <Button
            android:id="@+id/setLabourForceButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/set_labour_force" />
    </LinearLayout>

</LinearLayout>

Здесь код представления (@+id/simulation_canvas_view):

import co.mycompany.ccp.android.api.economypartsdimensioncalculator.EconomyPartsDimensionCalculator;
import co.mycompany.ccp.android.api.systemboundary.SystemBoundaryGraphicsCalculator;
import co.mycompany.ccp.android.impl.economypartsdimensioncalculator.DefaultEconomyPartsDimensionCalculator;
import co.mycompany.ccp.android.impl.systemboundary.DefaultSystemBoundaryGraphicsCalculator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * @author DP118M
 * 
 */
public class SimulationCanvasView extends View {

    private static final int SYSTEM_BOUNDARY_COLOUR = Color.LTGRAY;

    [...]

    private int width = -1;
    private int height= -1;
    private SystemBoundaryGraphicsCalculator systemBoundaryGraphicsCalculator = new DefaultSystemBoundaryGraphicsCalculator();
    [...]
    private Rect systemBoundaryDimensions = new Rect(100, 100, 100 + 100,
            100 + 100);
    private Rect externalEconomyDimensions;

    [...]

    public SimulationCanvasView(final Context aContext) {
        super(aContext);
    }

    public SimulationCanvasView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    public SimulationCanvasView(final Context context,
            final AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    [...]

    private void updateSystemBoundaryGraphicsCalculatorDimensions() {
        systemBoundaryGraphicsCalculator.setCanvasHeight(height);
        systemBoundaryGraphicsCalculator.setCanvasWidth(width);
        try {
            systemBoundaryGraphicsCalculator.run();
            systemBoundaryDimensions = systemBoundaryGraphicsCalculator
                    .getSystemBoundaryDimensions();
        } catch (final Exception exception) {
            throw new RuntimeException(exception);
        }
    }

    @Override
    protected void onDraw(final Canvas aCanvas) {
        super.onDraw(aCanvas);

        this.width = this.getWidth();
        this.height = this.getHeight();

        updateSystemBoundaryGraphicsCalculatorDimensions();         

        [...]

        drawRectangleWithRoundedEdges(aCanvas, systemBoundaryDimensions,
                SYSTEM_BOUNDARY_COLOUR);

        [...]
    }

    private void drawRectangleWithRoundedEdges(final Canvas aCanvas,
            final Rect aDimensions, int aStrokeColour) {
        final Paint paint = new Paint();

        paint.setColor(aStrokeColour);
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.STROKE);

        aCanvas.drawRoundRect(new RectF(aDimensions), 20, 20, paint);
    }   
}

Здесь класс для вычисления размеров закругленного прямоугольника:

package co.mycompany.ccp.android.impl.systemboundary;

import android.graphics.Rect;
import co.mycompany.ccp.android.api.systemboundary.SystemBoundaryGraphicsCalculator;

/**
 * @author DP118M
 * 
 */
public class DefaultSystemBoundaryGraphicsCalculator implements
        SystemBoundaryGraphicsCalculator {
    private int canvasWidth;
    private int canvasHeight;
    private int xPadding = SYSTEM_BOUNDARY_X_PADDING;
    private int yPadding = SYSTEM_BOUNDARY_Y_PADDING;
    private Rect systemBoundaryDimensions;

    public void setXPadding(final int xPadding) {
        this.xPadding = xPadding;
    }

    public void setYPadding(final int yPadding) {
        this.yPadding = yPadding;
    }

    @Override
    public Rect getSystemBoundaryDimensions() {
        return systemBoundaryDimensions;
    }

    @Override
    public void setCanvasWidth(final int width) {
        this.canvasWidth = width;
    }

    @Override
    public void setCanvasHeight(final int height) {
        this.canvasHeight = height;
    }

    @Override
    public void run() throws Exception {
        this.systemBoundaryDimensions = new Rect(0 + xPadding, 0 + yPadding,
                Math.max(this.canvasWidth - xPadding, 0), Math.max(
                        this.canvasHeight - yPadding, 0));
    }
}

Обновление 2:

Вот скриншот:

Screenshot

Обновление 3 (31.03.2013 19:38 MSK): Если вычесть 150 из ширины, сообщенной onLayout, onSizeChanged или onMeasure, прямоугольник отображается правильно.

Обновление 4 (05.04.2013 21:07 MSK): Здесь макет основной деятельности:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/menu_pane"
        android:layout_width="0px"
        android:layout_height="match_parent"
        android:layout_weight="1"
        class="co.altruix.ccp.android.impl.fragments.MenuFragment" />

    <FrameLayout
        android:id="@+id/content_fragment2"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        class="co.altruix.ccp.android.impl.fragments.ContentFragment2"/>

</LinearLayout>
4b9b3361

Ответ 1

В соответствии с моим комментарием по вопросу:

Ваш макет верхнего уровня: вы установили ширину content_fragment2 в fill_parent, поэтому он будет иметь ту же ширину, что и его parent linearlayout. Вероятно, вы хотите, чтобы в menu_pane была фиксированная ширина, нет layout_weight, а для content_fragment2 - layout_width = 0px и layout_weight = 1.

Рад, что это помогло!

Ответ 2

Я вижу android:layout_height="wrap_content" для пользовательского представления.

В таком случае parent/container ViewGroup хотел бы знать высоту содержимого при измерении этого представления.

Но для рисования контента вы зависите от размеров, измеренных макетом, которые до сих пор не имеют представления о высоте содержимого.

Установите android:layout_height в 0dp, что позволит использовать атрибут android:layout_weight, и тогда представление будет иметь предварительно измеренную высоту в соответствии с доступным пространством.

Кроме того, onSizeChanged() достаточно, чтобы информировать вас об изменениях размеров, когда макет снова измеряется.

Ответ 3

Попробуйте следующее:

view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
        @Override
        public void onGlobalLayout() {

        //capture view width and height here

    }//end onGlobalLayout()

        });

См. getViewTreeObserver().