getChildDrawingOrder调用/使用不正常?

时间:2013-01-24 15:16:19

标签: java android drawing

我正在创建一个包含简单图块的等轴测图,我已经扩展RelativeLayout来创建一个包含这些图块的布局。实际上,只要我的方向与将图块写入XML文件的顺序相匹配,只需使用RelativeLayout as-is就可以正常工作;所有我覆盖的都是构造函数,我只需调用supersetChildrenDrawingOrderEnabled(true);以及设置一些变量(网格的高度和宽度),然后调用getChildDrawingOrder本身。

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

不幸的是,它无法正常工作,或者说工作不正常。在我测试用例中的九个tile中,有三个看起来根本没有调用i':我上面提到的字符串是getChildDrawingOrder。其余的,尽管传递了正确的索引,但至少有一个被抽出。

这是一张图片(null方向):

Image of getChildDrawingOrder failure

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

2 个答案:

答案 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; }

  1. 作为一种方式来调整哪个孩子以哪种顺序被抽出(最后一个在最上面)
  2. 从点击/点击事件中更改订单
  3. 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);
        }
    
    }
    

    看起来像什么

    Starting Draw order (blue) First tap (red) Second tap (green

    左图是起始绘图顺序,这是基于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!