Android 自定义带箭头对话框背景

简介

自定义drawable,带箭头对话框背景,三角形+矩形组合。应用于对话框背景、提示语背景等。

可设置箭头显示方向、箭头大小、箭头导圆角尺寸、矩形尺寸、矩形导圆角尺寸、背景颜色、drawable padding值(影响宿主控件padding)。

希望能给大家带来方便。

一、效果图

Android 自定义带箭头对话框背景_第1张图片

 示例代码:

        ArrowsDrawable drawable = new ArrowsDrawable(ArrowsDrawable.BOTTOM, ConvertUtils.dp2px(8));
        drawable.setArrowsRadius(ConvertUtils.dp2px(3));
        drawable.setArrowsHeight(ConvertUtils.dp2px(8));
        drawable.setArrowsWidth(ConvertUtils.dp2px(12));
        drawable.setPadding(ConvertUtils.dp2px(10));
        drawable.setColor(Color.DKGRAY);
        textView.setBackground(drawable);

二、API详解

构造方法

//箭头方向,箭头高度 
public ArrowsDrawable(@Position int arrowsPosition, float arrowsHeight)

设置drawable padding

drawable设置padding之后,会影响使用该drawable控件的padding。例如示例中drawable设置了padding,即使用者TextView设置了相同的padding值,这是drawable的特性。另外,该api将箭头高度加到对应的padding值中了,比如箭头方向朝上,drawable设置4个padding均为10dp, 那么drawable paddingTop的值 = 10dp + 箭头高度值,其余均是10dp。

 public void setPadding(int p) 
 public void setPadding(int left, int top, int right, int bottom) 
设置箭头方向
LEFT, RIGHT, TOP, BOTTOM
   public void setArrowsPosition(@Position int arrowsPosition)
设置箭头圆角

设置箭头突出角的圆角尺寸,给该角导圆角

 public void setArrowsRadius(float arrowsRadius)

其它API

//设置箭头高度
        drawable.setArrowsHeight(ConvertUtils.dp2px(8));
        //设置箭头宽度,默认是箭头高度的2倍
        drawable.setArrowsWidth(ConvertUtils.dp2px(12));
        //设置背景色
        drawable.setColor(Color.DKGRAY);

扩展

如果 drawable需要设置margin效果, 可以通过InsetDrawable实现。

        InsetDrawable insetDrawable = new InsetDrawable(arrowsDrawable, padding);
        tv.setBackground(insetDrawable);

三、源码

package com.ttkx.deviceinfo.bkchart;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.view.Gravity;

import com.blankj.utilcode.util.ConvertUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import androidx.annotation.IntDef;


