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 RelativeLayout
as-is worked fine as long as my orientation matched the order in which the tiles were written to the XML file; all I’ve overwritten are the constructors, where I simply call super
and setChildrenDrawingOrderEnabled(true);
along with setting up some variables (height and width of the grid), and then getChildDrawingOrder
itself.
My code for getChildDrawingOrder
figures out the new index for the given child, and also sets a string in the child to i->i'
, where i
is the original index and i'
is the new index. I’m using this for testing; the children are set to draw this string on themselves along with their coordinates.
Unfortunately, it does not work correctly, or rather it works erratically. Of the nine tiles in my test case, three don’t seem to have getChildDrawingOrder
called at all: the string I mentioned above is null
. Of the rest, at least one is being drawn out of order despite getting the correct index passed to it.
Here’s a picture (in the TOP
orientation):
Notice that (0,2), (1,2), and (2,1) are all listed as NULL
, and therefore getChildDrawingOrder
appears to have never been called for them. Also note that (1,0) is drawn on top of (1,1), even though both its i
(3) and i'
(1) are less than (1,1)’s (4 and 4, respectively).
Here’s the code from getChildDrawingOrder
:
@Override
protected int getChildDrawingOrder(int childCount, int i)
{
TileView ch = (TileView)getChildAt(i);
ch.order = "Called"; // this string is drawn on my children
int gx, gy; // the "true" x,y for the current rotation,
// where 0,0 is the top corner
switch (rotation)
{
case TOP:
gx = ch.x();
gy = ch.y();
break;
case LEFT:
gx = (width()-1-ch.x());
gy = ch.y();
break;
case RIGHT:
gx = ch.x();
gy = (length()-1-ch.y());
break;
case BOTTOM:
gx = (width()-1-ch.x());
gy = (length()-1-ch.y());
break;
default:
gx = ch.x();
gy = ch.y();
}
int row = gx+gy; // current row
if ( row == 0 ) // row 0 is always just the top corner and 0
{
ch.order = new String(i+"->0"); // string set to i->i'
return 0;
}
else
{
int mx = width()-1, // maximum x value
my = length()-1, // maximum y value
mrow = mx+my, // maximum row
min = Math.min(mx, my), // minor axis length
maj = Math.max(mx, my), // major axis length
retn; // for storing the return value
// inside the top corner
if ( row <= min )
{
// Gauss's formula to get number of cells in previous rows
// plus the number for which cell in this row this is.
retn = row*(row+1)/2+gy;
}
// in the middle
else if ( row <= maj )
{
// Gauss's formula to get number of cells in top corner
// plus the number of cells in previous rows of the middle section
// plus the number for which cell in this row this is.
retn = min*(min+1)/2+min*(row-min)+gy;
}
// bottom corner
else
{
retn = (min+1)*(min+2)/2 // cells in the top corner
+ min*(maj-min) // cells in the middle
+ (mrow-maj)*(mrow-maj+1)/2 // total cells in bottom triangle
- (mrow-row+1)*(mrow-row+2)/2 // less cells after this one
+ gy // which cell in this row
- (row-maj) // to account for gy not starting at zero
;
}
ch.order = new String(i+"->"+retn); // string set to i->i'
return retn;
}
}
Can anyone shed some light on what’s going on? Why isn’t getChildDrawingOrder
being called for those three tiles? Why is (1,0) drawn in the wrong order, even though getChildDrawingOrder
is called on it?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With