6

我正在创建一个带有简单图块的等距地图,并且我已经扩展RelativeLayout以创建一个包含这些图块的布局。真的,RelativeLayout只要我的方向与将图块写入 XML 文件的顺序相匹配,就可以正常使用原样;我所覆盖的只是构造函数,我只是在其中调用supersetChildrenDrawingOrderEnabled(true);设置一些变量(网格的高度和宽度),然后是getChildDrawingOrder它本身。

我的代码用于getChildDrawingOrder计算给定子项的新索引,并将子项中的字符串设置为i->i',其中i是原始索引,i'是新索引。我正在使用它进行测试;孩子们被设置为在他们自己身上绘制这个字符串以及他们的坐标。

不幸的是,它不能正常工作,或者说它工作不规律。在我的测试用例中的九个图块中,三个似乎根本没有getChildDrawingOrder调用:我上面提到的字符串是null. 在其余部分中,尽管传递了正确的索引,但至少有一个被乱序绘制。

这是一张图片(在TOP方向):

getChildDrawingOrder 失败的图像

请注意,(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;
    }
}

任何人都可以阐明发生了什么吗?为什么不getChildDrawingOrder调用这三块瓷砖?为什么 (1,0) 以错误的顺序绘制,即使它getChildDrawingOrder 调用?

4

2 回答 2

12

好的,通过查看Android源代码弄清楚了。我有以下映射getChildDrawingOrderi传递的是“我应该画哪个孩子 ” 不是“我什么时候应该画孩子我?” s的原因NULL是因为那些孩子是在他们自己的孩子i通过之前被画出来的。

我更改了我的代码以在传递期间找出所有孩子的顺序,将其onMeasure保存在 aSparseIntArray中,然后从getChildDrawingOrder. 这行得通。

顺便说一下,反向计算getChildDrawingOrder函数中的索引是个坏主意,除非您想依赖声明子项的顺序。因为如果您不依赖该顺序,则必须遍历孩子列表以找到具有适当 x 和 y 值的孩子,这意味着您必须遍历每个孩子的孩子列表。这是一个 O(n²) 操作(阅读:相当低效)。数学也相当复杂。

于 2013-01-24T20:43:48.630 回答
3

这是一个简单的例子,展示了如何覆盖getChildDrawingOrder

  1. 作为一种调整哪个孩子按什么顺序绘制的方法(最后一个在最上面)
  2. 通过点击/单击事件更改订单

相对布局类:

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>

它看起来像什么

开始抽奖顺序(蓝色) 第一次点击(红色) 第二次点击(绿色

左图为开始绘制顺序,默认基于xml布局:

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

而且,在右侧向我们展示了在我们第二次点击后的样子,因为顺序更改为:蓝色、红色、绿色。

V/View: getChildDrawingOrder returnValue=2 i=0
V/View: getChildDrawingOrder returnValue=0 i=1
V/View: getChildDrawingOrder returnValue=1 i=2

在此之后的任何点击都会将其循环回原始顺序,由于模数计算,最后一次绘制蓝色

HTH!

于 2017-01-19T16:03:44.080 回答