I am creating an isometric map with simple tiles, and I’ve extended RelativeLayout
to create a layout that holds these tiles. Really, just using a R
OK, figured it out by looking at the Android source code. I had the mapping of getChildDrawingOrder
: the i
passed is “which child should I draw i th?” not "when should I draw child i?" The reason for the NULL
s is because those children were being drawn before their own i
was passed.
I changed my code to figure out the order for all children during the onMeasure
pass, saving that in a SparseIntArray
, and then just returned that from getChildDrawingOrder
. This works.
Back-calculating the index in the getChildDrawingOrder
function, by the way, is a bad idea unless you want to rely on the order in which the children are declared. Because if you don’t rely on that order, you have to walk through the list of children to find the one that has the appropriate x and y values, which means you have to walk through the list of children for each child. That’s an O(n²) operation (read: fairly inefficient). The mathematics are also reasonably complicated.
Here is a simple example that shows how to override getChildDrawingOrder
The RelativeLayout class:
public class AlternatingChildDrawingOrderRelativeLayout extends RelativeLayout {
// the childDrawingOrder modifier
private int childDrawingOrderModifier = 0;
public AlternatingChildDrawingOrderRelativeLayout(Context context) {
super(context);
init(context);
}
void init(Context context) {
setClickable(true);
setChildrenDrawingOrderEnabled(true);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// increment to adjust the child drawing order
childDrawingOrderModifier++;
// call invalidate to redraw with new order modifier
ViewCompat.postInvalidateOnAnimation(v);
}
});
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
// increment i with the modifier, then afford for out of bounds using modulus of the child count
int returnValue = (i + childDrawingOrderModifier) % childCount;
Log.v(VIEW_LOG_TAG, "getChildDrawingOrder returnValue=" + returnValue + " i=" + i);
return returnValue;
}
public AlternatingChildDrawingOrderRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AlternatingChildDrawingOrderRelativeLayout(Context context,
AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public AlternatingChildDrawingOrderRelativeLayout(Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
}
The xml layout
<?xml version="1.0" encoding="utf-8"?>
<com.example.ui.AlternatingChildDrawingOrderRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="300dp">
<View
android:id="@+id/red"
android:layout_width="125dp"
android:layout_height="300dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="#f00"
/>
<View
android:id="@+id/green"
android:layout_width="125dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:background="#0f0"/>
<View
android:id="@+id/blue"
android:layout_width="125dp"
android:layout_height="300dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="#00f"/>
</com.example.ui.AlternatingChildDrawingOrderRelativeLayout>
What it looks like
Pictured on the left is the starting drawing order, which is the default based on the xml layout:
Red = index 0
Green = index 1
Blue = index 2
So from first to last (or think bottom to top) that is: Red, Green, Blue. Here is the log dump of getChildDrawingOrder
being called
V/View: getChildDrawingOrder returnValue=0 i=0
V/View: getChildDrawingOrder returnValue=1 i=1
V/View: getChildDrawingOrder returnValue=2 i=2
In the middle, after our first tap, the order changes to Green, Blue, Red
V/View: getChildDrawingOrder returnValue=1 i=0
V/View: getChildDrawingOrder returnValue=2 i=1
V/View: getChildDrawingOrder returnValue=0 i=2
And, on the right side shows us what it looks like after our second tap since the order change to: Blue, Red, Green.
V/View: getChildDrawingOrder returnValue=2 i=0
V/View: getChildDrawingOrder returnValue=0 i=1
V/View: getChildDrawingOrder returnValue=1 i=2
Any tap after this pretty much loops it back to the original order where blue was last to be drawn due to the modulus calculation
HTHs!