@Override
  protected void onDraw(Canvas canvas) {
    if (!enabled) {
      return;
    }
    getLocationInWindow(location);
    float x = location[0];
    float y = location[1];

    int saveCount = canvas.save();

    float cx = getWidth() / 2f;
    float cy = getHeight() / 2f;

    camera.save();
    camera.rotate(rotationX, rotationY, 0);
    camera.getMatrix(matrix);
    camera.restore();

    matrix.preTranslate(-cx, -cy);
    matrix.postTranslate(cx, cy);
    canvas.concat(matrix);
    canvas.scale(zoom, zoom, cx, cy);

    if (!layeredViewQueue.isEmpty()) {
      throw new AssertionError("View queue is not empty.");
    }

    // We don't want to be rendered so seed the queue with our children.
    for (int i = 0, count = getChildCount(); i < count; i++) {
      LayeredView layeredView = layeredViewPool.obtain();
      layeredView.set(getChildAt(i), 0);
      layeredViewQueue.add(layeredView);
    }

    while (!layeredViewQueue.isEmpty()) {
      LayeredView layeredView = layeredViewQueue.removeFirst();
      View view = layeredView.view;
      int layer = layeredView.layer;

      // Restore the object to the pool for use later.
      layeredView.clear();
      layeredViewPool.restore(layeredView);

      // Hide any visible children.
      if (view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) view;
        visibilities.clear();
        for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
          View child = viewGroup.getChildAt(i);
          //noinspection ConstantConditions
          if (child.getVisibility() == VISIBLE) {
            visibilities.set(i);
            child.setVisibility(INVISIBLE);
          }
        }
      }

      int viewSaveCount = canvas.save();

      // Scale the layer index translation by the rotation amount.
      float translateShowX = rotationY / ROTATION_MAX;
      float translateShowY = rotationX / ROTATION_MAX;
      float tx = layer * spacing * density * translateShowX;
      float ty = layer * spacing * density * translateShowY;
      canvas.translate(tx, -ty);

      view.getLocationInWindow(location);
      canvas.translate(location[0] - x, location[1] - y);

      viewBoundsRect.set(0, 0, view.getWidth(), view.getHeight());
      canvas.drawRect(viewBoundsRect, viewBorderPaint);

      if (drawViews) {
        try {
          view.draw(canvas);
        } catch (IllegalStateException e) {
          e.printStackTrace();
        }
      }

      if (drawIds) {
        int id = view.getId();
        if (id != NO_ID) {
          canvas.drawText(nameForId(id), textOffset, textSize, viewBorderPaint);
        }
      }

      canvas.restoreToCount(viewSaveCount);

      // Restore any hidden children and queue them for later drawing.
      if (view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) view;
        for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
          if (visibilities.get(i)) {
            View child = viewGroup.getChildAt(i);
            //noinspection ConstantConditions
            child.setVisibility(VISIBLE);
            LayeredView childLayeredView = layeredViewPool.obtain();
            childLayeredView.set(child, layer + 1);
            layeredViewQueue.add(childLayeredView);
          }
        }
      }
    }

    canvas.restoreToCount(saveCount);
  }
Returns true when view layers draw their IDs.
saklib/src/main/java/com/wanjian/sak/layer/impl/ScalpelFrameLayout.java