效果如下:

可以设置颜色、描边、三角形高度和方向,以向上居中和向下居中为例

气泡.png

实现思路:

使用Canvas绘制气泡形状,因为气泡中间只显示文字,所以我直接继承TextView,重写onDraw方法。

关键代码:

1、在attrs.xml文件中自定义属性,我定义了气泡颜色、描边颜色、描边宽度、三角形高度、三角形方向代码如下:

2、Canvas绘制矩形,提供了两种重载方式:

drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)

drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)

rx表示圆心

ry表示半径

left, top可以理解为为矩形左上角点的坐标

right, bottom可以理解为矩形右下角点的坐标

如图所示:

矩形.jpg

3、Path绘制三角形,先moveTo移动到任意一点,然后lineTo画线:

描点.jpg

完整代码:

BubbleView.java

/**

* 类描述: 气泡

* 创建人: liufei

* 创建时间: 2019/10/25 15:14

*/

public class BubbleView extends AppCompatTextView {

private Paint mPaint;

private Paint mStrokePaint;

//背景颜色

private int bgColor;

//描边颜色

private int strokeColor;

//描边宽

private int strokeWidth;

//view总高

private int height;

//view总宽

private int width;

//矩形高

private int labelHeight;

//圆角半径

private int mRadius;

//三角形高

private int triangleHeight;

//三角形方向

private int triangleDirection;

public BubbleView(Context context) {

this(context, null);

}

public BubbleView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs, defStyleAttr);

}

public void init(Context context, AttributeSet attrs, int defStyleAttr) {

if (attrs != null) {

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BubbleView);

bgColor = a.getColor(R.styleable.BubbleView_bubbleColor, 0);

strokeColor = a.getColor(R.styleable.BubbleView_bubbleStrokeColor, 0);

strokeWidth = a.getDimensionPixelOffset(R.styleable.BubbleView_bubbleStrokeWidth, 0);

triangleHeight = a.getDimensionPixelOffset(R.styleable.BubbleView_triangleHeight, 30);

triangleDirection = a.getInt(R.styleable.BubbleView_triangleDirection, 0);

a.recycle();

}

setGravity(Gravity.CENTER);

initPaint();

labelHeight = getFontHeight() + getPaddingTop() + getPaddingBottom();

height = labelHeight + triangleHeight * 2 + strokeWidth * 2;

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// super.onMeasure(widthMeasureSpec, heightMeasureSpec);

width = getPaddingStart() + getFontWidth() + getPaddingEnd() + strokeWidth * 2;

setMeasuredDimension(width, height);

}

//初始化画笔

public void initPaint() {

mPaint = new Paint();

//设置抗锯齿

mPaint.setAntiAlias(true);

//设置填充

mPaint.setStyle(Paint.Style.FILL);

//设置防抖动

mPaint.setDither(true);

//字体大小

mPaint.setTextSize(getTextSize());

}

//初始化描边画笔

public void initStrokePaint() {

mStrokePaint = new Paint();

mStrokePaint.setAntiAlias(true);

mStrokePaint.setStyle(Paint.Style.FILL);

mStrokePaint.setDither(true);

}

@Override

protected void onDraw(Canvas canvas) {

drawView(canvas);

super.onDraw(canvas);

}

//绘制气泡

private void drawView(Canvas canvas) {

if (strokeColor != 0 && strokeWidth != 0) {

initStrokePaint();

mStrokePaint.setColor(strokeColor);

mRadius = labelHeight / 2 + strokeWidth;

drawRound(canvas, mStrokePaint, 0);

drawTriangle(canvas, mStrokePaint, 0);

}

if (bgColor != 0) {

mPaint.setColor(bgColor);

mRadius = labelHeight / 2;

drawRound(canvas, mPaint, strokeWidth);

drawTriangle(canvas, mPaint, strokeWidth);

}

}

//绘制矩形

private void drawRound(Canvas canvas, Paint paint, int stroke) {

canvas.drawRoundRect(stroke, triangleHeight + stroke,

width - stroke, height - triangleHeight - stroke,

mRadius, mRadius, paint);

}

//绘制三角形

private void drawTriangle(Canvas canvas, Paint paint, int stroke) {

Path path = new Path();

switch (triangleDirection) {

//上

case 1:

path.moveTo(width / 2 - triangleHeight + stroke / 2, triangleHeight + stroke);

path.lineTo(width / 2, stroke + stroke / 2);

path.lineTo(width / 2 + triangleHeight - stroke / 2, triangleHeight + stroke);

break;

//下

case 2:

path.moveTo(width / 2 - triangleHeight + stroke / 2, height - triangleHeight - stroke);

path.lineTo(width / 2, height - stroke - stroke / 2);

path.lineTo(width / 2 + triangleHeight - stroke / 2, height - triangleHeight - stroke);

break;

default:

return;

}

canvas.drawPath(path, paint);

}

//根据字号求字体高度

private int getFontHeight() {

Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();

return Math.round(fontMetrics.descent - fontMetrics.ascent);

}

//根据字号求字体宽度

private int getFontWidth() {

return (int) mPaint.measureText(getText().toString());

}

//设置气泡颜色

public void setBubbleColor(int color) {

this.bgColor = ContextCompat.getColor(getContext(), color);

invalidate();

}

//设置气泡描边

