package no.agens.depth.lib; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.ViewTreeObserver; import android.widget.RelativeLayout; import com.mdroid.repo.depth_lib_android_.R; public class DepthRendrer extends RelativeLayout { android.graphics.Matrix matrix = new android.graphics.Matrix(); private Paint shadowPaint = new Paint(); private NinePatchDrawable softShadow; private Drawable roundSoftShadow; private Path edgePath = new Path(); private float shadowAlpha = 0.3f; public DepthRendrer(Context context) { super(context); setup(); } public DepthRendrer(Context context, AttributeSet attrs) { super(context, attrs); setup(); } public DepthRendrer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setup(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public DepthRendrer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); setup(); } public float getTopEdgeLength(DepthLayout dl) { return getDistance(dl.getTopLeftBack(), dl.getTopRightBack()); } float getDistance(PointF p1, PointF p2) { return (float) Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } public float getShadowAlpha() { return shadowAlpha; } public void setShadowAlpha(float shadowAlpha) { this.shadowAlpha = Math.min(1f, Math.max(0, shadowAlpha)); } void setup() { getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof DepthLayout) { boolean hasChangedBounds = ((DepthLayout) child).calculateBounds(); if (hasChangedBounds) invalidate(); } } return true; } }); shadowPaint.setColor(Color.BLACK); shadowPaint.setAntiAlias(true); softShadow = (NinePatchDrawable) getResources().getDrawable(R.drawable.shadow, null); roundSoftShadow = getResources().getDrawable(R.drawable.round_soft_shadow, null); } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child instanceof DepthLayout && !isInEditMode()) { DepthLayout dl = (DepthLayout) child; float[] src = new float[] { 0, 0, dl.getWidth(), 0, dl.getWidth(), dl.getHeight(), 0, dl.getHeight() }; if (dl.isCircle()) { dl.getCustomShadow().drawShadow(canvas, dl, roundSoftShadow); if (Math.abs(dl.getRotationX()) > 1 || Math.abs(dl.getRotationY()) > 1) { drawCornerBaseShape(dl, canvas, src); } } else { dl.getCustomShadow().drawShadow(canvas, dl, softShadow); if (dl.getRotationX() != 0 || dl.getRotationY() != 0) { if (getLongestHorizontalEdge(dl) > getLongestVerticalEdge(dl)) { drawVerticalFirst(dl, canvas, src); } else { drawHorizontalFist(dl, canvas, src); } } } } return super.drawChild(canvas, child, drawingTime); } private void drawCornerBaseShape(DepthLayout dl, Canvas canvas, float[] src) { float[] dst = new float[] { dl.getTopLeftBack().x, dl.getTopLeftBack().y, dl.getTopRightBack().x, dl.getTopRightBack().y, dl.getBottomRightBack().x, dl.getBottomRightBack().y, dl.getBottomLeftBack().x, dl.getBottomLeftBack().y }; int count = canvas.save(); matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); canvas.concat(matrix); edgePath.reset(); edgePath.addRoundRect(0, 0, dl.getWidth(), dl.getHeight(), dl.getWidth() / 2f, dl.getHeight() / 2f, Path.Direction.CCW); canvas.drawPath(edgePath, dl.getEdgePaint()); shadowPaint.setAlpha((int) (shadowAlpha * 0.5f * 255)); canvas.drawPath(edgePath, shadowPaint); canvas.restoreToCount(count); } private void drawHorizontalFist(DepthLayout dl, Canvas canvas, float[] src) { if (getLeftEdgeLength(dl) <= getRightEdgeLength(dl)) { drawLeftEdge(dl, canvas, src); } else { drawRightEdge(dl, canvas, src); } drawTopEdge(dl, canvas, src); drawBottomEdge(dl, canvas, src); if (getLeftEdgeLength(dl) >= getRightEdgeLength(dl)) { drawLeftEdge(dl, canvas, src); } else { drawRightEdge(dl, canvas, src); } } private void drawVerticalFirst(DepthLayout dl, Canvas canvas, float[] src) { if (getTopEdgeLength(dl) <= getBottomEdgeLength(dl)) { drawTopEdge(dl, canvas, src); } else { drawBottomEdge(dl, canvas, src); } drawLeftEdge(dl, canvas, src); drawRightEdge(dl, canvas, src); if (getTopEdgeLength(dl) >= getBottomEdgeLength(dl)) { drawTopEdge(dl, canvas, src); } else { drawBottomEdge(dl, canvas, src); } } float getLongestHorizontalEdge(DepthLayout dl) { float topEdgeLength = getTopEdgeLength(dl); float bottomEdgeLength = getBottomEdgeLength(dl); if (topEdgeLength > bottomEdgeLength) { return topEdgeLength; } else { return bottomEdgeLength; } } float getLongestVerticalEdge(DepthLayout dl) { float leftEdgeLength = getLeftEdgeLength(dl); float rightEdgeLength = getRightEdgeLength(dl); if (leftEdgeLength > rightEdgeLength) { return leftEdgeLength; } else { return rightEdgeLength; } } private float getRightEdgeLength(DepthLayout dl) { return getDistance(dl.getTopRightBack(), dl.getBottomRightBack()); } private float getLeftEdgeLength(DepthLayout dl) { return getDistance(dl.getTopLeftBack(), dl.getBottomLeftBack()); } private float getBottomEdgeLength(DepthLayout dl) { return getDistance(dl.getBottomLeftBack(), dl.getBottomRightBack()); } void drawShadow(PointF point1, PointF point2, float correctionValue, Canvas canvas, DepthLayout dl) { float angle = Math.abs(Math.abs(getAngle(point1, point2)) + correctionValue); float alpha = angle / 180f; shadowPaint.setAlpha((int) (alpha * 255f * shadowAlpha)); canvas.drawRect(0, 0, dl.getWidth(), dl.getHeight(), shadowPaint); } private void drawRectancle(DepthLayout dl, Canvas canvas) { canvas.drawRect(0, 0, dl.getWidth(), dl.getHeight(), dl.getEdgePaint()); } public float getAngle(PointF point1, PointF point2) { float angle = (float) Math.toDegrees(Math.atan2(point1.y - point2.y, point1.x - point2.x)); return angle; } private void drawLeftEdge(DepthLayout dl, Canvas canvas, float[] src) { float[] dst = new float[] { dl.getTopLeft().x, dl.getTopLeft().y, dl.getTopLeftBack().x, dl.getTopLeftBack().y, dl.getBottomLeftBack().x, dl.getBottomLeftBack().y, dl.getBottomLeft().x, dl.getBottomLeft().y }; int count = canvas.save(); matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); canvas.concat(matrix); drawRectancle(dl, canvas); drawShadow(dl.getTopLeft(), dl.getBottomLeft(), 0, canvas, dl); canvas.restoreToCount(count); } private void drawRightEdge(DepthLayout dl, Canvas canvas, float[] src) { float[] dst = new float[] { dl.getTopRight().x, dl.getTopRight().y, dl.getTopRightBack().x, dl.getTopRightBack().y, dl.getBottomRightBack().x, dl.getBottomRightBack().y, dl.getBottomRight().x, dl.getBottomRight().y }; int count = canvas.save(); matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); canvas.concat(matrix); drawRectancle(dl, canvas); drawShadow(dl.getTopRight(), dl.getBottomRight(), -180f, canvas, dl); canvas.restoreToCount(count); } private void drawTopEdge(DepthLayout dl, Canvas canvas, float[] src) { float[] dst = new float[] { dl.getTopLeft().x, dl.getTopLeft().y, dl.getTopRight().x, dl.getTopRight().y, dl.getTopRightBack().x, dl.getTopRightBack().y, dl.getTopLeftBack().x, dl.getTopLeftBack().y }; int count = canvas.save(); matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); canvas.concat(matrix); drawRectancle(dl, canvas); drawShadow(dl.getTopLeft(), dl.getTopRight(), -180f, canvas, dl); canvas.restoreToCount(count); } private void drawBottomEdge(DepthLayout dl, Canvas canvas, float[] src) { float[] dst = new float[] { dl.getBottomLeft().x, dl.getBottomLeft().y, dl.getBottomRight().x, dl.getBottomRight().y, dl.getBottomRightBack().x, dl.getBottomRightBack().y, dl.getBottomLeftBack().x, dl.getBottomLeftBack().y }; int count = canvas.save(); matrix.setPolyToPoly(src, 0, dst, 0, dst.length >> 1); canvas.concat(matrix); drawRectancle(dl, canvas); drawShadow(dl.getBottomLeft(), dl.getBottomRight(), 0, canvas, dl); canvas.restoreToCount(count); } }