zoukankan      html  css  js  c++  java
  • android绘制圆形图片的两种方式

    看下效果先

    下面有完整的示例代码

    使用BitmapShader(着色器)

    我们在绘制view 的时候 就是小学上美术课 用水彩笔在本子上画画 使用着色器绘制圆形图片最简单的理解方式 就是把bitmap当做一种颜色 设置给paint ,paint都已经有颜色了 你想让它方了,圆了,扁了 还不是看你心情 canvas调用那个方法咯

    实现的大致思路如下:
    1. 创建一个类 继承imageView 重写onDraw()
    2. 获取到bitmap图片
    3. 计算图片的缩放比例 使用矩阵matrix 进行缩放
    4. 创建BitmapShader着色器 设置缩放矩阵
    5. paint设置着色器 绘制

    具体实现 注释也标注的很清楚

       private void shaderCircle(Canvas canvas){
            //获取Drawable
            Drawable resources=getDrawable();
            float scale = 1.0f;//缩放比例
            int mRadius=0;//圆的半径
            if (resources instanceof BitmapDrawable){
                //获取bitmap
                Bitmap bitmap=((BitmapDrawable) resources).getBitmap();
                if (bitmap==null) return;
                // 获取bitmap宽高中的小值
                int minBitMap = Math.min(bitmap.getWidth(), bitmap.getHeight());
                //取view宽高中的小值 尽量保证图片内容的显示
                int minValue=Math.min(getWidth(),getHeight());
                //设置半径
                mRadius=minValue/2;
                //计算缩放比例  一定要*1.0f 因为int之间的计算结果会四舍五入0或1 效果就不美丽了
                scale=minValue*1.0f/minBitMap;
                //设置缩放比例
                matrix.setScale(scale,scale);
                /**
                 * 创建着色器 设置着色模式
                 * TileMode的取值有三种:
                 *  CLAMP 拉伸  REPEAT 重复   MIRROR 镜像
                 */
                BitmapShader shader=new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                //设置矩阵
                shader.setLocalMatrix(matrix);
                paint.setShader(shader);
                canvas.drawCircle(mRadius, mRadius, mRadius, paint);
            }
        }
    

    使用Xfermode 设置图片相交模式

    简单说呢 在一张画布上画了两张图片 这两张图的以怎样的方式显示出来 例如:只显示上层图片,只显示下层图片 ,显示两张图的交集部分 等等等

    实现思路

    1. 创建一个空bitmap 根据这个bitmap创建一个Canvas
    2. 设置Canvas透明 画一个想要实现的形状
    3. 设置图形相交模式
    4. 获取图片资源 绘制到Canvas

    实现代码

     private Bitmap getCircleBitmap(){
            Drawable drawable=getDrawable();
    
            if (drawable instanceof BitmapDrawable) {
                Paint paint=new Paint();
                paint.setAntiAlias(true);
                //获取资源图片
                Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
                //创建空位图
                Bitmap output=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
                //创建画板
                Canvas canvas=new Canvas(output);
                //绘制整个画板为透明
                canvas.drawColor(Color.TRANSPARENT);
                paint.setColor(Color.WHITE);
                //绘制圆角图片
                if (type==ROUND){
                    canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), mRound, mRound,paint);
                }else{
    				//绘制圆形图片
    			
                    //取view宽高中的小值 尽量保证图片内容的显示
                    int minValue = Math.min(getWidth(), getHeight());
                    //设置半径
                    mRadius = minValue / 2;
                    canvas.drawCircle(mRadius,mRadius,mRadius,paint);
                }
                //设置图形相交模式
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    
                Rect src=new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
                Rect dst=new Rect(0,0,output.getWidth(),output.getHeight());
                canvas.drawBitmap(bitmap,src,dst,paint);
                return output;
            }
            return null;
    
        }
    

    这个特别经典的图......

    PorterDuff.Mode.CLEAR 清除画布上图像
    PorterDuff.Mode.SRC 显示上层图像
    PorterDuff.Mode.DST 显示下层图像
    PorterDuff.Mode.SRC_OVER上下层图像都显示,上层居上显示
    PorterDuff.Mode.DST_OVER 上下层都显示,下层居上显示
    PorterDuff.Mode.SRC_IN 取两层图像交集部分只显示上层图像
    PorterDuff.Mode.DST_IN 取两层图像交集部分,只显示下层图像
    PorterDuff.Mode.SRC_OUT 取上层图像非交集部分
    PorterDuff.Mode.DST_OUT 取下层图像非交集部分
    PorterDuff.Mode.SRC_ATOP 取下层图像非交集部分与上层图像交集部分
    PorterDuff.Mode.DST_ATOP 取上层图像非交集部分与下层图像交集部分
    PorterDuff.Mode.XOR 取两层图像的非交集部分
    

    参考文档

    讲Shader类非常非常屌的帖子
    详解Paint的setXfermode

    继承ImageVIew完成圆形和圆角图片控件的实现过程(使用着色器)

        <declare-styleable name="CircleImage">
            <attr name="imageRound" format="dimension"/>
            <attr name="imageType">
                <enum name="circle" value="0"/>
                <enum name="round" value="1"/>
            </attr>
    
        </declare-styleable>
    
    public class CircleImage extends ImageView {
    
        private Matrix matrix;
        private Paint paint;
        private int mRound;//圆角度数
        private int mRadius;//圆的半径
        private int type;//控件类型
        private final int CIRCLE=0;//圆形
        private final int ROUND=1;//圆角
    
        public CircleImage(Context context) {
            super(context,null);
        }
    
        public CircleImage(Context context, AttributeSet attrs) {
            super(context, attrs);
            matrix=new Matrix();
            paint=new Paint();
            paint.setAntiAlias(true);
            initAttrValues(context,attrs);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (getDrawable() == null) {
                return;
            }
            setShader();
            if (type==CIRCLE){
                canvas.drawCircle(mRadius, mRadius, mRadius, paint);
            }else{
                canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), mRound, mRound,paint);
            }
        }
    
        /**
         * 初始化属性集合
         * @param context
         * @param attrs
         */
        private void initAttrValues(Context context, AttributeSet attrs){
            TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CircleImage);
            for (int i=0;i<typedArray.getIndexCount();i++){
                int index=typedArray.getIndex(i);
                switch (index){
                    case R.styleable.CircleImage_imageRound:
                        mRound =typedArray.getDimensionPixelSize(index,
                                (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getResources().getDisplayMetrics()));
                        break;
                    case R.styleable.CircleImage_imageType:
                        type=typedArray.getInt(index,CIRCLE);
                        break;
                }
            }
        }
    
        /**
         * 设置着色器
         */
        private void setShader() {
            //获取Drawable
            Drawable resources=getDrawable();
            float scale = 1.0f;//缩放比例
            if (resources instanceof BitmapDrawable) {
                //获取bitmap
                Bitmap bitmap = ((BitmapDrawable) resources).getBitmap();
                if (bitmap == null) return;
                //圆形
                if (type==CIRCLE){
                    // 获取bitmap宽高中的小值
                    int minBitMap = Math.min(bitmap.getWidth(), bitmap.getHeight());
                    //取view宽高中的小值 尽量保证图片内容的显示
                    int minValue = Math.min(getWidth(), getHeight());
                    //设置半径
                    mRadius = minValue / 2;
                    //计算缩放比例  一定要*1.0f 因为int之间的计算结果会四舍五入0或1 效果就不美丽了
                    scale = minValue * 1.0f / minBitMap;
                }else{
                    //比较view和图片宽高比例大的 要让缩放后的图片大于view
                    scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()
                            * 1.0f / bitmap.getHeight());
                }
                //设置缩放比例
                matrix.setScale(scale, scale);
                /**
                 * 创建着色器 设置着色模式
                 * TileMode的取值有三种:
                 *  CLAMP 拉伸  REPEAT 重复   MIRROR 镜像
                 */
                BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                //设置矩阵
                shader.setLocalMatrix(matrix);
                //设置着色
                paint.setShader(shader);
            }
        }
    
    
        /**
         * 测试转换效果 没什么卵用 可以删除
         * @param event
         * @return
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction()==MotionEvent.ACTION_DOWN){
                if (type==CIRCLE){
                    mRound =10;
                    type=ROUND;
                }else{
                    type=CIRCLE;
                }
                invalidate();
            }
            return super.onTouchEvent(event);
        }
    }
    
    
  • 相关阅读:
    记录一次Jmeter性能测试
    【转】解疑性能测试之集合点
    WebService的发布及客户端的调用
    Jmeter性能测试之如何写Java请求测试用例类
    Vue nextTick用法
    Geolocation 地理定位
    Vue 生命周期及运用场景
    CSS3 动画基本使用
    Electron菜单
    Electron + vue 项目安装vue-devtools调试工具
  • 原文地址:https://www.cnblogs.com/r-decade/p/6250450.html
Copyright © 2011-2022 走看看