/**
 * 带箭头的Drawable
 * 

* Created by liuyu * on 2021/2/4 */ public class ArrowsDrawable extends GradientDrawable { //箭头显示位置 public static final int LEFT = Gravity.LEFT; public static final int TOP = Gravity.TOP; public static final int RIGHT = Gravity.RIGHT; public static final int BOTTOM = Gravity.BOTTOM; public static final int CENTER = Gravity.CENTER; @IntDef({LEFT, RIGHT, TOP, BOTTOM}) @Retention(RetentionPolicy.SOURCE) public @interface Position { } private Paint mPaint; private int arrowsPosition = BOTTOM; private float arrowsRadius = ConvertUtils.dp2px(2); private float arrowsHeight = ConvertUtils.dp2px(5); private float arrowsWidth; private float mRadius = ConvertUtils.dp2px(8); private float arrowsPadding = mRadius + ConvertUtils.dp2px(10);//箭头padding private Path mPath; public ArrowsDrawable(@Position int arrowsPosition, float arrowsHeight) { this.arrowsPosition = arrowsPosition; this.arrowsHeight = arrowsHeight; initPaint(); } private Rect mPadding; @Override public boolean getPadding(Rect padding) { if (mPadding != null) { padding.set(mPadding); return true; } else { return super.getPadding(padding); } } public void setPadding(int p) { setPadding(p, p, p, p); } /** * 设置drawable padding * * @param left * @param top * @param right * @param bottom */ public void setPadding(int left, int top, int right, int bottom) { if (mPadding == null) { mPadding = new Rect(); } switch (arrowsPosition) { case LEFT: left += arrowsHeight; break; case TOP: top += arrowsHeight; break; case RIGHT: right += arrowsHeight; break; default: bottom += arrowsHeight; break; } mPadding.set(left, top, right, bottom); invalidateSelf(); //super.setPadding(left, top, right, bottom);api=29,10.0 } /** * 设置箭头方向 * * LEFT, RIGHT, TOP, BOTTOM * @param arrowsPosition */ public void setArrowsPosition(@Position int arrowsPosition) { this.arrowsPosition = arrowsPosition; invalidateSelf(); } /** * 设置箭头圆角 * * @param arrowsRadius */ public void setArrowsRadius(float arrowsRadius) { this.arrowsRadius = arrowsRadius; invalidateSelf(); } /** * 设置箭头高度 * * @param arrowsHeight */ public void setArrowsHeight(float arrowsHeight) { this.arrowsHeight = arrowsHeight; invalidateSelf(); } /** * 设置箭头宽度 * * @param arrowsWidth */ public void setArrowsWidth(float arrowsWidth) { this.arrowsWidth = arrowsWidth; } /** * 设置箭头离矩形边的距离(参照:矩形的左边或上边) * * @param arrowsPadding */ public void setArrowsPadding(float arrowsPadding) { this.arrowsPadding = arrowsPadding; invalidateSelf(); } private void initPaint() { mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(1); mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); mPath = new Path(); } @Override protected void onBoundsChange(Rect r) { super.onBoundsChange(r); int width = r.width(); int height = r.height(); float aw = this.arrowsWidth; if (aw <= 0) { aw = arrowsHeight * 2;//默认情况下箭头宽度是高度的2倍 } float ar = aw / 2; //三个点的坐标和矩形 float px1 = r.left + arrowsPadding; float py1 = r.top + height - this.arrowsHeight; float px2 = px1 + aw; float py2 = py1; float px3 = px1 + ar; float py3 = py1 + this.arrowsHeight; //矩形起始点坐标 float sx = r.left; float sy = r.top; //矩形宽高度 float rectWidth = width; float rectHeight = height - this.arrowsHeight; switch (arrowsPosition) { case LEFT: px1 = r.left + this.arrowsHeight; py1 = r.top + arrowsPadding + this.arrowsHeight; px2 = px1; py2 = py1 + aw; px3 = px1 - this.arrowsHeight; py3 = py1 + ar; sx = px1; sy = r.top; rectWidth = width - this.arrowsHeight; rectHeight = height; break; case TOP: px1 = r.left + arrowsPadding; py1 = r.top + this.arrowsHeight; px2 = px1 + aw; py2 = py1; px3 = px1 + ar; py3 = py1 - this.arrowsHeight; sx = r.left; sy = r.top + this.arrowsHeight; rectWidth = width; rectHeight = height - this.arrowsHeight; break; case RIGHT: px1 = r.left + width - this.arrowsHeight; py1 = r.top + arrowsPadding; px2 = px1; py2 = py1 + aw; px3 = px1 + this.arrowsHeight; py3 = py1 + ar; sx = r.left; sy = r.top; rectWidth = width - this.arrowsHeight; rectHeight = height; break; } mPath.reset(); addTrianglePath(mPath, arrowsRadius, px1, py1, px2, py2, px3, py3); RectF rectF = new RectF(sx, sy, sx + rectWidth, sy + rectHeight); mPath.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW); } @Override public void draw(Canvas canvas) { super.draw(canvas); canvas.drawPath(mPath, mPaint); } /** * 添加三角形path * * @param path 路径 * @param radiu 三角形突出角圆角半径 * @param x1 与内容框连接1点X坐标 (起始点) * @param y1 与内容框连接1点y坐标 * @param x2 与内容框连接2点X坐标 * @param y2 与内容框连接2点Xy坐标 * @param x3 三角形突出角x坐标 * @param y3 三角形突出角y坐标 */ private void addTrianglePath(Path path, float radiu, float x1, float y1, float x2, float y2, float x3, float y3) { //起始点 path.moveTo(x1, y1); path.lineTo(x2, y2); float[] ps2 = getCornerCoordinateEnd(radiu, x2, y2, x3, y3); path.lineTo(ps2[0], ps2[1]); float[] ps3 = getCornerCoordinateStart(radiu, x3, y3, x1, y1); //绘制圆角 path.cubicTo(ps2[0], ps2[1], x3, y3, ps3[0], ps3[1]); //关闭三角形 path.close(); } /** * 获取圆角坐标(圆角半径长度相对于起始点x1,y1) * * @param radiu 圆角半径 * @param x1 起始点x坐标 * @param y1 起始点y坐标 * @param x2 结束点x坐标 * @param y2 结束点y坐标 * @return */ private float[] getCornerCoordinateStart(float radiu, float x1, float y1, float x2, float y2) { double degree = MathHelper.getDegree(x1, y1, x2, y2); double lx = MathHelper.getRightSideFromDegree(degree, radiu); double ly = MathHelper.getLeftSideFromDegree(degree, radiu); double v2 = x1 + lx; double v3 = y1 + ly; return new float[]{(float) v2, (float) v3}; } /** * 获取圆角坐标(圆角半径长度相对于结束点x2,y2) * * @param radiu 圆角半径 * @param x1 起始点x坐标 * @param y1 起始点y坐标 * @param x2 结束点x坐标 * @param y2 结束点y坐标 * @return */ private float[] getCornerCoordinateEnd(float radiu, float x1, float y1, float x2, float y2) { double degree = MathHelper.getDegree(x1, y1, x2, y2); double lx = MathHelper.getRightSideFromDegree(degree, radiu); double ly = MathHelper.getLeftSideFromDegree(degree, radiu); double v2 = x2 - lx; double v3 = y2 - ly; return new float[]{(float) v2, (float) v3}; } @Override public void setColor(int color) { if (mPaint != null) { mPaint.setColor(color); } invalidateSelf(); } /** * 设置矩形的圆角 * * @param radius */ @Override public void setCornerRadius(float radius) { mRadius = radius; } }

你可能感兴趣的:(android)