Question

I have been facing a problem with a custom view I coded. Basically, I have a custom view which handles different part of a seat, with different states. I managed to code it, and it was working perfectly.
Since the app was getting a bit slow, I decided to crop the images: instead of taking the whole screen with transparency, it only takes a part of the screen (I didn’t do the graphics).

But since I have cropped the images, they are messing up my layout. And I have no idea why, because when I replace my custom view with an ImageView, it’s fitting perfectly!
It looks like my view is ignoring “wrap_content”, and takes more than what it needs. Setting the value to “match_parent” didn’t work either.

I tried cropping my images again, I thought it was because of the size, but it is not. I tried overriding the onMeasure method, no change. And I don’t want to hardcode the size, because I feel like it’s a bad thing to do.

Why is this happening, and how do I fix it?

Here are some of my code snippets.

fragment_lumbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Main screen -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background_logo">

    <!-- Left menu with control buttons -->

    <RelativeLayout
        android:id="@+id/lumbar_control"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="61dp">

        <ImageButton
            android:id="@+id/button_arrowup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="40dp"
            android:background="@drawable/arrowup_button"
            android:contentDescription="@string/moveup_lumbar" />

        <!-- Plus/minus buttons -->

        <ImageButton
            android:id="@+id/button_plus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/button_arrowup"
            android:layout_centerVertical="true"
            android:background="@drawable/plus_button"
            android:contentDescription="@string/inflate_lumbar" />

        <ImageButton
            android:id="@+id/button_minus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/button_arrowup"
            android:layout_toRightOf="@id/button_plus"
            android:layout_marginLeft="90dp"
            android:background="@drawable/minus_button"
            android:contentDescription="@string/deflate_back" />

        <!-- Arrown down button -->

        <ImageButton
            android:id="@+id/button_arrowdown"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/button_plus"
            android:layout_centerHorizontal="true"
            android:background="@drawable/arrowdown_button"
            android:contentDescription="@string/movedown_lumbar" />

        <!-- Home button -->


    </RelativeLayout>

    <!-- Right panel -->

    <!-- Screen -->

    <FrameLayout
        android:id="@+id/center_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="7dp"
        android:layout_toRightOf="@id/lumbar_control"
        android:background="@drawable/screen" >

       <TextView
        android:id="@+id/text_state"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_margin="10dp"
        android:textSize="32sp"
        android:gravity="center"
        android:textColor="@color/white"
        android:text="hello"/>

        <!-- Seat screen -->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/seat"
            android:src="@drawable/lumbar_control_seat"/>

        <com.SeatStateView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/lumbar_seat_state"
            android:id="@+id/lumbar_seat_state" />

    </FrameLayout>

    <!-- Home button -->
    <Button
        android:id="@+id/button_home"
        android:layout_width="332dp"
        android:layout_height="44dp"
        android:layout_centerHorizontal="true"
        android:background="@android:color/transparent"
        android:layout_alignParentBottom="true"
        android:contentDescription="@string/home_button"/>
</RelativeLayout>

lumbar_seat_state:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/lumbar_seat_state_1" />
    <item android:drawable="@drawable/lumbar_seat_state_2" />
    <item android:drawable="@drawable/lumbar_seat_state_3" />
</layer-list>

lumbar_seat_state_1:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com">

    <item android:drawable="@drawable/lumbar_inflate_1"
        app:state_inflating="true" />
    <item android:drawable="@drawable/lumbar_deflate_1"
        app:state_deflating="true" />
    <item android:drawable="@drawable/lumbar_idle_1" />
</selector>

SeatStateView.java:

public class SeatStateView extends View {

    /* Custom states */
    private static final int[] INFLATING_STATE_SET = {
        R.attr.state_inflating
    };

    private static final int[] DEFLATING_STATE_SET = {
        R.attr.state_deflating
    };

    private static final int[] HEATING_STATE_SET = {
        R.attr.state_heating
    };

    private static final int[] COOLING_STATE_SET = {
        R.attr.state_cooling
    };

    /* Inflate/Deflate state */
    private boolean isInflating = false;
    private boolean isDeflating = false;

    /* Heating state */
    private boolean isHeating = false;
    private boolean isCooling = false;

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

    // Overrides the onCreateDrawable to add our custom states
    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);

        // Checking the states
        if(isInflating) {
            mergeDrawableStates(drawableState, INFLATING_STATE_SET);
        }

        if(isDeflating) {
            mergeDrawableStates(drawableState, DEFLATING_STATE_SET);
        }

        if(isHeating) {
            mergeDrawableStates(drawableState, HEATING_STATE_SET);
        }

        if(isCooling) {
            mergeDrawableStates(drawableState, COOLING_STATE_SET);
        }

        return drawableState;
    }

    @Override
    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
       super.onMeasure(widthMeasureSpec, heightMeasureSpec);

       int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
       int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
       this.setMeasuredDimension(parentWidth, parentHeight);
    }

    /**
     * Clears all the states and set to idle.
     */

    public void setIdle() {
        isInflating = isDeflating = false;

        // Refresh view
        refreshDrawableState();
    }

    public void setInflating(boolean state) {
        if(isInflating != state) {
            // Update all the states
            isInflating = state;

            if(isInflating) {
                isDeflating = false;
            }

            // Refresh view
            refreshDrawableState();
        }
    }

    public void setDeflating(boolean state) {
        if(isDeflating != state) {
            // Update all the states
            isDeflating = state;

            if(isDeflating) {
                isInflating = false;
            }

            // Refresh view
            refreshDrawableState();
        }
    }

    public void setHeating(boolean state) {
        if(isHeating != state) {
            isHeating = state;

            if(state) {
                isCooling = false;
            }

            // Refresh view
            refreshDrawableState();
        }
    }

    public void setCooling(boolean state) {
        if(isCooling != state) {
            isCooling = state;

            if(state) {
                isHeating = false;
            }

            // Refresh view
            refreshDrawableState();
        }
    }
}
Was it helpful?

Solution

Well, just searched more. Found out that I didn’t override my onMeasure method correctly. Here is my new implementation if someone stumbles upon this question:

SeatStateView.java:

@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){

    // Background image’s size
    int desiredWidth = getBackground().getIntrinsicWidth();
    int desiredHeight = getBackground().getIntrinsicHeight();

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    // Final size
    int width, height;

    // Set width depending on mode
    if(widthMode == MeasureSpec.EXACTLY) {
        width = widthSize;
    }
    else if(widthMode == MeasureSpec.AT_MOST) {
        width = Math.min(desiredWidth, widthSize);
    }
    else {
        width = desiredWidth;
    }

    // Set height depending on mode
    if(heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
    }
    else if(widthMode == MeasureSpec.AT_MOST) {
        height = Math.min(desiredHeight, heightSize);
    }
    else {
        height = desiredHeight;
    }

    // Finally, set dimension
    setMeasuredDimension(width, height);
}

For details, check this page: onMeasure custom view explanation.

Sorry for bothering you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top