项目中聊天模块要实现图片消息和视频消息带尖嘴的效果。
老的项目中实现方式是 重写ImageView的onDraw方法,通过BitMapShaper和Path路径实现圆角和尖角的绘制。
新的项目中大量的使用了fresco的simpleDraweeView,故需要一种新的实现方式。
实现圆角或尖角的原理:
欲实现圆角和尖嘴有两种实现技术:BitMapShaper 和PorterDuffXfermode。本文使用PorterDuffXfermode ,不过多介绍BitMapShaper。
PorterDuffXfermode 图形混合模式
该类有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),通过PorterDuff.Mode 可以实现两个图形的各种组合效果。
下图是PorterDuff.Mode取不同值时的组合效果:
在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式:
ADD:饱和相加,对图像饱和度进行相加,不常用
CLEAR:清除图像
DARKEN:变暗,较深的颜色覆盖较浅的颜色,若两者深浅程度相同则混合
DST:只显示目标图像
DST_ATOP:在源图像和目标图像相交的地方绘制【目标图像】,在不相交的地方绘制【源图像】,相交处的效果受到源图像和目标图像alpha的影响
DST_IN:只在源图像和目标图像相交的地方绘制【目标图像】,绘制效果受到源图像对应地方透明度影响
DST_OUT:只在源图像和目标图像不相交的地方绘制【目标图像】,在相交的地方根据源图像的alpha进行过滤,源图像完全不透明则完全过滤,完全透明则不过滤
DST_OVER:将目标图像放在源图像上方
LIGHTEN:变亮,与DARKEN相反,DARKEN和LIGHTEN生成的图像结果与Android对颜色值深浅的定义有关
MULTIPLY:正片叠底,源图像素颜色值乘以目标图像素颜色值除以255得到混合后图像像素颜色值
OVERLAY:叠加
SCREEN:滤色,色调均和,保留两个图层中较白的部分,较暗的部分被遮盖
SRC:只显示源图像
SRC_ATOP:在源图像和目标图像相交的地方绘制【源图像】,在不相交的地方绘制【目标图像】,相交处的效果受到源图像和目标图像alpha的影响
SRC_IN:只在源图像和目标图像相交的地方绘制【源图像】
SRC_OUT:只在源图像和目标图像不相交的地方绘制【源图像】,相交的地方根据目标图像的对应地方的alpha进行过滤,目标图像完全不透明则完全过滤,完全透明则不过滤
SRC_OVER:将源图像放在目标图像上方
XOR:在源图像和目标图像相交的地方之外绘制它们,在相交的地方受到对应alpha和色值影响,如果完全不透明则相交处完全不绘制。
此处应该使用SRC_IN,取两个图形的交集
PorterDuffXfermode 实现圆形图片
/**
* 根据原图和边场绘制圆形图片
*
* @param source
* @param min
* @return
*/
private Bitmap createCircleImage(Bitmap source, int min)
{
final Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min, min, Config.ARGB_8888);
/**
* 产生一个同样大小的画布
*/
Canvas canvas = new Canvas(target);
/**
* (1)首先绘制圆形 - 第一次绘制
*/
canvas.drawCircle(min / 2, min / 2, min / 2, paint);
/**
* (2)paint使用SRC_IN,取两次绘制的交集
*/
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
/**
* (3)绘制图片 -第二次绘制
*/
canvas.drawBitmap(source, 0, 0, paint);
return target;
}
首先创建一个Canvas,然后就是三步走:
- 第一步 在canva上绘制一个圆形。
- 第二步 paint.setXfermode() 指定PorterDuff.Mode.SRC_IN,取两次绘制的交集。
- 第三步 将原bitmap绘制在Canvas上,进行第二次绘制。
最终 原始的图片成了一个图形图片。
PorterDuffXfermode 实现尖嘴图片
原理同“圆形图片”,只不过将canvas.drawCircle 绘制圆形改成canvas.drawPath(path,paint) 绘制特定路径,其中path实现一个尖嘴路径。
绘制尖角路径的方法如下:
/**
* 绘制尖嘴在左侧的path
*
* A
* * * * * * * * * * * * * *
* * * *
* * * *
* * F * B *
* * * *
* * mArrowTop * * * * * * **
* * *
* * *
* * *
* * *
* * * C
* * *
* * *
* * E *
* * *
* * *
* * *
* * *
* * *
* * *
* * * * * * * * * * * * * * *
* D
*
* @param rect
* @param path 如上图所示 从A点开始 顺时针绘制path路径.
*/
public void leftPath(RectF rect, Path path) {
path.moveTo(mCornerRadius + mArrowWidth, rect.top);//移动到A点
path.lineTo(rect.width(), rect.top);//顶部横线
path.arcTo(new RectF(rect.right - mCornerRadius * 2, rect.top, rect.right,
mCornerRadius * 2 + rect.top), 270, 90);//绘制 右上角的90度的圆弧. (B对应的区域)
path.lineTo(rect.right, rect.top);//绘制 右侧直线
path.arcTo(new RectF(rect.right - mCornerRadius * 2, rect.bottom - mCornerRadius * 2,
rect.right, rect.bottom), 0, 90);//右下角圆弧
path.lineTo(rect.left + mArrowWidth, rect.bottom);//底部横线 (D对应的横线)
path.arcTo(new RectF(rect.left + mArrowWidth, rect.bottom - mCornerRadius * 2,
mCornerRadius * 2 + rect.left + mArrowWidth, rect.bottom), 90, 90);//左下角圆弧
path.lineTo(rect.left + mArrowWidth, mArrowTop + mArrowHeight);//左侧偏下部竖线(E所示竖线)
path.lineTo(rect.left, mArrowTop - mArrowOffset);//左侧凸起尖角 下半部分斜线
path.lineTo(rect.left + mArrowWidth, mArrowTop); //左侧凸起尖角 上半部分斜线
path.lineTo(rect.left + mArrowWidth, rect.top);//左侧片上部竖线(F所示竖线)
path.arcTo(new RectF(rect.left + mArrowWidth, rect.top, mCornerRadius * 2
+ rect.left + mArrowWidth, mCornerRadius * 2 + rect.top), 180, 90);//左上角圆弧
path.close();
}
PorterDuffXfermode 与SimpleDraweeView结合
我们知道fresco的SimpleDraweeView 中包含了多个图层,以显示placeholder、loading、加载失败等状态。所以不能简单的继承SimpleDraweeView重写onDraw方法。需要寻找新的方法。
查询fresco官网 发现fresco提供了一种叫做后处理器BasePostprocessor的工具,允许在bitmap下载完成后,对原始bitmap进行一些处理。
- 尝试一 :利用BasePostprocessor,对下载完成的图片利用PorterDuffXfermode 生成尖嘴 再返回处理后的图片。
public void showImage(final Uri uri, final int imageSuitableWidth, final int imageSuitableHeight){
Postprocessor redMeshPostPorcessor = new BasePostprocessor() {
@Override
public void process(Bitmap destBitmap, Bitmap sourceBitmap) {
Canvas canvas = new Canvas(destBitmap);
int color = 0xff424242;// int color = 0xff424242;
Paint paint = new Paint();
paint.setColor(color);
// 防止锯齿
paint.setAntiAlias(true);
Rect rect = new Rect(0,0,sourceBitmap.getWidth(),sourceBitmap.getHeight());
RectF rectF = new RectF(rect);
Path path = new Path();
if(mArrowLocation == LOCATION_LEFT){
leftPath(rectF,path);
}else {
rightPath(rectF,path);
}
canvas.drawARGB(0,0,0,0);
canvas.drawPath(path,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(sourceBitmap,rect,rect,paint);
LogUtils.d(TAG,"test size - redMeshPostPorcessor.width:"+sourceBitmap.getWidth()+",height:"+sourceBitmap.getHeight()+",destBitmap.width:"+destBitmap.getWidth()+",destBitMap.height:"+destBitmap.getHeight()+",imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight+",mArrowWidth:"+mArrowWidth+",location:"+mArrowLocation+",uri:"+uri);
}
};
//LogUtils.d(TAG,"test size - imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(imageSuitableWidth, imageSuitableHeight))
.setPostprocessor(redMeshPostPorcessor)
.build();
ViewGroup.LayoutParams params = getLayoutParams();
params.width = imageSuitableWidth;
params.height = imageSuitableHeight;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(getController())
.setImageRequest(request)
.build();
setController(controller);
setLayoutParams(params);
}
经测试基本实现了尖角效果,但是却存在一个问题:尖角效果是在原始Bitmap上重新绘制实现的,原始的bitmap 在SimpleDrawView上显示时,经常要经过一个放缩的处理,这个过程中绘制的尖角会被等比例的放大和缩小。导致的结果是 不同大小的图片 经过放缩处理后,在聊天列表页面显示时 尖嘴的大小也大小不一。
如何解决这个问题呢?查阅文档后发现fresco 后处理器 还有另一个方法,允许改变bitmap的大小
public CloseableReference process(
Bitmap sourceBitmap,
PlatformBitmapFactory bitmapFactory) {
}
- 尝试二 重写BasePostprocessor,处理原始图片时 首先把原始图片放缩到 最终要显示的大小,然后再添加尖角效果。问题解决。
public void showImage(final Uri uri, final int imageSuitableWidth, final int imageSuitableHeight){
Postprocessor redMeshPostPorcessor = new BasePostprocessor() {
@Override
public CloseableReference process(
Bitmap sourceBitmap,
PlatformBitmapFactory bitmapFactory) {
//创建一个安全的 新的bitmap
CloseableReference bitmapRef = bitmapFactory.createBitmap(
imageSuitableWidth,
imageSuitableHeight);
try {
Bitmap destBitmap = bitmapRef.get();
Canvas canvas = new Canvas(destBitmap);
int color = 0xff424242;// int color = 0xff424242;
Paint paint = new Paint();
paint.setColor(color);
// 防止锯齿
paint.setAntiAlias(true);
Rect rect = new Rect(0,0,imageSuitableWidth,imageSuitableHeight);
RectF rectF = new RectF(rect);
Path path = new Path();
if(mArrowLocation == LOCATION_LEFT){
leftPath(rectF,path);
}else {
rightPath(rectF,path);
}
canvas.drawARGB(0,0,0,0);
canvas.drawPath(path,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
float scale = 1.0f;
float scaleWidth = (float) (imageSuitableWidth*1.0/sourceBitmap.getWidth());
float scaleHeight = (float) (imageSuitableHeight*1.0/sourceBitmap.getHeight());
scale = Math.max(scaleWidth,scaleHeight);
// canvas.drawBitmap(sourceBitmap,rect,rect,paint);
Matrix matrix = new Matrix();
matrix.postScale(scale,scale);
LogUtils.d(TAG,"scaleWidth:"+scaleWidth+",scaleHeight:"+scaleHeight+",scale:"+scale);
LogUtils.d(TAG,"test size - redMeshPostPorcessor.width:"+sourceBitmap.getWidth()+",height:"+sourceBitmap.getHeight()+",destBitmap.width:"+destBitmap.getWidth()+",destBitMap.height:"+destBitmap.getHeight()+",imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight+",mArrowWidth:"+mArrowWidth+",location:"+mArrowLocation+",uri:"+uri);
canvas.drawBitmap(sourceBitmap,matrix,paint);
return CloseableReference.cloneOrNull(bitmapRef);
} finally {
CloseableReference.closeSafely(bitmapRef);
}
}
};
//LogUtils.d(TAG,"test size - imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(imageSuitableWidth, imageSuitableHeight))
.setPostprocessor(redMeshPostPorcessor)
.build();
ViewGroup.LayoutParams params = getLayoutParams();
params.width = imageSuitableWidth;
params.height = imageSuitableHeight;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(getController())
.setImageRequest(request)
.build();
setController(controller);
setLayoutParams(params);
}
完整代码:
重写SimpleDraweView实现自定义ArrowSimpleDraweeView
package com.sogou.arrowsdview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.facebook.common.references.CloseableReference;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.request.BasePostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.request.Postprocessor;
/**
* Created by baixuefei on 18/2/11.
*/
public class ArrowSimpleDraweeView extends SimpleDraweeView {
private static final String TAG = ArrowSimpleDraweeView.class.getSimpleName();
private float mCornerRadius ;
private float mArrowTop ;//尖角纵向顶部到矩形登录的距离.
private float mArrowWidth ;//尖角的横向宽度.
private float mArrowHeight ;//尖角的纵向高度
private float mArrowOffset ;
private int mArrowLocation = 0;
private static final int LOCATION_LEFT = 0;
private static final int LOCATION_RIGHT = 1;
private Context mContext;
public ArrowSimpleDraweeView(Context context) {
super(context);
mContext = context;
intiView(null);
}
public ArrowSimpleDraweeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
intiView(attrs);
}
public ArrowSimpleDraweeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
intiView(attrs);
}
public void intiView(AttributeSet attrs){
mCornerRadius = DensityUtils.dip2px(mContext,10);
mArrowTop =DensityUtils.dip2px(mContext,40);//尖角纵向顶部到矩形登录的距离.
mArrowWidth = DensityUtils.dip2px(mContext,10);//尖角的横向宽度.
mArrowHeight = DensityUtils.dip2px(mContext,20);//尖角的纵向高度
mArrowOffset = -DensityUtils.dip2px(mContext,10);
if(attrs != null){
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ArrowSimpleDraweeView);
mCornerRadius = a.getDimension(R.styleable.ArrowSimpleDraweeView_aCornerRadius,mCornerRadius);
mArrowTop = a.getDimension(R.styleable.ArrowSimpleDraweeView_arrowTop,mArrowTop);
float tmp = a.getDimension(R.styleable.ArrowSimpleDraweeView_arrowWidth,mArrowWidth);
mArrowWidth = tmp;
//LogUtils.d(TAG,"mArrowWidth:"+tmp+",DensityUtils.dip2px(10):"+DensityUtils.dip2px(10));
mArrowHeight = a.getDimension(R.styleable.ArrowSimpleDraweeView_arrowHeihgt,mArrowHeight);
mArrowOffset = a.getDimension(R.styleable.ArrowSimpleDraweeView_arrowOffsety,mArrowOffset);
mArrowLocation = a.getInt(R.styleable.ArrowSimpleDraweeView_arrowLocation,mArrowLocation);
a.recycle();
}
}
public void showImage(final Uri uri, final int imageSuitableWidth, final int imageSuitableHeight){
// Postprocessor redMeshPostPorcessor = new BasePostprocessor() {
// @Override
// public void process(Bitmap destBitmap, Bitmap sourceBitmap) {
//
// Canvas canvas = new Canvas(destBitmap);
// int color = 0xff424242;// int color = 0xff424242;
// Paint paint = new Paint();
// paint.setColor(color);
// // 防止锯齿
// paint.setAntiAlias(true);
//
// Rect rect = new Rect(0,0,sourceBitmap.getWidth(),sourceBitmap.getHeight());
//
// RectF rectF = new RectF(rect);
//
// Path path = new Path();
// if(mArrowLocation == LOCATION_LEFT){
// leftPath(rectF,path);
// }else {
// rightPath(rectF,path);
// }
// canvas.drawARGB(0,0,0,0);
// canvas.drawPath(path,paint);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// canvas.drawBitmap(sourceBitmap,rect,rect,paint);
//
// LogUtils.d(TAG,"test size - redMeshPostPorcessor.width:"+sourceBitmap.getWidth()+",height:"+sourceBitmap.getHeight()+",destBitmap.width:"+destBitmap.getWidth()+",destBitMap.height:"+destBitmap.getHeight()+",imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight+",mArrowWidth:"+mArrowWidth+",location:"+mArrowLocation+",uri:"+uri);
// }
// };
Postprocessor redMeshPostPorcessor = new BasePostprocessor() {
@Override
public CloseableReference process(
Bitmap sourceBitmap,
PlatformBitmapFactory bitmapFactory) {
//创建一个安全的 新的bitmap
CloseableReference bitmapRef = bitmapFactory.createBitmap(
imageSuitableWidth,
imageSuitableHeight);
try {
Bitmap destBitmap = bitmapRef.get();
Canvas canvas = new Canvas(destBitmap);
int color = 0xff424242;// int color = 0xff424242;
Paint paint = new Paint();
paint.setColor(color);
// 防止锯齿
paint.setAntiAlias(true);
Rect rect = new Rect(0,0,imageSuitableWidth,imageSuitableHeight);
RectF rectF = new RectF(rect);
Path path = new Path();
if(mArrowLocation == LOCATION_LEFT){
leftPath(rectF,path);
}else {
rightPath(rectF,path);
}
canvas.drawARGB(0,0,0,0);
canvas.drawPath(path,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
float scale = 1.0f;
float scaleWidth = (float) (imageSuitableWidth*1.0/sourceBitmap.getWidth());
float scaleHeight = (float) (imageSuitableHeight*1.0/sourceBitmap.getHeight());
scale = Math.max(scaleWidth,scaleHeight);
// canvas.drawBitmap(sourceBitmap,rect,rect,paint);
Matrix matrix = new Matrix();
matrix.postScale(scale,scale);
//LogUtils.d(TAG,"scaleWidth:"+scaleWidth+",scaleHeight:"+scaleHeight+",scale:"+scale);
//LogUtils.d(TAG,"test size - redMeshPostPorcessor.width:"+sourceBitmap.getWidth()+",height:"+sourceBitmap.getHeight()+",destBitmap.width:"+destBitmap.getWidth()+",destBitMap.height:"+destBitmap.getHeight()+",imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight+",mArrowWidth:"+mArrowWidth+",location:"+mArrowLocation+",uri:"+uri);
canvas.drawBitmap(sourceBitmap,matrix,paint);
return CloseableReference.cloneOrNull(bitmapRef);
} finally {
CloseableReference.closeSafely(bitmapRef);
}
}
};
//LogUtils.d(TAG,"test size - imageSuitableWidth:"+imageSuitableWidth+",imageSuitableHeight:"+imageSuitableHeight);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(imageSuitableWidth, imageSuitableHeight))
.setPostprocessor(redMeshPostPorcessor)
.build();
ViewGroup.LayoutParams params = getLayoutParams();
params.width = imageSuitableWidth;
params.height = imageSuitableHeight;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(getController())
.setImageRequest(request)
.build();
setController(controller);
setLayoutParams(params);
}
/**
* 绘制尖角在左侧的path
*
* A
* * * * * * * * * * * * * *
* * * *
* * * *
* * F * B *
* * * *
* * mArrowTop * * * * * * **
* * *
* * *
* * *
* * *
* * * C
* * *
* * *
* * E *
* * *
* * *
* * *
* * *
* * *
* * *
* * * * * * * * * * * * * * *
* D
*
* @param rect
* @param path 如上图所示 从A点开始 顺时针绘制path路径.
*/
public void leftPath(RectF rect, Path path) {
path.moveTo(mCornerRadius + mArrowWidth, rect.top);//移动到A点
path.lineTo(rect.width(), rect.top);//顶部横线
path.arcTo(new RectF(rect.right - mCornerRadius * 2, rect.top, rect.right,
mCornerRadius * 2 + rect.top), 270, 90);//绘制 右上角的90度的圆弧. (B对应的区域)
path.lineTo(rect.right, rect.top);//绘制 右侧直线
path.arcTo(new RectF(rect.right - mCornerRadius * 2, rect.bottom - mCornerRadius * 2,
rect.right, rect.bottom), 0, 90);//右下角圆弧
path.lineTo(rect.left + mArrowWidth, rect.bottom);//底部横线 (D对应的横线)
path.arcTo(new RectF(rect.left + mArrowWidth, rect.bottom - mCornerRadius * 2,
mCornerRadius * 2 + rect.left + mArrowWidth, rect.bottom), 90, 90);//左下角圆弧
path.lineTo(rect.left + mArrowWidth, mArrowTop + mArrowHeight);//左侧偏下部竖线(E所示竖线)
path.lineTo(rect.left, mArrowTop - mArrowOffset);//左侧凸起尖角 下半部分斜线
path.lineTo(rect.left + mArrowWidth, mArrowTop); //左侧凸起尖角 上半部分斜线
path.lineTo(rect.left + mArrowWidth, rect.top);//左侧片上部竖线(F所示竖线)
path.arcTo(new RectF(rect.left + mArrowWidth, rect.top, mCornerRadius * 2
+ rect.left + mArrowWidth, mCornerRadius * 2 + rect.top), 180, 90);//左上角圆弧
path.close();
}
/**
* 绘制 尖角在右侧 的path
* @param rect
* @param path
*/
public void rightPath(RectF rect, Path path) {
path.moveTo(mCornerRadius, rect.top);
path.lineTo(rect.width(), rect.top);
path.arcTo(new RectF(rect.right - mCornerRadius * 2 - mArrowWidth, rect.top,
rect.right - mArrowWidth, mCornerRadius * 2 + rect.top), 270, 90);
path.lineTo(rect.right - mArrowWidth, mArrowTop);
path.lineTo(rect.right, mArrowTop - mArrowOffset);
path.lineTo(rect.right - mArrowWidth, mArrowTop + mArrowHeight);
path.lineTo(rect.right - mArrowWidth, rect.height() - mCornerRadius);
path.arcTo(new RectF(rect.right - mCornerRadius * 2 - mArrowWidth, rect.bottom
- mCornerRadius * 2, rect.right - mArrowWidth, rect.bottom), 0, 90);
path.lineTo(rect.left, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mCornerRadius * 2, mCornerRadius * 2
+ rect.left, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top);
path.arcTo(new RectF(rect.left, rect.top, mCornerRadius * 2 + rect.left,
mCornerRadius * 2 + rect.top), 180, 90);
path.close();
}
public float getmCornerRadius() {
return mCornerRadius;
}
public void setmCornerRadius(float mCornerRadius) {
this.mCornerRadius = mCornerRadius;
}
public float getmArrowTop() {
return mArrowTop;
}
public void setmArrowTop(float mArrowTop) {
this.mArrowTop = mArrowTop;
}
public float getmArrowWidth() {
return mArrowWidth;
}
public void setmArrowWidth(float mArrowWidth) {
this.mArrowWidth = mArrowWidth;
}
public float getmArrowHeight() {
return mArrowHeight;
}
public void setmArrowHeight(float mArrowHeight) {
this.mArrowHeight = mArrowHeight;
}
public float getmArrowOffset() {
return mArrowOffset;
}
public void setmArrowOffset(float mArrowOffset) {
this.mArrowOffset = mArrowOffset;
}
public int getmArrowLocation() {
return mArrowLocation;
}
public void setmArrowLocation(int mArrowLocation) {
this.mArrowLocation = mArrowLocation;
}
}
res->values->style.xml中 定义ArrowSimpleDraweeView 自定义属性
布局文件中声明 ArrowSimpleDraweeView
利用ArrowSimpleDraweeView加载尖嘴图片
vh.leftImage.showImage(uri,imageSuitableWidth,imageSuitableHeight);
最终实现效果:
github地址:
https://github.com/feifei-123/ArrowSimpleDraweeView-master