自定义View实现CircleImageView(圆形)、圆角、旗帜、爱心等等ImageView效果

版权声明:本文是博主原创文章,不得转载本文任何内容。原文地址: https://blog.csdn.net/smile_Running/article/details/81872881

                         【声明】:未经许可,禁止转载!

· 介绍

    今天,我们继续上篇的自定义之ImageView篇来实现CircleImageView(圆形效果)LoveImageView(爱心效果)FlagImageView(动态旗帜效果)RoundRectImageView(圆角矩形效果)等等效果的ImageView控件。

既然,我们代码是沿用上篇的自定义View之从零打造一个简单的图片显示控件 —— SimpleImageView,所以在此篇文章中,我们不再去介绍实现ImageView的步骤了。以下,我默认您已经实现了上篇文章所简述的代码。好了,我们先来看一波实现的效果图。

实现效果的对比图:

自定义ImageView的通用代码:

/**
 * @Created by xww.
 * @Creation time 2018/8/8.
 */

public class CircleImageView extends View {

    private Paint mPaint;
    private Drawable mDrawable;
    private BitmapShader mBitmapShader;
    private int mWidth;
    private int mHeight;

    @SuppressLint("Recycle")
    private void initAttrs(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray array = null;
            try {
                array = getContext().obtainStyledAttributes(attrs, R.styleable.RectangleImageView);
                mDrawable = array.getDrawable(R.styleable.RectangleImageView_src);
                if (mDrawable == null) {
                    throw new NullPointerException("drawable is not null");
                }
                mWidth = mDrawable.getIntrinsicWidth();
                mHeight = mDrawable.getIntrinsicHeight();
            } finally {
                if (array != null) {
                    array.recycle();
                }
            }
        }
    }

    public CircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        initAttrs(attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(mWidth, mHeight);
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDrawable == null) {
            return;
        }
        final int width = canvas.getWidth();
        final int height = canvas.getHeight();

        /**
         * 绘制圆形图片
         */
        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        canvas.drawCircle(width / 2, height / 2, width / 2, mPaint);
    }

    private int measureWidth(int widthMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        switch (widthMode) {
            case MeasureSpec.UNSPECIFIED: 
            case MeasureSpec.AT_MOST: 
                break;
            case MeasureSpec.EXACTLY: 
                mWidth = widthSize;
                break;
        }
        return mWidth;
    }

    private int measureHeight(int heightMeasureSpec) {
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        switch (heightMode) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                break;
            case MeasureSpec.EXACTLY:
                mHeight = heightSize;
                break;
        }
        return mHeight;
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, config);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, mWidth, mHeight);
        drawable.draw(canvas);
        return bitmap;
    }
}

一、圆形ImageView效果

关键代码:

  利用canvas绘制圆形的效果。

        /**
         * 绘制圆形图片
         */
        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        canvas.drawCircle(width / 2, height / 2, width / 2, mPaint);

二、圆角矩形ImageView效果

关键代码:

  将本段代码替换圆形图片的注释部分的代码即可。

        /**
         * 绘制圆角矩形图片
         */
        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        canvas.drawRoundRect(0, 0, width, height, 50, 50, mPaint);

三、椭圆形ImageView效果

关键代码:

  将本段代码替换圆形图片的注释部分的代码即可。

        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        canvas.drawOval(0, 0, width-50, height-200, mPaint);

四、三角形ImageView效果

关键代码:

  简单介绍一下,利用路径来绘制一个三角形,将本段代码替换圆形图片的注释部分的代码即可。

        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        Path path = new Path();
        path.moveTo(width / 2, 0);
        path.lineTo(width, height);
        path.lineTo(0, height);
        path.close();
        canvas.drawPath(path, mPaint);

五、爱心形ImageView效果

