效果图 - 文字没有调偏移量,可自行调整位置偏移setHintTextOffsetXY(x, y)
调用方式
uhv_user_hint.setHeightLightView(heightLightView) //设置高光显示的view
.setHeightLightType(UserHintView.DrawHeightLightType.CUSTOM_ROUND_RECT) //设置高光类型为 自定义圆角
.setRectRoundCustom(0, 0, 0, 0) //高光类型为自定义圆角时,四个角的round 单位dp
.setHintBackgroundColor(Color.parseColor("#88000000")) //设置背景颜色
//.setHeightLightType(UserHintView.DrawHeightLightType.ROUND_RECT) //设置高光类型为 圆角矩形
//.setRectRound(5) //设置圆角矩形的角度 单位dp
//.setHeightLightType(UserHintView.DrawHeightLightType.CIRCLE) //设置高光类型为 圆形
//.setHeightLightType(UserHintView.DrawHeightLightType.RECT) //设置高光类型为 矩形
.setHeightLightExpendSize(2) // 设置高光扩张大小 自定义圆角矩形无效 单位dp
.setArrowBitmap(BitmapFactory.decodeResource(context.getResources(), res)) //设置箭头提示图片Bitmap
.setArrowSize(150, 150) // 设置图片的大小 单位dp
.setDrawHintDirection(UserHintView.DrawHintDirection.LEFT) // 设置提示图片的位置
.setArrowOffsetXY(x, y) //设置图片 X Y轴的偏移量 单位dp
.setHintText("测试测试测\n测试测试测") //设置提示文字
.setHintTextColor(Color.WHITE) //设置提示文字的颜色
.setHintTextSize(17) //设置提示文字的大小 单位dp
.setHintTextOffsetXY(10, 10) //设置提示文字的 X Y轴的偏移量 单位dp
.create();
如果是在AlertDialog中使用,取消AlertDialog半透明背景的方法
private void setStyle() {
//去除半透明阴影
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.dimAmount = 0.0f;
getWindow().setAttributes(layoutParams);
}
@Override
public void show() {
super.show();
setStyle();
}
注意:在onCreate中调用的话,需要监听view的可视化状态变更事件,在该监听中去使用
例:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
...
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
//在recyclerView 中的item
rv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//获取对应itemView
View view = rv.getLayoutManager().findViewByPosition(0);
//获取对应item中的某个view
//view.findViewById(R.id.tv);
rv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
枚举类型:
//绘制高亮类型
private DrawHeightLightType mHeightLightType = DrawHeightLightType.RECT;
public enum DrawHeightLightType{
RECT, CIRCLE, ROUND_RECT, CUSTOM_ROUND_RECT
}
/**
* 设置要绘制的方向
*/
private DrawHintDirection mDirection = DrawHintDirection.RIGHT;
public enum DrawHintDirection{
TOP, BOTTOM, LEFT, RIGHT
}
自定义View 类文件
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class UserHintView extends View {
private Context mContext;
//需要绘制高亮的view
private View mHeightLightView;
private int[] location;
private int viewWidth = 200;
private int viewHeight = 200;
//绘制高亮类型
private DrawHeightLightType mHeightLightType = DrawHeightLightType.RECT;
public enum DrawHeightLightType{
RECT, CIRCLE, ROUND_RECT, CUSTOM_ROUND_RECT
}
/**
* 矩形/圆角矩形 高光扩大范围
*/
private int mHeightLightExpandSize = 0;
/**
* 圆角
*/
private int mLeftTopRound = 0;
private int mRightTopRound = 0;
private int mLeftBottomRound = 0;
private int mRightBottomRound = 0;
/**
* 引导箭头图片
*/
private Bitmap mArrow;
/**
* 设置要绘制的方向
*/
private DrawHintDirection mDirection = DrawHintDirection.RIGHT;
public enum DrawHintDirection{
TOP, BOTTOM, LEFT, RIGHT
}
/**
* 箭头图片绘制宽高
*/
private int mArrowWidth;
private int mArrowHeight;
/**
* 箭头图片偏移量
*/
private int mArrowOffsetX = 0;
private int mArrowOffsetY = 0;
//绘制文字内容
private String mHintText;
/**
* 文字内容偏移量
*/
private int mHintTextOffsetX = 0;
private int mHintTextOffsetY = 0;
private TextPaint mPaintText = new TextPaint();
private int mTextColor = Color.parseColor("#FFFFFF");
private int mTextSize = 30;
//绘制背景颜色
private int mBackgroundColor = Color.parseColor("#50000000");
//画笔
private Paint mPaint = new Paint();
private PorterDuffXfermode mPdf = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
private PorterDuffXfermode mPdfDstOver = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);
//图片着色器
private BitmapShader shader;
private Matrix matrix = new Matrix();
public UserHintView(Context context) {
super(context);
mContext = context;
}
public UserHintView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public UserHintView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
}
public UserHintView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mContext = context;
}
/**
* 设置绘制高亮的view
* @param view
* @return
*/
public UserHintView setHeightLightView(View view){
mHeightLightView = view;
location = new int[]{0 , 0};
if (mHeightLightView != null){
mHeightLightView.getLocationOnScreen(location);
viewWidth = mHeightLightView.getMeasuredWidth();
viewHeight = mHeightLightView.getMeasuredHeight();
}
location[1] = location[1] - getStatusBarHeight();
return this;
}
/**
* 设置绘制高亮的类型
* @param type 矩形 圆形 圆角矩形 自定义圆角矩形
* @return
*/
public UserHintView setHeightLightType(DrawHeightLightType type){
mHeightLightType = type;
return this;
}
/**
* 设置矩形/圆角矩形 高光扩大范围
* @param size
* @return
*/
public UserHintView setHeightLightExpendSize(int size){
mHeightLightExpandSize = dp2px(size);
return this;
}
/**
* 设置引导箭头图片
* @param bitmap
* @return
*/
public UserHintView setArrowBitmap(Bitmap bitmap){
mArrow = bitmap;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
return this;
}
/**
* 设置引导箭头图片大小
* @param width
* @param height
* @return
*/
public UserHintView setArrowSize(int width, int height){
mArrowWidth = dp2px(width);
mArrowHeight = dp2px(height);
return this;
}
/**
* 设置引导箭头图片 X Y轴 位置偏移量
* @param x
* @param y
* @return
*/
public UserHintView setArrowOffsetXY(int x, int y){
mArrowOffsetX = dp2px(x);
mArrowOffsetY = dp2px(y);
return this;
}
/**
* 设置绘制提示箭头与文字的位置
* @param direction
* @return
*/
public UserHintView setDrawHintDirection(DrawHintDirection direction){
mDirection = direction;
return this;
}
/**
* 设置绘制的提示文字
* @param hintText
* @return
*/
public UserHintView setHintText(String hintText){
mHintText = hintText;
return this;
}
/**
* 设置绘制提示文字的偏移量
* @param x
* @param y
* @return
*/
public UserHintView setHintTextOffsetXY(int x, int y){
mHintTextOffsetX = dp2px(x);
mHintTextOffsetY = dp2px(y);
return this;
}
/**
* 绘制提示文字的字号
* @param textSize
* @return
*/
public UserHintView setHintTextSize(int textSize){
mTextSize = dp2px(textSize);
return this;
}
/**
* 绘制提示文字的颜色
* @param color
* @return
*/
public UserHintView setHintTextColor(int color){
mTextColor = color;
return this;
}
/**
* 设置圆角
* @param rectRound
* @return
*/
public UserHintView setRectRound(int rectRound){
return setRectRoundCustom(rectRound, rectRound, rectRound, rectRound);
}
/**
* 设置自定义圆角
* @param leftTop
* @param rightTop
* @param leftBottom
* @param rightBottom
* @return
*/
public UserHintView setRectRoundCustom(int leftTop, int rightTop, int leftBottom, int rightBottom){
mLeftTopRound = dp2px(leftTop);
mRightTopRound = dp2px(rightTop);
mLeftBottomRound = dp2px(leftBottom);
mRightBottomRound = dp2px(rightBottom);
return this;
}
public UserHintView setHintBackgroundColor(int color){
mBackgroundColor = color;
return this;
}
/**
* 开始绘制
*/
public void create(){
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawColor(mBackgroundColor);
mPaint.setXfermode(mPdf);
initHeightLightDraw(canvas);
initArrowBitmapDraw(canvas);
initHintTextDraw(canvas);
}
/**
* 绘制高光提示
* @param canvas
*/
private void initHeightLightDraw(Canvas canvas){
mPaint.setStyle(Paint.Style.FILL);
//抗锯齿
mPaint.setAntiAlias(true);
RectF rectF = new RectF();
rectF.left = location[0] - mHeightLightExpandSize;
rectF.top = location[1] - mHeightLightExpandSize;
rectF.right = location[0] + viewWidth + mHeightLightExpandSize;
rectF.bottom = location[1] + viewHeight + mHeightLightExpandSize;
switch (mHeightLightType){
case RECT:
canvas.drawRect(rectF, mPaint);
break;
case CIRCLE:
canvas.drawCircle(location[0] + viewWidth / 2f, location[1] + viewHeight / 2f,
viewWidth > viewHeight ? viewWidth / 2f + mHeightLightExpandSize : viewHeight / 2f + mHeightLightExpandSize, mPaint);
break;
case ROUND_RECT: {
canvas.drawRoundRect(rectF, mLeftTopRound, mRightBottomRound, mPaint);
break;
}
case CUSTOM_ROUND_RECT:
initCustomRoundRect(canvas, location[0], location[1], viewWidth, viewHeight);
break;
}
}
/**
* 绘制中部十字形,再绘制四个角
* @param canvas
* @param x
* @param y
* @param viewWidth
* @param viewHeight
*/
private void initCustomRoundRect(Canvas canvas, int x, int y, int viewWidth, int viewHeight){
if (mLeftTopRound != 0){
canvas.drawCircle(x + mLeftTopRound, y + mLeftTopRound, mLeftTopRound, mPaint);
}else {
canvas.drawRect(x, y, x + mRightTopRound, y + mRightTopRound, mPaint);
}
if (mRightTopRound != 0){
canvas.drawCircle(x + viewWidth - mRightTopRound, y + mRightTopRound, mRightTopRound, mPaint);
}else {
canvas.drawRect(x + viewWidth - mLeftTopRound, y, x + viewWidth, y + mLeftTopRound, mPaint);
}
if (mLeftBottomRound != 0){
canvas.drawCircle(x + mLeftBottomRound, y + viewHeight - mLeftBottomRound, mLeftBottomRound, mPaint);
}else {
canvas.drawRect(x, y + viewHeight - mRightBottomRound , x + mRightBottomRound, y + viewHeight, mPaint);
}
if (mRightBottomRound != 0){
canvas.drawCircle(x + viewWidth - mRightBottomRound, y + viewHeight - mRightBottomRound, mRightBottomRound, mPaint);
}else {
canvas.drawRect(x + viewWidth - mLeftBottomRound, y + viewHeight - mLeftBottomRound, x + viewWidth, y + viewHeight, mPaint);
}
int horLeftRound = Math.max(mLeftTopRound, mLeftBottomRound);
int horRightRound = Math.max(mRightTopRound, mRightBottomRound);
//中部矩形 - 纵向
canvas.drawRect(x + horLeftRound, y, x +viewWidth - horRightRound, y + viewHeight, mPaint);
//中部矩形 - 横向
int verLeftRound = Math.max(mLeftTopRound, mRightTopRound);
int verRightRound = Math.max(mLeftBottomRound, mRightBottomRound);
canvas.drawRect(x, y + verLeftRound, x + viewWidth, y + viewHeight - verRightRound, mPaint);
}
/**
* 绘制箭头图片
* @param canvas
*/
private void initArrowBitmapDraw(Canvas canvas){
//抗锯齿
mPaintBitmap.setAntiAlias(true);
if (mArrow != null){
if (mArrowWidth == 0 && mArrowHeight == 0){
mArrowWidth = dp2px(150);
mArrowHeight = dp2px(150);
}
// 计算缩放比例
float scaleWidth = ((float) mArrowWidth) / mArrow.getWidth();
float scaleHeight = ((float) mArrowHeight) / mArrow.getHeight();
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
mArrow = Bitmap.createBitmap(mArrow, 0, 0, mArrow.getWidth(), mArrow.getHeight(), matrix, true);
int left = 0, top = 0;
//Rect rect = new Rect();
switch (mDirection){
case LEFT: {
left = location[0] - mArrowWidth;
top = location[1];
/*rect.left = location[0] - mArrowWidth;
rect.top = location[1];
rect.right = location[0];
rect.bottom = location[1] + mArrowHeight;*/
break;
}
case RIGHT: {
left = location[0] + viewWidth;
top = location[1];
break;
}
case TOP: {
left = location[0];
top = location[1] - mArrowHeight;
break;
}
case BOTTOM: {
left = location[0];
top = location[1] + viewHeight;
break;
}
}
canvas.drawBitmap(mArrow, left + mArrowOffsetX, top + mArrowOffsetY, mPaintBitmap);
}
}
/**
* 绘制提示文字
* @param canvas
*/
private void initHintTextDraw(Canvas canvas){
int x = 0, y = 0;
switch (mDirection) {
case LEFT:{
x = location[0] - mArrowWidth + mArrowOffsetX + mHintTextOffsetX;
y = location[1] + mArrowHeight + mArrowOffsetY + mHintTextOffsetY;
break;
}
case RIGHT: {
x = location[0] + viewWidth + mArrowWidth + mArrowOffsetX + mHintTextOffsetX;
y = location[1] + mArrowHeight + mArrowOffsetY + mHintTextOffsetY;
break;
}
case TOP: {
x = location[0] + mArrowWidth + mArrowOffsetX + mHintTextOffsetX;
y = location[1] - mArrowHeight + mArrowOffsetY + mHintTextOffsetY;
break;
}
case BOTTOM: {
x = location[0] + mArrowWidth + mArrowOffsetX + mHintTextOffsetX;
y = location[1] + viewHeight + mArrowHeight + mArrowOffsetY + mHintTextOffsetY;
break;
}
}
mPaintText.setAntiAlias(true);
mPaintText.setColor(mTextColor);
mPaintText.setStyle(Paint.Style.FILL);
mPaintText.setTextSize(mTextSize);
canvas.translate(x, y);
StaticLayout myStaticLayout = new StaticLayout(mHintText, mPaintText, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
myStaticLayout.draw(canvas);
//canvas.drawText(mHintText, , y, mPaintText);
canvas.translate(-x, -y);
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
mContext.getResources().getDisplayMetrics());
}
private int getWindowWidth(){
return mContext.getResources().getDisplayMetrics().widthPixels;
}
private int getWindowHeight(){
return mContext.getResources().getDisplayMetrics().heightPixels;
}
public int getStatusBarHeight() {
Resources resources = mContext.getResources();
int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
int height = resources.getDimensionPixelSize(resourceId);
return height;
}
}