Size of a canvas

android

Solution

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!

Problem

I have an Android application, which has several fragments. In one of these fragments, there is - a lettering, - custom view, - 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: - Get the dimensions of the view in the method `onSizeChanged` (new width/height). - Get the dimensions of the view in the method `onLayout`. - 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: 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> ```

Original source