您的位置:首页 > 其它

BubbleView源码解析

2015-11-12 13:43 471 查看
BubbleView源码解析

做IM应用时, 聊天界面的消息一般都有一个背景, 我们叫它为"气泡",

一般这个气泡都使用9patch图片, 但是还有一种方法就是 "自定义View".

下面就来看看github上的一个开源项目吧

BubbleView地址: https://github.com/lguipeng/BubbleView

作者定义了三个BubbleView分别为: BubbleImageView,BubbleTextVew,BubbleLinearLayout

当然最主要的功能类是: BubbleDrawable

关于这些类的用法 ==>
请看这里

效果图如下:



一. 类结构

下面是BubbleView的整体类图:



BubbleImageView, BubbleTextView, BubbleLinearLayoutView都引用了一个BubbleDrawable的实例,

都是通过BubbleDrawable的实例实现"气泡" 功能的, 但是各有不同;

二. BubbleTextView

BubbleTextView重写了onDraw()方法

@Override
protected void onDraw(Canvas canvas) {
if (bubbleDrawable != null)
bubbleDrawable.draw(canvas);
super.onDraw(canvas);
}


当然在onDraw方法之前(会收集创建bubbleDrawable对象所需的相关信息并实例化一个对象)会生成bubbleDrawable对象

此方法会先绘制背景, 即气泡背景, 然后调用父类的onDraw()绘制文本

三. BubbleLinearLayoutView

BubbleLinearLayout则重写了onSizeChanged()方法, 在此方法中收集bubbleDrawable对象所需的相关信息, 并实例化, 然后将bubbleDrawable设置为背景

代码如下:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0){
setUp(w, h); //先构建bubbleDrawable, 然后设置为背景
}
}

private void setUp(int left, int right, int top, int bottom){
if (right < left || bottom < top)
return;
RectF rectF = new RectF(left, top, right, bottom);
bubbleDrawable = new BubbleDrawable.Builder()
.rect(rectF)
.arrowLocation(mArrowLocation)
.bubbleType(BubbleDrawable.BubbleType.COLOR)
.angle(mAngle)
.arrowHeight(mArrowHeight)
.arrowWidth(mArrowWidth)
.arrowPosition(mArrowPosition)
.bubbleColor(bubbleColor)
.build();
}

private void setUp(int width, int height){
setUp(getPaddingLeft(),  + width - getPaddingRight(),
getPaddingTop(), height - getPaddingBottom());
setBackgroundDrawable(bubbleDrawable);
}


四. BubbleImageView

BubbleImageView同时实现类onDraw()和onSizeChanged()和onLayout()方法.

onDraw方法将绘制工作委托给bubbleDrawable对象, onSizeChanged()和onLayout()方法主要是在view的大小改变时重新构建bubbleDrawable,

当然绘制起泡的任务还是交给了bubbleDrawable对象

代码如下:

注意: 部分省略, setUp方法有几个重载, 但最终都会调用setUp(int, int, int, int, 因此其他省略)

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0){
setUp(w, h);
}
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
setUp();
}

@Override
protected void onDraw(Canvas canvas) {
int saveCount = canvas.getSaveCount();
canvas.translate(getPaddingLeft(), getPaddingTop());
if (bubbleDrawable != null)
bubbleDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}

private void setUp(int left, int right, int top, int bottom){
if (right <= left || bottom <= top)
return;

RectF rectF = new RectF(left, top, right, bottom);
if (sourceDrawable != null)
mBitmap = getBitmapFromDrawable(sourceDrawable);
bubbleDrawable = new BubbleDrawable.Builder()
.rect(rectF)
.arrowLocation(mArrowLocation)
.angle(mAngle)
.arrowHeight(mArrowHeight)
.arrowWidth(mArrowWidth)
.bubbleType(BubbleDrawable.BubbleType.BITMAP)
.arrowPosition(mArrowPosition)
.bubbleBitmap(mBitmap)
.build();
}


五. BubbleDrawable

此类是实现"气泡"的关键类,

实现原理:

1. 有两种类型的BubbleDrawable, color或者bitmap类型, BubbleDrawable定义了一个bubbleType变量表示,

此类型有具体的BubbleXXXView而定, 一般color类型的BubbleDrawable用于非ImageView, 而bitmap类型的BubbleDrawable用于ImageView

2. color类型的BubbleDrawable是通过Canvas绘制一个纯色的气泡形状而达到目的

3. bitmap类型的BubbleDrawable则需要通过BitmapShader对bitmap进行相关处理, 让后再通过canvas绘制bitmap

源码片段:

private void setUp(Canvas canvas){
switch (bubbleType){
case COLOR:
mPaint.setColor(bubbleColor);
break;
case BITMAP:
if (bubbleBitmap == null)
return;
if (mBitmapShader == null){
mBitmapShader = new BitmapShader(bubbleBitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
mPaint.setShader(mBitmapShader);
setUpShaderMatrix();
break;
}
setUpPath(mArrowLocation, mPath);
canvas.drawPath(mPath, mPaint);
}


4. 重写BubbleDrawable的draw方法, 并调用上述的绘制代码

由于BubbleDrawable类的代码比较多, 就不贴出类, 传送门---->
这里

第一次写源码解析类的博文, 难免出错或者逻辑混乱, 请多多指教
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: