Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size of a canvas

Tags:

android

I have an Android application, which has several fragments.

In one of these fragments, there is

  1. a lettering,
  2. custom view,
  3. two panels with buttons.

In the custom view (item 2) I need to draw several figures, one of which is tied to the size of the view, i. e. there should be a rectangle with rounded edges, whose size is equal to the size of the canvas minus padding.

In order to do this, I need to get the width and height of the canvas.

I tried following things:

  1. Get the dimensions of the view in the method onSizeChanged (new width/height).
  2. Get the dimensions of the view in the method onLayout.
  3. Get the dimensions of the view in onDraw method (canvas.getWidth()/getHeight(), View.getMeasuredWidth()/getMeasuredHeight()).

All three methods return the same width and height and all of them don't work - the figure is too narrow (fills only approx. 60 % of available space instead of 100 %) and too tall (the bottom of the figure is not visible).

What is the correct way to determine the dimensions (RectF instance) of a custom view?

Note that I test this application on a Nexus 7 emulator in landscape mode.

Update 1 (28.03.2013 21:42 MSK)

The XML file of the corresponding fragment:

<?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>

Here's the code of the view (@+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);
    }   
}

Here's the class for calculating the dimensions of the rounded rectangle:

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

Update 2:

Here's the screenshot:

Screenshot

Update 3 (31.03.2013 19:38 MSK): If I subtract 150 from the width reported by onLayout, onSizeChanged or onMeasure, the rectangle is displayed correctly.

Update 4 (05.04.2013 21:07 MSK): Here's the layout of the main activity:

<?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>
like image 781
Dmitrii Pisarenko Avatar asked Mar 28 '13 11:03

Dmitrii Pisarenko


People also ask

What is a good size for a canvas?

The ideal height of the canvas would be between 5.4 to 6.75 and the ideal width would between 3 feet and 3.75 feet. 2) When hanging wall art over furniture, such as a bed, a fireplace or a couch, it should be between 2/3 to 3/4 of the width of the furniture.

How big is a 12x9 canvas?

12" x 9" Canvas Prints Slightly larger than a standard piece of paper, a 12" x 9" canvas print is an extremely versatile size. This size makes for great gifts for any occasion, or can fit it any area of your home.


Video Answer


2 Answers

I see android:layout_height="wrap_content" for custom view.

In such a case, parent/container ViewGroup would like to know the content's height when measuring this View.

But, to draw the content, you depend on dimensions measured by layout, which still has no idea of the content's height.

Set android:layout_height to 0dp, which will allow android:layout_weight attribute to be used, and the View will then have a pre measured height according to space available.

Also, onSizeChanged() is sufficient to inform you about dimension changes, when layout is measured again.

like image 54
S.D. Avatar answered Nov 06 '22 02:11

S.D.


As per my comment on the question:

Your top-level layout: you've set content_fragment2's width to fill_parent, so it's going to be the same width as its parent linearlayout. You probably want menu_pane to have a fixed width, no layout_weight, and for content_fragment2 to have layout_width=0px and layout_weight=1.

Glad this helped!

like image 35
Reuben Scratton Avatar answered Nov 06 '22 00:11

Reuben Scratton