关键代码:

  将本段代码替换圆形图片的注释部分的代码即可。

        /**
         * 调用drawLove()方法
         */
        mBitmapShader = new BitmapShader(drawableToBitmap(mDrawable), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint.setShader(mBitmapShader);
        drawLove(canvas);


    private void drawLove(Canvas canvas) {
        //(17*(x^2))-(16*abs(x)*y)+(17*(y^2))<255 x(-5,5) y(-5,5) (心形函数方程式)

        int loveWidth = 500;//心型宽度,必须是偶数
        int oneLine = loveWidth / 2;//一条轴长度
        float scale = oneLine / 5f;//实际坐标比上方程式坐标,倍数

        for (int i = 0; i < oneLine; i++) {
            for (int j = 0; j < oneLine; j++) {
                //根据表达式xy的范围,所以要把坐标系的范围也缩小
                float xf = i / scale;
                float yf = j / scale;

                if ((17 * Math.pow(xf, 2) - 16 * Math.abs(xf) * yf + 17 * Math.pow(yf, 2)) < 255) {
                    canvas.drawPoint(250 - xf * scale, 250 - yf * scale, mPaint);
                    canvas.drawPoint(250 + xf * scale, 250 - yf * scale, mPaint);
                }

                if ((17 * Math.pow(xf, 2) - 16 * Math.abs(xf) * (-yf) + 17 * Math.pow(yf, 2)) < 255) {
                    canvas.drawPoint(250 - xf * scale, 250 + yf * scale, mPaint);
                    canvas.drawPoint(250 + xf * scale, 250 + yf * scale, mPaint);
                }
            }
        }
    }

五、动态旗帜ImageView效果

关键代码:

将本类所有代码,替换之前的代码即可。

/**
 * 旗帜飘扬的动态效果
 *
 * @Created by xww.
 * @Creation time 2018/8/8.
 */
public class FlagImageView extends View {

    //将图像分成多少格
    private int WIDTH = 200;
    private int HEIGHT = 200;
    //交点坐标的个数
    private int COUNT = (WIDTH + 1) * (HEIGHT + 1);
    //用于保存COUNT的坐标
    //x0, y0, x1, y1......
    private float[] verts = new float[COUNT * 2];
    //用于保存原始的坐标
    private float[] orig = new float[COUNT * 2];
    private Bitmap mBitmap;
    private float K = 1;

    public FlagImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        int index = 0;
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_loop_ad_2);
        float bmWidth = mBitmap.getWidth();
        float bmHeight = mBitmap.getHeight();

        for (int i = 0; i < HEIGHT + 1; i++) {
            float fy = bmHeight * i / HEIGHT;
            for (int j = 0; j < WIDTH + 1; j++) {
                float fx = bmWidth * j / WIDTH;
                //X轴坐标 放在偶数位
                verts[index * 2 + 0] = fx;
                orig[index * 2 + 0] = verts[index * 2 + 0];
                //Y轴坐标 放在奇数位
                //向下移动200
                verts[index * 2 + 1] = fy + 200;
                orig[index * 2 + 1] = verts[index * 2 + 1];
                index += 1;
            }
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < HEIGHT + 1; i++) {
            for (int j = 0; j < WIDTH + 1; j++) {
                verts[(i * (WIDTH + 1) + j) * 2 + 0] += 0;
                //利用正弦函数的周期性
                float offsetY = (float) Math.sin((float) j / WIDTH * 2 * Math.PI + K * 2 * Math.PI);
                verts[(i * (WIDTH + 1) + j) * 2 + 1] = orig[(i * (WIDTH + 1) + j) * 2 + 1] + offsetY * 50;
            }
        }
        //平移 旗帜飘扬效果
        K += 0.1F;
        canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, verts, 0, null, 0, null);
        invalidate();
    }
}

当然,如果你觉得效果还不够丰富,可以自己利用画布绘制更多的形状效果。

©版权所有:https://blog.csdn.net/smile_Running/article/details/81872881

猜你喜欢

转载自blog.csdn.net/smile_Running/article/details/81872881