Java getChildDrawingOrder调用/使用不稳定?
我正在用简单的平铺创建一个等轴测地图,并扩展了Java getChildDrawingOrder调用/使用不稳定?,java,android,drawing,Java,Android,Drawing,我正在用简单的平铺创建一个等轴测地图,并扩展了RelativeLayout,以创建一个包含这些平铺的布局。实际上,只要我的方向与写入XML文件的瓷砖顺序相匹配,就可以使用RelativeLayoutas;我所覆盖的是构造函数,我只需调用super和setChildrenDrawingOrderEnabled(true)以及设置一些变量(网格的高度和宽度),然后getChildDrawingOrder本身 我的getChildDrawingOrder代码计算出给定子项的新索引,并将子项中的字符串设
RelativeLayout
,以创建一个包含这些平铺的布局。实际上,只要我的方向与写入XML文件的瓷砖顺序相匹配,就可以使用RelativeLayout
as;我所覆盖的是构造函数,我只需调用super
和setChildrenDrawingOrderEnabled(true)
以及设置一些变量(网格的高度和宽度),然后getChildDrawingOrder
本身
我的getChildDrawingOrder
代码计算出给定子项的新索引,并将子项中的字符串设置为i->i'
,其中i
是原始索引,i'
是新索引。我用它来测试;孩子们被设置为在自己身上绘制这个字符串以及他们的坐标
不幸的是,它不能正常工作,或者说它工作不稳定。在我的测试用例中的九个tile中,有三个似乎根本没有调用getChildDrawingOrder
:我上面提到的字符串是null
。在其余的部分中,尽管得到了正确的索引,但至少有一个是无序绘制的
这是一张图片(在顶部
方向):
请注意,(0,2)、(1,2)和(2,1)都列为NULL
,因此似乎从未为它们调用过getChildDrawingOrder
。还请注意,(1,0)绘制在(1,1)的顶部,即使其i
(3)和i'
(1)都小于(1,1)(分别为4和4)
以下是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;
}
}
@覆盖
受保护的int getChildDrawingOrder(int childCount,int i)
{
TileView ch=(TileView)getChildAt(i);
ch.order=“Called”;//这个字符串是在我的孩子身上画的
int gx,gy;//当前旋转的“真”x,y,
//其中0,0是顶角
开关(旋转)
{
案例顶部:
gx=ch.x();
gy=ch.y();
打破
案例左:
gx=(宽度()-1通道x());
gy=ch.y();
打破
案例权利:
gx=ch.x();
gy=(长度()-1通道y());
打破
箱底:
gx=(宽度()-1通道x());
gy=(长度()-1通道y());
打破
违约:
gx=ch.x();
gy=ch.y();
}
int row=gx+gy;//当前行
if(row==0)//第0行始终仅为上角,第0行
{
ch.order=新字符串(i+“->0”);//字符串设置为i->i'
返回0;
}
其他的
{
int mx=width()-1,//最大x值
my=length()-1,//最大y值
mrow=mx+my,//最大行数
min=Math.min(mx,my),//短轴长度
maj=Math.max(mx,my),//长轴长度
retn;//用于存储返回值
//在顶角内
如果(第一排)
返回retn;
}
}
有人能解释一下发生了什么吗?为什么没有为这三个tile调用
getChildDrawingOrder
?为什么是(1,0)以错误的顺序绘制,即使调用了getChildDrawingOrder
。好的,通过查看Android源代码来解决。我有getChildDrawingOrder
的映射:传递的I
是“我应该绘制哪个孩子?”而不是“我应该何时绘制孩子I?”NULL
s的原因是,这些子对象是在传递自己的i
之前绘制的
在测量过程中,我更改了代码以确定所有子项的顺序,并将其保存在一个SparseIntArray
中,然后从getChildDrawingOrder
返回。这很有效
顺便说一句,在
getChildDrawingOrder
函数中反向计算索引是个坏主意,除非您想依赖于子项声明的顺序。因为如果您不依赖于该顺序,您必须遍历子项列表以找到具有适当x和y值的子项,这意味着您必须浏览每个子项的子项列表。这是一个O(n²)操作(阅读:效率相当低)。数学也相当复杂。下面是一个简单的示例,演示如何覆盖getChildDrawingOrder
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>
因此,从第一个到最后一个(或从下到上考虑),即:红色、绿色、蓝色。下面是调用的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
右边显示了第二次点击后的外观,因为顺序变为:蓝色、红色、绿色
V/View: getChildDrawingOrder returnValue=2 i=0
V/View: getChildDrawingOrder returnValue=0 i=1
V/View: getChildDrawingOrder returnValue=1 i=2
在此之后的任何点击都会将其循环回原来的顺序,由于模数计算,蓝色最后一次被绘制
HTHs!我觉得这需要更多的介绍。我已经远离Android开发多年了,所以我必须深入了解这段代码并理解它在做什么。如果不这样做,我甚至无法判断这是否是一个好答案。更多关于
getChildDrawingOrder
及其工作原理/使用方法的解释我想这会有帮助。我会添加一些图像来说明
V/View: getChildDrawingOrder returnValue=2 i=0
V/View: getChildDrawingOrder returnValue=0 i=1
V/View: getChildDrawingOrder returnValue=1 i=2