我正在创建一个包含简单图块的等轴测图,我已经扩展RelativeLayout
来创建一个包含这些图块的布局。实际上,只要我的方向与将图块写入XML文件的顺序相匹配,只需使用RelativeLayout
as-is就可以正常工作;所有我覆盖的都是构造函数,我只需调用super
和setChildrenDrawingOrderEnabled(true);
以及设置一些变量(网格的高度和宽度),然后调用getChildDrawingOrder
本身。
我的getChildDrawingOrder
代码计算出给定孩子的新索引,并将子项中的字符串设置为i->i'
,其中i
是原始索引,{{1是新索引。我正在用它进行测试;孩子们被设置为在他们自己的坐标上绘制这个字符串。
不幸的是,它无法正常工作,或者说工作不正常。在我测试用例中的九个tile中,有三个看起来根本没有调用i'
:我上面提到的字符串是getChildDrawingOrder
。其余的,尽管传递了正确的索引,但至少有一个被抽出。
这是一张图片(null
方向):
请注意,(0,2),(1,2)和(2,1)都列为TOP
,因此NULL
似乎从未被调用过。另请注意,(1,0)绘制在(1,1)之上,即使getChildDrawingOrder
(3)和i
(1)都小于(1,1) (分别为4和4)。
以下是i'
的代码:
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;
}
}
?为什么(1,0)以错误的顺序绘制,即使在其上调用getChildDrawingOrder
?
答案 0 :(得分:11)
好的,通过查看Android源代码来搞清楚。我有getChildDrawingOrder
的映射:i
传递的是“我应该画哪个孩子我?”而不是“我什么时候应该画孩子?” NULL
s的原因是因为这些孩子在他们自己i
被传递之前被抽出。
我更改了代码以确定onMeasure
次传递期间所有孩子的顺序,将其保存在SparseIntArray
中,然后从getChildDrawingOrder
返回。这很有效。
顺便说一下,在getChildDrawingOrder
函数中反向计算索引是一个坏主意,除非你想依赖于子句被声明的顺序。因为如果您不依赖于该顺序,则必须遍历子项列表以查找具有相应x和y值的子项,这意味着您必须遍历每个子项的子项列表。这是一个O(n²)操作(读:相当低效)。数学也相当复杂。
答案 1 :(得分:2)
这是一个简单的示例,演示如何覆盖.as-console-wrapper { max-height: 100% !important; top: 0; }
RelativeLayout类:
getChildDrawingOrder
xml布局
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);
}
}
看起来像什么
左图是起始绘图顺序,这是基于xml布局的默认设置:
<?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>
所以从头到尾(或从下到上思考)是:红色,绿色,蓝色。这是被称为Red = index 0
Green = index 1
Blue = index 2
的日志转储
getChildDrawingOrder
在中间,我们第一次点击后,订单变为绿色,蓝色,红色
V/View: getChildDrawingOrder returnValue=0 i=0
V/View: getChildDrawingOrder returnValue=1 i=1
V/View: getChildDrawingOrder returnValue=2 i=2
并且,在右侧显示我们在订单更改为“蓝色,红色,绿色”后第二次点击后的样子。
V/View: getChildDrawingOrder returnValue=1 i=0
V/View: getChildDrawingOrder returnValue=2 i=1
V/View: getChildDrawingOrder returnValue=0 i=2
在此之后的任何点击几乎将其循环回原始顺序,其中由于模数计算而最后绘制蓝色
HTHS!