getChildDrawingOrder called/used erratically?

前端 未结 2 888
梦谈多话
梦谈多话 2021-01-18 09:07

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 R

相关标签:
2条回答
  • 2021-01-18 09:13

    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 NULLs 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.

    0 讨论(0)
  • 2021-01-18 09:24

    Here is a simple example that shows how to override getChildDrawingOrder

    1. as a way to adjust which of the children gets drawn in which order (with the last on being on top)
    2. have the order change from a tap/click event

    The RelativeLayout class:

    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);
        }
    
    }
    

    The xml layout

    <?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>
    

    What it looks like

    Pictured on the left is the starting drawing order, which is the default based on the xml layout:

    Red = index 0
    Green = index 1
    Blue = index 2  
    

    So from first to last (or think bottom to top) that is: Red, Green, Blue. Here is the log dump of getChildDrawingOrder being called

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

    In the middle, after our first tap, the order changes to Green, Blue, Red

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

    And, on the right side shows us what it looks like after our second tap since the order change to: Blue, Red, Green.

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

    Any tap after this pretty much loops it back to the original order where blue was last to be drawn due to the modulus calculation

    HTHs!

    0 讨论(0)
提交回复
热议问题