实现仿照微信聊天气泡里显示图片效果的自定义View

第一部分是自定义的气泡效果的View,代码如下

public class BitmapShapeView extends View {
    private Paint mPaint;
    private Path mPath;//包裹图片的那个不规则气泡给需要自己用Path实现
    private BitmapShader mBitmapShader;//填充起泡的渲染器
    private Bitmap mBitmap;

    private int mDefaultMinWidth = Constant.CHAT_MSG_IMG_DEFAULT_MIN_WIDTH;
    private int mDefaultMinHeight = Constant.CHAT_MSG_IMG_DEFAULT_MIN_HEIGHT;
    private int mBubbleRadius = 16;
    private int mTriangleSize = 16;
    private int mDirection = 2;

    public BitmapShapeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mBitmap = BitmapUtils.resetBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.logo_gray), mDefaultMinWidth, mDefaultMinHeight);
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        mPaint = new Paint();
        mPath = new Path();

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BubbleImageView);
        mBubbleRadius = array.getDimensionPixelSize(R.styleable.BubbleImageView_bubbleRadius, 16);
        mTriangleSize = array.getDimensionPixelSize(R.styleable.BubbleImageView_bubbleTriangleSize, 16);
        mDirection = array.getInt(R.styleable.BubbleImageView_bubbleDirection, 2);
        mDefaultMinWidth = array.getDimensionPixelSize(R.styleable.BubbleImageView_bubbleDefaultMinWidth, Constant.CHAT_MSG_IMG_DEFAULT_MIN_WIDTH);
        mDefaultMinHeight = array.getDimensionPixelSize(R.styleable.BubbleImageView_bubbleDefaultMinHeight, Constant.CHAT_MSG_IMG_DEFAULT_MIN_HEIGHT);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setShader(mBitmapShader);
        canvas.drawPath(mPath, mPaint);

        mPaint.reset();
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mBitmap != null) {
            setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
            mPath.reset();
            int width = getMeasuredWidth();
            int height = getMeasuredHeight();
            //画三角
            if (mDirection == 1) {//左三角
                mPath.moveTo(mTriangleSize, height / 3 + mTriangleSize / 2);
                mPath.lineTo(0, height / 3);
                mPath.lineTo(mTriangleSize, height / 3 - mTriangleSize / 2);
                mPath.arcTo(new RectF(mTriangleSize, 0, mTriangleSize + mBubbleRadius * 2, mBubbleRadius * 2), 180, 90);//起始位置的角度值,旋转的角度值
                mPath.lineTo(width - mBubbleRadius, 0);
                mPath.arcTo(new RectF(width - mBubbleRadius * 2, 0, width, mBubbleRadius * 2), -90, 90);
                mPath.lineTo(width, height - mBubbleRadius);
                mPath.arcTo(new RectF(width - 2 * mBubbleRadius, height - mBubbleRadius * 2, width, height), 0, 90);
                mPath.lineTo(mTriangleSize + mBubbleRadius, height);
                mPath.arcTo(new RectF(mTriangleSize, height - mBubbleRadius * 2, mTriangleSize + mBubbleRadius * 2, height), 90, 90);
                mPath.close();
            } else if (mDirection == 2) {//右三角
                mPath.moveTo(0, mBubbleRadius);
                mPath.arcTo(new RectF(0, 0, mBubbleRadius * 2, mBubbleRadius * 2), 180, 90);//起始位置的角度值,旋转的角度值
                mPath.lineTo(width - mBubbleRadius + mTriangleSize, 0);
                mPath.arcTo(new RectF(width - mBubbleRadius * 2 - mTriangleSize, 0, width - mTriangleSize, mBubbleRadius * 2), -90, 90);
                mPath.lineTo(width - mTriangleSize, height / 3 - mTriangleSize / 2);
                mPath.lineTo(width, height / 3);
//                mPath.lineTo(width-1,height/3-1);
//                mPath.arcTo(new RectF(width-4,height/3-4, width, height/3+4), -90, 180);
                mPath.lineTo(width - mTriangleSize, height / 3 + mTriangleSize / 2);
                mPath.lineTo(width - mTriangleSize, height - mBubbleRadius);
                mPath.arcTo(new RectF(width - 2 * mBubbleRadius - mTriangleSize, height - mBubbleRadius * 2, width - mTriangleSize, height), 0, 90);
                mPath.lineTo(mBubbleRadius, height);
                mPath.arcTo(new RectF(0, height - mBubbleRadius * 2, mBubbleRadius * 2, height), 90, 90);
                mPath.close();
            }
        }
    }

    public void setImageSrc(String path) {
        mBitmap = BitmapUtils.resetBitmap(BitmapFactory.decodeFile(path), mDefaultMinWidth, mDefaultMinHeight);
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        requestLayout();
        invalidate();
    }

    public void setImageSrc(int resId) {
        mBitmap = BitmapUtils.resetBitmap(BitmapFactory.decodeResource(getResources(), resId), mDefaultMinWidth, mDefaultMinHeight);
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        requestLayout();
        invalidate();
    }

    public void setImageBitmap(Bitmap bitmap) {
        mBitmap = BitmapUtils.resetBitmap(bitmap, mDefaultMinWidth, mDefaultMinHeight);
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        requestLayout();//一定得加上这方法,否则当加载不同的View时,View方法的onMeasure不会重新调用
        invalidate();
    }
}

第二部分是属性值部分,设置气泡的圆角,气泡三角的大小,图片显示最小的宽高值,代码如下:

 <declare-styleable name="BubbleImageView">
        <attr name="bubbleRadius" format="dimension"/>
        <attr name="bubbleTriangleSize" format="dimension"/>
        <attr name="bubbleDirection" format="integer"/>
        <attr name="bubbleDefaultMinWidth" format="dimension"/>
        <attr name="bubbleDefaultMinHeight" format="dimension"/>
    </declare-styleable>

最后只要在你的layout文件里使用这自定义的View就能显示气泡图片了。初次写,代码不完善的地方希望同学们能不吝赐教啊,O(∩_∩)O

转载于:https://my.oschina.net/u/2607809/blog/599736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值