package cn.mutils.app.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import cn.mutils.app.R;
import cn.mutils.app.util.AppUtil;
/**
* Round rectangle tip view width triangle
*/
@SuppressWarnings({"unused", "UnnecessaryLocalVariable", "UnusedAssignment", "ConstantConditions"})
public class TipView extends RelativeLayout {
public static final int TRIANGLE_ALIGN_TOP_LEFT = 0;
public static final int TRIANGLE_ALIGN_TOP_CENTER = 1;
public static final int TRIANGLE_ALIGN_TOP_RIGHT = 2;
public static final int TRIANGLE_ALIGN_BOTTOM_LEFT = 3;
public static final int TRIANGLE_ALIGN_BOTTOM_CENTER = 4;
public static final int TRIANGLE_ALIGN_BOTTOM_RIGHT = 5;
protected int mTopLeftRadius = 8;
protected int mTopRightRadius = 8;
protected int mBottomLeftRadius = 8;
protected int mBottomRightRadius = 8;
protected int mTriangleHeight = 12;
protected float mTriangleAngle = 77;
protected int mTriangleAlign = TRIANGLE_ALIGN_TOP_RIGHT;
protected int mTrianlgePadding = 8;
protected int mSolidColor = 0xFFFFFFFF;
protected int mStrokeColor = 0xFFD0D0D0;
protected int mStrokeWidth = 1;
protected int mPointToScreenX;
protected int mPointToScreenY;
protected Path mPath = new Path();
protected Paint mPaint = new Paint();
protected int[] mScreenLocation = new int[2];
public TipView(Context context) {
super(context);
init(context, null);
}
public TipView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public TipView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
protected void init(Context context, AttributeSet attrs) {
setWillNotDraw(false);
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TipView);
mSolidColor = typedArray.getColor(R.styleable.TipView_android_solidColor, mSolidColor);
mStrokeColor = typedArray.getColor(R.styleable.TipView_strokeColor, mStrokeColor);
mStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.TipView_strokeWidth, mStrokeWidth);
int radius = typedArray.getDimensionPixelSize(R.styleable.TipView_android_radius, -1);
if (radius != -1) {
mTopLeftRadius = mTopRightRadius = mBottomLeftRadius = mBottomRightRadius = radius;
}
mTopLeftRadius = typedArray.getDimensionPixelSize(R.styleable.TipView_android_topLeftRadius,
mTopLeftRadius);
mTopRightRadius = typedArray.getDimensionPixelSize(R.styleable.TipView_android_topRightRadius,
mTopRightRadius);
mBottomLeftRadius = typedArray.getDimensionPixelSize(R.styleable.TipView_android_bottomLeftRadius,
mBottomLeftRadius);
mBottomRightRadius = typedArray.getDimensionPixelSize(R.styleable.TipView_android_bottomRightRadius,
mBottomRightRadius);
mTrianlgePadding = typedArray.getDimensionPixelSize(R.styleable.TipView_trianglePadding, mTrianlgePadding);
mTriangleHeight = typedArray.getDimensionPixelSize(R.styleable.TipView_triangleHeight, mTriangleHeight);
mTriangleAngle = typedArray.getFloat(R.styleable.TipView_triangleAngle, mTriangleAngle);
try {
mTriangleAlign = typedArray.getInt(R.styleable.TipView_triangleAlign, mTriangleAlign);
} catch (Exception e) {
// RuntimeException
}
typedArray.recycle();
}
}
public int getTriangleAlign() {
return mTriangleAlign;
}
public void setTriangleAlign(int triangleAlign) {
switch (triangleAlign) {
case TRIANGLE_ALIGN_TOP_LEFT:
mTriangleAlign = TRIANGLE_ALIGN_TOP_LEFT;
break;
case TRIANGLE_ALIGN_TOP_CENTER:
mTriangleAlign = TRIANGLE_ALIGN_TOP_CENTER;
break;
case TRIANGLE_ALIGN_TOP_RIGHT:
mTriangleAlign = TRIANGLE_ALIGN_TOP_RIGHT;
break;
case TRIANGLE_ALIGN_BOTTOM_LEFT:
mTriangleAlign = TRIANGLE_ALIGN_BOTTOM_LEFT;
break;
case TRIANGLE_ALIGN_BOTTOM_CENTER:
mTriangleAlign = TRIANGLE_ALIGN_BOTTOM_CENTER;
break;
case TRIANGLE_ALIGN_BOTTOM_RIGHT:
mTriangleAlign = TRIANGLE_ALIGN_BOTTOM_RIGHT;
break;
default:
break;
}
postInvalidate();
}
public void pointTo(View v) {
int[] vLocation = new int[2];
v.getLocationOnScreen(vLocation);
pointTo(vLocation[0] + v.getWidth() / 2, vLocation[1] + v.getHeight() / 2);
}
public void pointTo(Rect screenRect) {
pointTo(screenRect.left + screenRect.width() / 2, screenRect.top + screenRect.height() / 2);
}
public void pointTo(int screenX, int screenY) {
mPointToScreenX = screenX;
mPointToScreenY = screenY;
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
float l = mStrokeWidth * 0.5F;// left
float t = l;// top
float r = getWidth() - l;// right
float b = getHeight() - t;// bottom
float triangleBottomRadius = (float) Math.tan(AppUtil.TO_RADIAN * mTriangleAngle / 2) * mTriangleHeight;
float triangleTopX = 0, triangleTopY = 0;
boolean canDrawTriangle = false;
boolean pointValid = mPointToScreenX != 0 || mPointToScreenY != 0;
int pointX = 0, pointY = 0;
if (pointValid) {
this.getLocationOnScreen(mScreenLocation);
}
if (mTriangleAlign == TRIANGLE_ALIGN_TOP_LEFT) {
canDrawTriangle = mTopLeftRadius + mTopRightRadius + mTrianlgePadding * 2 + triangleBottomRadius * 2 < r
- l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = t;
} else {
triangleTopX = l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius;
triangleTopY = t;
}
}
} else if (mTriangleAlign == TRIANGLE_ALIGN_TOP_CENTER) {
canDrawTriangle = mTopLeftRadius + mTopRightRadius + mTrianlgePadding * 2 + triangleBottomRadius * 2 < r
- l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = t;
} else {
triangleTopX = l + (r - l) / 2;
triangleTopY = t;
}
}
} else if (mTriangleAlign == TRIANGLE_ALIGN_TOP_RIGHT) {
canDrawTriangle = mTopLeftRadius + mTopRightRadius + mTrianlgePadding * 2 + triangleBottomRadius * 2 < r
- l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = t;
} else {
triangleTopX = r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius;
triangleTopY = t;
}
}
} else if (mTriangleAlign == TRIANGLE_ALIGN_BOTTOM_LEFT) {
canDrawTriangle = mBottomLeftRadius + mBottomRightRadius + mTrianlgePadding * 2
+ triangleBottomRadius * 2 < r - l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = b;
} else {
triangleTopX = l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius;
triangleTopY = b;
}
}
} else if (mTriangleAlign == TRIANGLE_ALIGN_BOTTOM_CENTER) {
canDrawTriangle = mBottomLeftRadius + mBottomRightRadius + mTrianlgePadding * 2
+ triangleBottomRadius * 2 < r - l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = b;
} else {
triangleTopX = l + (r - l) / 2;
triangleTopY = b;
}
}
} else if (mTriangleAlign == TRIANGLE_ALIGN_BOTTOM_RIGHT) {
canDrawTriangle = mBottomLeftRadius + mBottomRightRadius + mTrianlgePadding * 2
+ triangleBottomRadius * 2 < r - l;
canDrawTriangle = canDrawTriangle && mTriangleHeight < b - t;
if (canDrawTriangle) {
if (pointValid) {
pointX = mPointToScreenX - mScreenLocation[0];
pointY = mPointToScreenY - mScreenLocation[1];
}
pointValid = pointValid
? (pointX > (l + mTopLeftRadius + mTrianlgePadding + triangleBottomRadius)
&& pointX < (r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius))
: pointValid;
if (pointValid) {
triangleTopX = pointX;
triangleTopY = b;
} else {
triangleTopX = r - mTopRightRadius - mTrianlgePadding - triangleBottomRadius;
triangleTopY = b;
}
}
} else {
return;
}
float x = l, y = t;
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.FILL);
mPaint.setColor(mSolidColor);
mPath.reset();
if (canDrawTriangle && triangleTopY == t) {
y += mTriangleHeight;
}
x += mTopLeftRadius;
mPath.moveTo(x, y);
if (canDrawTriangle && triangleTopY == t) {
x = triangleTopX - triangleBottomRadius;
mPath.lineTo(x, y);
mPath.lineTo(triangleTopX, triangleTopY);
x = triangleTopX + triangleBottomRadius;
mPath.lineTo(x, y);
}
x = r - mTopRightRadius;
mPath.lineTo(x, y);
mPath.quadTo(r, y, r, y + mTopRightRadius);
x = r;
y = b;
if (canDrawTriangle && triangleTopY == b) {
y -= mTriangleHeight;
}
y -= mBottomRightRadius;
mPath.lineTo(x, y);
y += mBottomRightRadius;
mPath.quadTo(r, y, r - mBottomRightRadius, y);
if (canDrawTriangle && triangleTopY == b) {
x = triangleTopX + triangleBottomRadius;
mPath.lineTo(x, y);
mPath.lineTo(triangleTopX, triangleTopY);
x = triangleTopX - triangleBottomRadius;
mPath.lineTo(x, y);
}
x = l + mBottomLeftRadius;
mPath.lineTo(x, y);
mPath.quadTo(l, y, l, y - mBottomLeftRadius);
x = l;
y = t;
if (canDrawTriangle && triangleTopY == t) {
y += mTriangleHeight;
}
y += mTopLeftRadius;
mPath.lineTo(x, y);
y -= mTopLeftRadius;
mPath.quadTo(l, y, l + mTopLeftRadius, y);
mPath.close();
canvas.drawPath(mPath, mPaint);
if (mStrokeWidth != 0) {
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mStrokeColor);
canvas.drawPath(mPath, mPaint);
}
}
}