今天是我第一次在掘金发表文章,做为一个菜鸟,常常找UI哥.为啥呢?由于有些效果须要点九图啊,虽然SDK带有工具,可是首先你得有那个原图,才能在四周加线啊!因此今儿咱们就来实现一个利用Path绘制一个相似点九图的效果背景!javascript
首先,仍是来个图说明哈,无图无真相!
java
看官感兴趣就往下看!在这里感谢 github.com/lguipeng/Bu…,
咱们是站在了巨人的肩膀上,才能看得更远!下面我就参考大神的样例,加上我本身的一些体会,讲讲具体实现过程!android
在这里咱们须要使用 Path,因此先说下咱们须要使用和 Path 相关的几个APIgit
接下来咱们将效果从简单到复杂三步走, 第一步 咱们画一个矩形.github
package com.jooyer.bubbleview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* 使用 Path 实现点九图效果
* Created by Jooyer on 2017/3/11
*/
public class JooyerBubbleView extends TextView {
private Paint mPaint;
private Path mPath;
// 画笔描边默认宽度
private static final float DEFAULT_STROKE_WIDTH = 10;
public JooyerBubbleView(Context context) {
this(context, null);
}
public JooyerBubbleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public JooyerBubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mPaint = new Paint();
// 抗锯齿
mPaint.setAntiAlias(true);
// 画笔颜色
mPaint.setColor(Color.GREEN);
// 画笔的填充模式
mPaint.setStyle(Paint.Style.STROKE);
// 画笔描边宽度
mPaint.setStrokeWidth(DEFAULT_STROKE_WIDTH);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRect(canvas);
}
private void drawRect(Canvas canvas) {
mPath.moveTo(100,100);
mPath.lineTo(500,100);
mPath.lineTo(500,300);
mPath.lineTo(100,300);
mPath.close();
canvas.drawPath(mPath,mPaint);
}
}
复制代码
这里贴个布局代码,方便你们直接拷贝过去运行,就看到效果啦!
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.jooyer.bubbleview.MainActivity"> <com.jooyer.bubbleview.JooyerBubbleView android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>复制代码
获得的效果如图
canvas
有的朋友可能会问了,画个矩形,直接 canvas.drawRect()不就行了嘛!
是的,条条大路通罗马.不过咱们这里由于要用到四个角,对其进行圆弧处理,因此用 path 更方便处理了!
废话那么多,我本身都很差意思了,那么接下来实现 第二步 四个圆角部分.app
package com.jooyer.bubbleview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* 使用 Path 实现点九图效果
* Created by Jooyer on 2017/3/11
*/
public class JooyerBubbleView extends TextView {
private Paint mPaint;
private Path mPath;
// 默认圆角半径
private static final float DEFAULT_RADIUS = 50;
// 画笔描边默认宽度
private static final float DEFAULT_STROKE_WIDTH = 10;
public JooyerBubbleView(Context context) {
this(context, null);
}
public JooyerBubbleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public JooyerBubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mPaint = new Paint();
// 抗锯齿
mPaint.setAntiAlias(true);
// 画笔颜色
mPaint.setColor(Color.GREEN);
// 画笔的填充模式
mPaint.setStyle(Paint.Style.STROKE);
// 画笔描边宽度
mPaint.setStrokeWidth(DEFAULT_STROKE_WIDTH);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRect(canvas);
}
private void drawRect(Canvas canvas) {
// 这个地方由于圆弧的关系,起点须要有(100,100)改变为(100 + DEFAULT_RADIUS,100)
mPath.moveTo(100 + DEFAULT_RADIUS, 100);
// 由于绘制了一段圆弧,因此这里的终点是圆弧的起点,因此这里的值不能是(500,100)
mPath.lineTo(500 - DEFAULT_RADIUS, 100);
//绘制右上第一个圆角
mPath.arcTo(new RectF((500 - DEFAULT_RADIUS), 100, 500, (100 + DEFAULT_RADIUS)), 270, 90);
//同理这里的终点则是下一段圆弧的起点
mPath.lineTo(500, 300 - DEFAULT_RADIUS);
mPath.arcTo(new RectF((500 - DEFAULT_RADIUS), (300 - DEFAULT_RADIUS), 500, 300), 0, 90);
mPath.lineTo(100 + DEFAULT_RADIUS, 300);
mPath.arcTo(new RectF(100, (300 - DEFAULT_RADIUS), (100 + DEFAULT_RADIUS), 300), 90, 90);
mPath.lineTo(100, 300 - DEFAULT_RADIUS);
mPath.arcTo(new RectF(100, 100, (100 + DEFAULT_RADIUS), (100 + DEFAULT_RADIUS)), 180, 90);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
}
复制代码
获得的效果如图:ide
估计你们有个疑问,第一个圆弧那里:
mPath.arcTo(new RectF((500 - DEFAULT_RADIUS), 100, 500, (100 + DEFAULT_RADIUS)), 270, 90); 为什么是270°呢?
开始我也没搞明白,后来才知道,Android里面绘图角度是顺时针转动的,朝右为正,朝下为正.请看下图:工具
注释比较清楚了,其余的若是有问题就给我发邮件吧?Jooyer@outlook.com,注意第一个字符大写哦!布局
好了,终于到了咱们最后阶段了.
package com.jooyer.bubbleview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* 使用 Path 实现点九图效果
* Created by Jooyer on 2017/3/11
*/
public class JooyerBubbleView extends TextView {
private Paint mPaint;
private Path mPath;
// 默认圆角半径
private static final float DEFAULT_RADIUS = 50;
// 画笔描边默认宽度
private static final float DEFAULT_STROKE_WIDTH = 10;
public JooyerBubbleView(Context context) {
this(context, null);
}
public JooyerBubbleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public JooyerBubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mPaint = new Paint();
// 抗锯齿
mPaint.setAntiAlias(true);
// 画笔颜色
mPaint.setColor(Color.GREEN);
// 画笔的填充模式
mPaint.setStyle(Paint.Style.STROKE);
// 画笔描边宽度
mPaint.setStrokeWidth(DEFAULT_STROKE_WIDTH);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRect(canvas);
}
private void drawRect(Canvas canvas) {
// 这个地方由于圆弧的关系,起点须要有(100,100)改变为(100 + DEFAULT_RADIUS,100)
mPath.moveTo(100 + DEFAULT_RADIUS, 100);
// 由于绘制了一段圆弧,因此这里的终点是圆弧的起点,因此这里的值不能是(500,100)
mPath.lineTo(500 - DEFAULT_RADIUS, 100);
//绘制右上第一个圆角
mPath.arcTo(new RectF((500 - DEFAULT_RADIUS), 100, 500, (100 + DEFAULT_RADIUS)), 270, 90);
//同理这里的终点则是下一段圆弧的起点
mPath.lineTo(500, 300 - DEFAULT_RADIUS);
mPath.arcTo(new RectF((500 - DEFAULT_RADIUS), (300 - DEFAULT_RADIUS), 500, 300), 0, 90);
mPath.lineTo(100 + DEFAULT_RADIUS, 300);
mPath.arcTo(new RectF(100, (300 - DEFAULT_RADIUS), (100 + DEFAULT_RADIUS), 300), 90, 90);
// 假设咱们想凸起部分在左侧,其实咱们知道凸起部分就是2条线段而已,因此处理就简单了
// 咱们假设凸起部分的高度为 50 ,宽度也为50,也就是三角的底边长度50,底边高度也是50
// mPath.lineTo(100, 100 + DEFAULT_RADIUS);
// 那么上面的这个线则不能移动到 (100, 100 + DEFAULT_RADIUS),必须加上一个三角形底边长度
mPath.lineTo(100, 100 + DEFAULT_RADIUS + 50);
// 等腰三角形,因此其定点高度值为底边一半
mPath.lineTo(100 - 50, 100 + DEFAULT_RADIUS + 25);
mPath.lineTo(100,100 + DEFAULT_RADIUS);
mPath.arcTo(new RectF(100, 100, (100 + DEFAULT_RADIUS), (100 + DEFAULT_RADIUS)), 180, 90);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
}
复制代码
获得的效果如图:
是否是以为三角很丑呢,这个你能够根据须要调整其大小,就好看咯!
三部曲完成了,那么接下来就是咱们的实际使用时间了.上面只是演示 Path 具体用法,可是若是想把上面的效果看成点九图来使用,也为了之后的复用,咱们将画笔操做单独提出来,放在一个自定义的drawble中,这个 drawable仅仅使用了以上画笔的功能,也就是把画笔的这部分功能封装在drawable 里面了而已!
首先咱们看看 JooyerBubbleDrawable 这个类
package com.jooyer.bubbleview;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
/**
* Created by Jooyer on 2017/3/11
*/
public class JooyerBubbleDrawable extends Drawable {
private static final String TAG = JooyerBubbleDrawable.class.getSimpleName();
/**
* 保存坐标(自定义控件的大小)
*/
private RectF mRect;
/**
* 气泡的路径
*/
private Path mPath = new Path();
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/**
* 箭头宽度
*/
private float mArrowWidth;
/**
* 箭头宽度
*/
private float mArrowHeight;
/**
* 圆弧半径
*/
private float mRadius;
/**
* 箭头所在位置偏移量
*/
private float mArrowOffset;
/**
* 气泡背景色
*/
private int mBubbleColor;
/**
* 三角箭头所在位置
*/
private ArrowDirection mArrowDirection;
/**
* 箭头是否居中
*/
private boolean mArrowCenter;
/**
* 重写此方法,在这里实现和 自定义控件中 onDraw 相似的功能
*/
@Override
public void draw(Canvas canvas) {
mPaint.setColor(mBubbleColor);
setUpPath(mArrowDirection, mPath);
canvas.drawPath(mPath, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT; //窗口透明化
}
private void setUpPath(ArrowDirection arrowDirection, Path path) {
switch (arrowDirection) {
case LEFT:
setUpLeftPath(mRect, path);
break;
case TOP:
setUpTopPath(mRect, path);
break;
case RIGHT:
setUpRightPath(mRect, path);
break;
case BOTTOM:
setUpBottomPath(mRect,path);
break;
}
}
/**
* 箭头朝左
*/
private void setUpLeftPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.bottom - rect.top - mArrowWidth) / 2;
path.moveTo(rect.left + mArrowWidth + mRadius, rect.top);
path.lineTo(rect.width() - mRadius, rect.top); // 这里的rect.width() 是能够使用rect.right
Log.i(TAG, "====setUpLeftPath========" + (rect.width() - mRadius) + "======= : " + (rect.right - mRadius));
path.arcTo(new RectF(rect.right - mRadius, rect.top, rect.right, rect.top + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mRadius, mRect.bottom - mRadius, rect.right, rect.bottom), 0, 90);
path.lineTo(rect.left + mArrowWidth + mRadius, rect.bottom);
path.arcTo(new RectF(rect.left + mArrowWidth, rect.bottom - mRadius, rect.left + mArrowWidth + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left + mArrowWidth, mArrowHeight + mArrowOffset);
path.lineTo(rect.left, mArrowOffset + mArrowHeight / 2);
path.lineTo(rect.left + mArrowWidth, mArrowOffset);
path.lineTo(rect.left + mArrowWidth, rect.top + mRadius);
path.arcTo(new RectF(rect.left + mArrowWidth, mRect.top, rect.left + mArrowWidth + mRadius, rect.top + mRadius), 180, 90);
path.close();
}
/**
* 箭头朝上
*/
private void setUpTopPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.right - rect.left - mArrowWidth) / 2;
path.moveTo(rect.left + Math.min(mRadius, mArrowOffset), rect.top + mArrowHeight);
path.lineTo(rect.left + mArrowOffset, rect.top + mArrowHeight);
path.lineTo(rect.left + mArrowOffset + mArrowWidth / 2, rect.top);
path.lineTo(rect.left + mArrowOffset + mArrowWidth, rect.top + mArrowHeight);
path.lineTo(rect.right - mRadius, rect.top + mArrowHeight);
path.arcTo(new RectF(rect.right - mRadius, rect.top + mArrowHeight, rect.right, rect.top + mArrowHeight + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mRadius, rect.bottom - mRadius, rect.right, rect.bottom), 0, 90);
path.lineTo(rect.left + mRadius, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mRadius, rect.left + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top + mArrowHeight + mRadius);
path.arcTo(new RectF(rect.left, rect.top + mArrowHeight, rect.left + mRadius, rect.top + mArrowHeight + mRadius), 180, 90);
path.close();
}
/**
* 箭头朝右
*/
private void setUpRightPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.bottom - rect.top - mArrowWidth) / 2;
path.moveTo(rect.left + mRadius, rect.top);
path.lineTo(rect.right - mRadius - mArrowWidth, rect.top);
path.arcTo(new RectF(rect.right - mArrowWidth - mRadius, rect.top, rect.right - mArrowWidth, rect.top + mRadius), 270, 90);
path.lineTo(rect.right - mArrowWidth, rect.top + mArrowOffset);
path.lineTo(rect.right, rect.top + mArrowOffset + mArrowHeight / 2);
path.lineTo(rect.right - mArrowWidth, rect.top + mArrowOffset + mArrowHeight);
path.lineTo(rect.right - mArrowWidth, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mArrowWidth - mRadius, rect.bottom - mRadius, rect.right - mArrowWidth, rect.bottom), 0, 90);
path.lineTo(rect.right - mArrowWidth - mRadius, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mRadius, rect.left + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top + mRadius);
path.arcTo(new RectF(rect.left, rect.top, rect.left + mRadius, rect.top + mRadius), 180, 90);
path.close();
}
/**
* 箭头朝下
*/
private void setUpBottomPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.right - rect.left - mArrowWidth) / 2;
path.moveTo(rect.left + mRadius, rect.top);
path.lineTo(rect.right - mRadius, rect.top);
path.arcTo(new RectF(rect.right - mRadius, rect.top, rect.right, rect.top + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mArrowHeight - mRadius);
path.arcTo(new RectF(rect.right - mRadius, rect.bottom - mArrowHeight - mRadius, rect.right, rect.bottom - mArrowHeight), 0, 90);
path.lineTo(rect.left + mArrowOffset + mArrowWidth, rect.bottom - mArrowHeight);
path.lineTo(rect.left + mArrowOffset + mArrowWidth / 2, rect.bottom);
path.lineTo(rect.left + mArrowOffset, rect.bottom - mArrowHeight);
path.lineTo(rect.left + mRadius, rect.bottom - mArrowHeight);
path.arcTo(new RectF(rect.left, rect.bottom - mArrowHeight - mRadius, rect.left + mRadius, rect.bottom - mArrowHeight), 90, 90);
path.lineTo(rect.left, rect.top + mRadius);
path.arcTo(new RectF(rect.left, rect.top,rect.left + mRadius,rect.top + mRadius),180,90);
path.close();
}
private JooyerBubbleDrawable(Builder builder) {
this.mRect = builder.mRectF;
this.mRadius = builder.mRadius;
this.mArrowWidth = builder.mArrowWidth;
this.mArrowHeight = builder.mArrowHeight;
this.mArrowOffset = builder.mArrowOffset;
this.mBubbleColor = builder.mBubbleColor;
this.mArrowDirection = builder.mArrowDirection;
this.mArrowCenter = builder.mArrowCenter;
}
/**
* 建造者模式
*/
public static class Builder {
/**
* 箭头默认宽度
*/
public static float DEFAULT_ARROW_WIDTH = 25;
/**
* 箭头默认高度
*/
public static float DEFAULT_ARROW_HEIGHT = 25;
/**
* 默认圆角半径
*/
public static float DEFAULT_RADIUS = 20;
/**
* 默认箭头偏移量
*/
public static float DEFAULT_ARROW_OFFSET = 50;
/**
* 气泡默认背景颜色
*/
public static int DEFAULT_BUBBLE_COLOR = Color.RED;
private RectF mRectF;
private float mArrowWidth = DEFAULT_ARROW_WIDTH;
private float mArrowHeight = DEFAULT_ARROW_HEIGHT;
private float mRadius = DEFAULT_RADIUS;
private float mArrowOffset = DEFAULT_ARROW_OFFSET;
private int mBubbleColor = DEFAULT_BUBBLE_COLOR;
private ArrowDirection mArrowDirection = ArrowDirection.LEFT;
private boolean mArrowCenter;
public Builder rect(RectF rect) {
this.mRectF = rect;
return this;
}
public Builder arrowWidth(float width) {
this.mArrowWidth = width;
return this;
}
public Builder arrowHeight(float height) {
this.mArrowHeight = height;
return this;
}
public Builder radius(float angle) {
this.mRadius = angle; //TODO
return this;
}
public Builder arrowOffset(float position) {
this.mArrowOffset = position;
return this;
}
public Builder bubbleColor(int color) {
this.mBubbleColor = color;
return this;
}
public Builder arrowDirection(ArrowDirection direction) {
this.mArrowDirection = direction;
return this;
}
public Builder arrowCenter(boolean arrowCenter) {
this.mArrowCenter = arrowCenter;
return this;
}
public JooyerBubbleDrawable build() {
if (null == mRectF) {
throw new IllegalArgumentException("BubbleDrawable RectF can not be null");
}
return new JooyerBubbleDrawable(this);
}
}
/**
* 箭头位置
*/
public enum ArrowDirection {
LEFT(0x00),
TOP(0x01),
RIGHT(0x02),
BOTTOM(0x03);
private int mValue;
ArrowDirection(int value) {
mValue = value;
}
private int getIntValue() {
return mValue;
}
public static ArrowDirection getDefault() {
return LEFT;
}
public static ArrowDirection mapIntToValue(int stateInt) {
for (ArrowDirection value : ArrowDirection.values()) {
if (stateInt == value.getIntValue()) {
return value;
}
}
return getDefault();
}
}
}
复制代码
而后看看 JooyerTextView 这个类:
package com.jooyer.bubbleview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* Created by Jooyer on 2017/3/11
*/
public class JooyerTextView extends TextView {
private static String TAG = JooyerTextView.class.getSimpleName();
private JooyerBubbleDrawable mBubbleDrawable;
private float mArrowWidth;
private float mArrowHeight;
private float mRadius;
private float mArrowOffset;
private int mBubbleColor;
private JooyerBubbleDrawable.ArrowDirection mArrowDirection;
private boolean mArrowCenter;
public JooyerTextView(Context context) {
this(context,null);
}
public JooyerTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public JooyerTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.JooyerBubble);
mArrowWidth = array.getDimension(R.styleable.JooyerBubble_jooyer_bubble_arrow_width,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_WIDTH);
mArrowHeight = array.getDimension(R.styleable.JooyerBubble_jooyer_bubble_arrow_width,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_HEIGHT);
mArrowOffset = array.getDimension(R.styleable.JooyerBubble_jooyer_bubble_arrow_width,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_OFFSET);
mRadius = array.getDimension(R.styleable.JooyerBubble_jooyer_bubble_arrow_width,
JooyerBubbleDrawable.Builder.DEFAULT_RADIUS);
mBubbleColor = array.getColor(R.styleable.JooyerBubble_jooyer_bubble_arrow_color,
JooyerBubbleDrawable.Builder.DEFAULT_BUBBLE_COLOR);
mArrowCenter = array.getBoolean(R.styleable.JooyerBubble_jooyer_bubble_arrow_center,
false);
int direction = array.getInt(R.styleable.JooyerBubble_jooyer_bubble_arrow_direction,
0);
mArrowDirection = JooyerBubbleDrawable.ArrowDirection.mapIntToValue(direction);
array.recycle();
setPadding();
}
/**
* 因为箭头的问题,当有 padding 时咱们须要再加三角箭头的尺寸
*/
private void setPadding() {
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom();
switch (mArrowDirection){
case LEFT:
left += mArrowWidth;
break;
case TOP:
top += mArrowHeight;
break;
case RIGHT:
right += mArrowWidth;
break;
case BOTTOM:
bottom += mArrowHeight;
break;
}
setPadding(left,top,right,bottom);
}
/**
* 当大小发生改变时,咱们须要重绘
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0) {
reset(w, h);
}
}
/**
* 当位置发生改变时,咱们须要重绘
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
reset(getWidth(),getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制背景
if (null != mBubbleDrawable){
mBubbleDrawable.draw(canvas);
}
super.onDraw(canvas);
}
private void reset(int width, int height) {
reset(0,0,width,height);
}
private void reset(int left, int top, int right, int bottom) {
RectF rectF = new RectF(left,top,right,bottom);
mBubbleDrawable = new JooyerBubbleDrawable.Builder()
.rect(rectF)
.arrowWidth(mArrowWidth)
.arrowHeight(mArrowHeight)
.radius(mRadius)
.arrowOffset(mArrowOffset)
.arrowDirection(mArrowDirection)
.arrowCenter(mArrowCenter)
.bubbleColor(mBubbleColor)
.build();
}
}
复制代码
接着看下 jooyer_bobbleview_attrs 这个文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JooyerBubble">
<!-- 三角箭头宽度 -->
<attr name="jooyer_bubble_arrow_width" format="dimension"/>
<!-- 三角箭头高度 -->
<attr name="jooyer_bubble_arrow_height" format="dimension"/>
<!-- 三角箭头位置(相对偏移量) -->
<attr name="jooyer_bubble_arrow_offset" format="dimension"/>
<!-- 气泡圆角半径 -->
<attr name="jooyer_bubble_arrow_radius" format="dimension"/>
<!-- 气泡背景颜色 -->
<attr name="jooyer_bubble_arrow_color" format="color"/>
<!-- 三角箭头是否居中 -->
<attr name="jooyer_bubble_arrow_center" format="boolean"/>
<!-- 三角箭头方向朝向 -->
<attr name="jooyer_bubble_arrow_direction" format="enum">
<enum name="jooyer_bubble_arrow_direction_left" value="0x00"/>
<enum name="jooyer_bubble_arrow_direction_top" value="0x01"/>
<enum name="jooyer_bubble_arrow_direction_right" value="0x02"/>
<enum name="jooyer_bubble_arrow_direction_bottom" value="0x03"/>
</attr>
</declare-styleable>
</resources>复制代码
还有布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context="com.jooyer.bubbleview.MainActivity"> <com.jooyer.bubbleview.JooyerTextView android:text="@string/test" android:textSize="20sp" android:textColor="@color/color_test" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" app:jooyer_bubble_arrow_width="20dp" app:jooyer_bubble_arrow_height="20dp" app:jooyer_bubble_arrow_offset="20dp" app:jooyer_bubble_arrow_radius="20dp" app:jooyer_bubble_arrow_color="#e363e134" app:jooyer_bubble_arrow_center="false" app:jooyer_bubble_arrow_direction="jooyer_bubble_arrow_direction_left" /> </LinearLayout>复制代码
最后来看下运行的效果图:
是否是以为不错呢,哈哈!若是喜欢记得点赞收藏和关注哦哦!下一章我们就理由今天的学习实现常见toolbar点击弹出菜单效果,欢喜前来踢场!