package com.buddycloud.customviews;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.buddycloud.R;
import com.buddycloud.utils.TypefacesUtil;
/**
* Create custom error tooltip view. It offers different
* set of attributes that can help to customize the tooltip
* view.
*
* <code>
* <com.buddycloud.customviews.TooltipErrorView
* android:id="@+id/passwordErrorTooltip"
* android:layout_width="fill_parent"
* android:layout_height="wrap_content"
* tooltipErrorView:bgColor="#f6f6f6"
* tooltipErrorView:borderColor="#d5d5d5"
* tooltipErrorView:fontTypeface="Roboto-Light.ttf"
* tooltipErrorView:textColor="#768595" />
* </code>
*
* @author Adnan Urooj (Deminem)
*
*/
public class TooltipErrorView extends LinearLayout implements
ViewTreeObserver.OnPreDrawListener {
private static final String FONTS_PATH = "fonts/";
private static final int POINTER_HEIGHT = 6;
private static final int POINTER_WIDE_HEIGHT = 12;
private static final int POINTER_START = 35;
private ViewGroup mContentHolder;
private TextView mToolTipTV;
private CharSequence mText;
private int mColor;
private int mBorderColor;
private int mTextColor;
private int mTextSize;
private Typeface mTypeface;
private int mPointHeightPx;
public TooltipErrorView(final Context context) {
super(context);
init(context, null, 0);
}
public TooltipErrorView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
private void init(final Context context, final AttributeSet attrs,
final int defStyle) {
setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
setOrientation(VERTICAL);
LayoutInflater.from(getContext()).inflate(R.layout.tooltip, this, true);
mContentHolder = (ViewGroup) findViewById(R.id.tooltip_contentholder);
mToolTipTV = (TextView) findViewById(R.id.tooltip_contenttv);
Resources r = getContext().getResources();
mPointHeightPx = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, POINTER_HEIGHT,
r.getDisplayMetrics());
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.TooltipErrorView, 0, 0);
try {
mText = a.getString(R.styleable.TooltipErrorView_text);
mTypeface = getTypeface(context,
a.getString(R.styleable.TooltipErrorView_fontTypeface));
mTextSize = a.getInt(R.styleable.TooltipErrorView_textSize, 18);
mTextColor = a.getColor(R.styleable.TooltipErrorView_textColor,
Color.parseColor("#72828C"));
mColor = a.getColor(R.styleable.TooltipErrorView_bgColor,
Color.parseColor("#f6f6f6"));
mBorderColor = a.getColor(R.styleable.TooltipErrorView_borderColor,
Color.parseColor("#d4d4d4"));
} finally {
a.recycle();
}
// setup the config for tooltip
setupToolTip();
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
@Override
public boolean onPreDraw() {
mContentHolder.measure(getMeasuredWidth(), getTextHeight() + mPointHeightPx);
Shape shape = getTooltipShape();
ShapeDrawable d = new ShapeDrawable(shape);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mContentHolder.setBackground(d);
} else {
mContentHolder.setBackgroundDrawable(d);
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = getMeasuredWidth();
int h = getMeasuredHeight();
w -= getPaddingLeft() - getPaddingRight();
h = getTextHeight() + getPaddingTop() + getPaddingBottom()
+ mPointHeightPx;
setMeasuredDimension(w, h);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
mContentHolder.setVisibility(visibility);
mToolTipTV.setVisibility(visibility);
invalidate();
}
/**
* Setup the error tooltip
*
* @param text
*/
private void setupToolTip() {
if (!TextUtils.isEmpty(mText)) {
mToolTipTV.setText(mText);
}
mToolTipTV.setTypeface(mTypeface);
mToolTipTV.setTextColor(mTextColor);
mToolTipTV.setTextSize(mTextSize);
getViewTreeObserver().addOnPreDrawListener(this);
}
/**
* Get the typeface for given font
*
* @param context
* @param fontName
* @return
*/
private Typeface getTypeface(Context context, String fontName) {
if (!TextUtils.isEmpty(fontName)) {
return TypefacesUtil.get(context, FONTS_PATH + fontName);
}
return Typeface.SANS_SERIF;
}
private int getTextHeight() {
mToolTipTV.setText(mText);
mToolTipTV.measure(MeasureSpec.makeMeasureSpec(
mContentHolder.getWidth(), MeasureSpec.EXACTLY), MeasureSpec
.makeMeasureSpec(LayoutParams.WRAP_CONTENT,
MeasureSpec.UNSPECIFIED));
return mToolTipTV.getMeasuredHeight();
}
/**
* Set the tooltip text
*
* @param msg
*/
public void setText(CharSequence msg) {
if (!TextUtils.isEmpty(msg) && mText != msg) {
mText = msg;
mToolTipTV.setText(mText);
requestLayout();
invalidate();
}
}
/**
* Set the tooltip text color
*
* @param color
*/
public void setTextColor(int color) {
if (mTextColor != color) {
mTextColor = color;
mToolTipTV.setTextColor(color);
invalidate();
}
}
/**
* Set the tooltip border color
*
* @param color
*/
public void setBorderColor(int color) {
if (mBorderColor != color) {
mBorderColor = color;
invalidate();
}
}
/**
* Set the tooltip background color
*
* @param color
*/
public void setBackgroundColor(int color) {
if (mColor != color) {
mColor = color;
invalidate();
}
}
/**
* Set the tooltip typeface
*
* @param color
*/
public void setTypeface(Typeface typeface) {
if (mTypeface != typeface) {
mTypeface = typeface;
invalidate();
}
}
/**
* Get the error tooltip text
*
* @return
*/
public CharSequence getText() {
return mText;
}
/**
* Get the tooltip background color
*
* @return
*/
public int getColor() {
return mColor;
}
/**
* Get the text color
*
* @return
*/
public int getTextColor() {
return mTextColor;
}
/**
* Get the typeface
*
* @return
*/
public Typeface getTypeface() {
return mTypeface;
}
/**
* Get the tooltip shape
*
* @return
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private Shape getTooltipShape() {
Resources r = this.getContext().getResources();
final int pointHeightPx = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, POINTER_HEIGHT,
r.getDisplayMetrics());
final int pointedHeightPx = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, POINTER_WIDE_HEIGHT,
r.getDisplayMetrics());
final int pointStartPx = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, POINTER_START,
r.getDisplayMetrics());
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mContentHolder
.getLayoutParams();
mToolTipTV.setY(pointHeightPx);
params.height = mToolTipTV.getHeight() + pointHeightPx;
final Path rectPath = new Path();
final Path rectBorderPath = new Path();
// Create the rectangular shape
Shape shape = new RectShape() {
@Override
protected void onResize(float w, float h) {
createShapePath(rectPath, rectBorderPath, w, h, pointHeightPx,
pointedHeightPx, pointStartPx);
}
@Override
public void draw(Canvas canvas, Paint paint) {
drawOnCanvas(canvas, paint, rectPath, rectBorderPath);
}
};
return shape;
}
/**
* Create the shape path
*
* @param rectPath
* @param rectBorderPath
* @param width
* @param height
* @param pointHeightPx
* @param pointedHeightPx
* @param pointStartPx
*/
private void createShapePath(Path rectPath, Path rectBorderPath,
float width, float height, int pointHeightPx, int pointedHeightPx,
int pointStartPx) {
int w = (int) width;
int h = (int) height;
Point a = new Point(0, h);
Point b = new Point(w, h);
Point c = new Point(w, pointHeightPx);
Point d = new Point((w - (w - pointStartPx)) + (pointedHeightPx / 2),
pointHeightPx);
Point e = new Point((w - (w - pointStartPx)), 0); // this is the sharp
// point of the
// triangle
Point f = new Point((w - (w - pointStartPx)) - (pointedHeightPx / 2),
pointHeightPx);
Point g = new Point(0, pointHeightPx);
rectPath.reset();
rectPath.moveTo(a.x, a.y);
rectPath.lineTo(b.x, b.y);
rectPath.lineTo(c.x, c.y);
rectPath.lineTo(d.x, d.y);
rectPath.lineTo(e.x, e.y);
rectPath.lineTo(f.x, f.y);
rectPath.lineTo(g.x, g.y);
rectPath.close();
rectBorderPath.reset();
rectBorderPath.moveTo(a.x, a.y);
rectBorderPath.lineTo(b.x, b.y);
rectBorderPath.lineTo(c.x, c.y);
rectBorderPath.lineTo(d.x, d.y);
rectBorderPath.lineTo(e.x, e.y);
rectBorderPath.lineTo(f.x, f.y);
rectBorderPath.lineTo(g.x, g.y);
rectBorderPath.close();
}
/**
* Draw the shape on canvas
*
* @param c
* @param p
* @param rectPath
* @param rectBorderPath
*/
private void drawOnCanvas(Canvas c, Paint p, Path rectPath,
Path rectBorderPath) {
// set background color
if (rectPath != null) {
p.setColor(mColor);
c.drawPath(rectPath, p);
}
// set border
if (rectBorderPath != null) {
p.setColor(mBorderColor);
p.setStyle(Style.STROKE);
p.setStrokeWidth(3);
c.drawPath(rectBorderPath, p);
}
}
}