今天是我第一次在掘金髮表文章,做爲一個菜鳥,常常找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點擊彈出菜單效果,歡喜前來踢場!