whompum whompum - 19 days ago 5
Android Question

My custom view is being clipped if its position is not (0,0)

My problem is that if i set the Y-axis of my view to anything but 0 its drawn region gets clipped from the top. Using log traces i've discovered that the view bounds (and its drawable's bounds) are always the correct position. I've tried clipChildren=false, but that gave me a stranger behavior where the drawn region and the views bounds are not in sync. Here's all pertinent code to my view

//onMeasure
@Override
public void onMeasure(int w, int h){
int width = MeasureSpec.getSize(w);
//minHeight is 48dp scaled for density
setMeasuredDimension(width, minHeight);
}


//onDraw
//Note that i've ommited the log statements, however they return the correct
//coordinates for the view Rect
@Override
public void onDraw(Canvas c){
c.drawRect(trackRect, tempPaint);
}

//onLayout
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
trackRect.set(left, top, right, bottom);
mTrack.setBounds(trackRect); //irrelevant atm
}

//XML CODE

//BELOW draws a perfect rectangle with a width of match_parent and a height
//of 48dp

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" >


<com.bryanstudios.bryan.clock.LocationSwitch
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</RelativeLayout>

//BELOW will cause clipping
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">

<com.bryanstudios.bryan.clock.LocationSwitch
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</RelativeLayout>

//BELOW causes the view to disappear entirely
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">

<com.bryanstudios.bryan.clock.LocationSwitch
android:align_parent_bottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</RelativeLayout>


My best guess is my onMeasure isn't done properly. Also note again that regardless of where i position the view (via w/ margins or LayoutParam attributes) the logical positioning of the view is accurate, yet the drawn region is not.

Tom Tom
Answer
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
   trackRect.set(left, top, right, bottom);
   ...

The left/top/etc params here are relative to the parent. If your view's y position == 0, top also == 0. If you change the view's Y position relative to its parent, top is set to that same value. You are then assigning this top to the rect you draw.

public void onDraw(Canvas c){ 
   c.drawRect(trackRect, tempPaint);
   ...

This will draw a rectangle with the same offsets you have specified in onLayout. This means that it will begin drawing trackRect.top from the top of the view.

If you just want the actual size of the view, view.getWidth() and view.getHeight() are likely all that is needed; if you want to initialise something (like a Path) when the width and height of the view are known, override onSizeChanged() and do it in there instead of in onLayout().