public void setStroke(int color, int width) {

this.strokeColor = ContextCompat.getColor(getContext(), color);

this.strokeWidth = width;

invalidate();

}

}

使用

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5dp"

android:padding="6dp"

android:text="向上向上"

android:textColor="#000000"

android:textSize="20sp"

app:bubbleColor="#ffffff"

app:bubbleStrokeColor="#000000"

app:bubbleStrokeWidth="2dp"

app:triangleDirection="top"

app:triangleHeight="10dp" />

android 代码设置textview draw,Android 自定义气泡TextView相关推荐

  1. android 代码设置像素,【Android实例】用设计原则来重构1像素保活代码

    1 类图 在[FJU项目]1像素进程保活(二)中,涉及到的几个类的类图如下所示(仅供参考): 实线箭头:关联 虚线箭头:依赖 重构前UML类图在上图中,OnePixelManager里面有太多的职责, ...

  2. android 代码设置居右_android如何让textview文字居右

    LinearLayoutcontainer=newLinearLayout(ctx);//设置为水平的线性布局管理器container.setOrientation(1);//定义一个线性布局管理器L ...

  3. android代码设置drawor色值,Android 着色器 tint

    本文主要总结了 Android 着色器的使用及其原理,在实现同等效果的情况下,减少资源图的使用以减小 apk 包的体积并降低对内存的占用. 假设我们想实现一种效果,如下: 不怎么友好的做法是让设计师给 ...

  4. Android代码设置角标,Android上的Badge,快速实现给应用添加角标

    应用角标是iOS的一个特点,原生Android并不支持.或许是由于当时iOS的通知栏比较鸡肋(固然如今已经改进了不少),而Android的通知栏功能强大?因此才出现了一方依赖于数字角标,一方坚持强大的 ...

  5. android代码设置弹窗颜色,Android编程实现简单设置按钮颜色的方法

    本文实例讲述了Android编程实现简单设置按钮颜色的方法.分享给大家供大家参考,具体如下: 1.工程目录 a.在res目录-新建drawble文件夹放入自定义图片 2.main.xml androi ...

  6. android 代码设置铃声,在Android中设置铃声

    慕的地6264312 解决方案是在将资源文件资产提供给内容解析器进行插入之前,先获取资源文件资产并将其写入sdcard 1st.File newSoundFile = new File("/ ...

  7. android 代码设置EditText的hint字符

    今天,简单讲讲android里如何在代码里设置  EditText的hint字符. 之前,我一般是直接在xml文件设置EditText 的hint字符,后来需要在代码里修改hint字符,发现自己居 ...

  8. android 铃声设置失败,无法通过Android代码设置铃声

    我正在开发一个应用程序,它将随机设置用户已选择的铃声列表中的铃声.无法通过Android代码设置铃声 虽然我的代码适用于Android N及以上版本,但我遇到了Android M及以下版本的问题.我为 ...

  9. Android中设置显示文本,Android文本显示控件-TextView属性详解

    android:autoLink //设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web /email/phone/map/all) andr ...

  10. Android 系统性能优化(42)---Android代码内存优化建议-Android资源篇

    Android代码内存优化建议-Android资源篇 这篇文章主要介绍在实际Android应用程序的开发中,容易导致内存泄露的一些情况.开发人员如果在进行代码编写之前就有内存泄露方面的基础知识,那么写 ...

最新文章

  1. IBM蓝色基因/Q将采用NAND闪存存储
  2. 老码农冒死揭开行业黑幕:如何编写无法维护的代码
  3. gwt-2.8.2下载_GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
  4. 影响PoE交换机不稳定的因素
  5. JAVA刷题方法整理
  6. python从云端数据库获取数据失败_使用%s的Python MySQL Connector数据库查询失败
  7. 修改Azure Website默认时区
  8. 【面试题】机器学习与深度学习常见面试题
  9. Linux系统进程管理详解
  10. js基础-19-判断图片加载完成的方法
  11. IC卡读写器开发说明
  12. Node.js中运行JavaScript代码
  13. 车联网群雄逐鹿,通信业将如何掘金?
  14. 固态硬盘(SSD)——NAND闪存芯片(颗粒)QLC、SLC、MLC、TLC
  15. 用Windows Media Service打造的流媒体直播系统
  16. 华为手机日历倒计时_倒计时软件app哪个好 苹果倒计时软件推荐
  17. 青云上NAS服务器挂的操作(他们的文档)
  18. av_register_all
  19. 数据结构课程设计报告-职工信息管理系统
  20. 重磅消息!天地图2021版正式启用!首次发布高清地图,实现电子地图无级缩放

热门文章

  1. 最近在SDK下使用WebBrowser遇到了个问题
  2. 飞鸽传书2011看到一篇国外的博客
  3. 飞秋_飞秋2010_飞秋2010下载_飞秋下载2010正式版
  4. [视频]中国军事专家论谷歌地球(Google Earth)
  5. python之线程,不得不了解的硬知识!
  6. C++ 程序员自信心曲线图
  7. 突破传统生物3D打印技术局限-王秀杰/Charlie C.L. Wang/刘永进团队合作开发新型生物3D打印体系...
  8. 参考文献中杂志名字问题
  9. VideoSolo Blu ray Player for Mac - 强大的蓝光播放器
  10. 小学奥数 7830 求小数的某一位 python