0

I am trying to build a custom view but there seems to be something that I am not getting.

I have overriden the onSizeChanged and onDraw methods and added my custom view in the activity layout and given it a height of say 100dp and pinned it to the bottom and start and end of the parent relative layout. However the view doesn't render correctly and there is a blank empty space beneath it.

below is my onDraw and onSizedChanged methods

 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        viewHeight = h;
        viewWidth = w;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // draw background
        painter.setStrokeWidth(viewHeight);
        painter.setColor(Color.BLUE);
        canvas.drawLine(0, 0, viewWidth, 0, painter);
    }

below is how I am adding the view to the layout xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_registration"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.example.activities.RegistrationActivity">

        <com.example.custom.widgets.MyCustomView
            android:id="@+id/holder"
            android:layout_alignParentEnd="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentBottom="true"
            android:layout_width="match_parent"
            android:layout_height="100dp"/>

    <FrameLayout
        android:layout_above="@+id/holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button
            android:text="kjdgfjkasdgfjkahsdgfjkhsa"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
</RelativeLayout>

this is how it looksenter image description here

FWIW, I also trying embedding my custom view inside a FrameLayout and explicitly setting the height of the FrameLayout and setting the height of my custom view to match_parent. still no success.

Fouad
  • 855
  • 1
  • 11
  • 30
  • Still, the problem you are trying to solve is mysterious for me. Do you want your custom view to be 100dp height blue line only? – azizbekian Feb 18 '17 at 10:18
  • @azizbekian I want my custom view to take as much height as specified in the layout_height property which in this case it's 100dp – Fouad Feb 18 '17 at 10:19
  • `painter.setStrokeWidth(viewHeight);` Is the logics behind this line correct? Are you trying to set the width of the stroke 100dp? – azizbekian Feb 18 '17 at 10:22
  • @azizbekian painter.setStrokeWidth(viewHeight); is supposed to draw based on my understanding a line of 100dp or the equivalent in pixels – Fouad Feb 18 '17 at 10:23
  • 1
    Nope. `canvas.drawLine(0, 0, viewWidth, 0, painter);` will actually draw the line. `painter.setStrokeWidth(viewHeight);` specifies how thick the line you want to be. Just set it to, let's say, 10, and see the difference. – azizbekian Feb 18 '17 at 10:24
  • @azizbekian, I want the line drawn by painter.setStrokeWidth(viewHeight); to be as high as the component. in other words if my custom view is 100dp high I want to draw a line that is 100dp thick – Fouad Feb 18 '17 at 10:27
  • Then why do you want to draw a line? Just set background color to the view: `setBackgroundColor(R.color.blue)`. – azizbekian Feb 18 '17 at 10:31
  • I am trying to create this [component](http://imgur.com/a/c8ZWV) I thought I would start by drawing a black background then draw the text then draw the yellow foreground. The blue color used above is just for testing purposes – Fouad Feb 18 '17 at 10:35
  • Fine. So particularly in this step you only want your view to have black background with height of that much, that is specified in xml. For that problem you do not have to save the value in onSizeChanged and then draw a line. You may set background color to your view from constructor. And your view will be drawn 100dp (as specified in xml) and with black color, no actions needed from your side. – azizbekian Feb 18 '17 at 10:38
  • ok, I am starting to get it. so I should set a black background to the view in xml using `android:background="@color/black"` then how would I draw the yellow foreground to have a height as high as the component? – Fouad Feb 18 '17 at 10:42
  • You shouldn't know the height of the component. In `onDraw()` method the view is already measured, so you know the exact sizes of it. You can get the height of your custom view by `getHeight()` and `getWidth()`. This will return sizes in pixels. Later you may make calculations to draw each sections. E.g. you have 4 items (50, 75, 80, 90%), each one should take `getWidth() / 4` length. – azizbekian Feb 18 '17 at 10:45

1 Answers1

0

Overriding onMeasure() in your custom view class will set the size of your view dependent on the layout constraints provided by the parent.

This should give your custom view a height of 100dp:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = Math.min(100, MeasureSpec.getSize(heightMeasureSpec));
    setMeasuredDimension(width, height);
}

If you change the parent's constraints, you will need to change the MeasureSpec values that are passed into the method. See this question: https://stackoverflow.com/a/12267248/7395923

Change the onDraw() method to this:

protected void onDraw(Canvas canvas) {
    // draw background
    painter.setStrokeWidth(getWidth());
    painter.setColor(Color.BLUE);
    canvas.drawLine(0, 0, getWidth(), 0, painter);
}

And remove the onSizeChanged() method.

Community
  • 1
  • 1
aneurinc
  • 1,238
  • 12
  • 20