关闭

Android把图片做成圆形的

标签: android图片
350人阅读 评论(0) 收藏 举报

如果图片质量要求不高 图片比较多的话 可以把  ARGB_8888改成 ARGB_4444

避免内存溢出





第一个是原图,第二个是圆形效果,第三第四设置了不同的圆角大小。 
准备改变一个博客的风格,首先给大家讲一下原理,让大家明白了,然后再贴代码,不然可以直接看那么长的代码也比较痛苦,核心代码其实就那么几行: 
核心代码分析: 

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
   
     * 根据原图和变长绘制圆形图片
   
     
   
     * @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); 
   
        /**
   
         * 首先绘制圆形
   
         */
   
        canvas.drawCircle(min / 2, min / 2, min / 2, paint); 
   
        /**
   
         * 使用SRC_IN
   
         */
   
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
   
        /**
   
         * 绘制图片
   
         */
   
        canvas.drawBitmap(source, 00, paint); 
   
        return target; 
   
    }

其实主要靠:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));这行代码,为什么呢,我给大家解释下,SRC_IN这种模式,两个绘制的效果叠加后取交集展现后图,怎么说呢,咱们第一个绘制的是个圆形,第二个绘制的是个Bitmap,于是交集为圆形,展现的是BItmap,就实现了圆形图片效果。圆角,其实就是先绘制圆角矩形,是不是很简单,以后别人再说实现圆角,你就把这一行代码给他就行了。 
从Android的示例中,给大家证明一下: 
下面有一张PorterDuff.Mode的16中效果图,咱们的只是其一: 


源码咱们只关心谁先谁后绘制的: 

复制代码
1
2
3
4
5
6
7
8
9
10
11
canvas.translate(x, y); 
   
canvas.drawBitmap(mDstB, 00, paint); 
   
paint.setXfermode(sModes); 
   
canvas.drawBitmap(mSrcB, 00, paint); 
   
paint.setXfermode(null); 
   
canvas.restoreToCount(sc);


可以看出先绘制的Dst,再绘制的Src,最后的展示是SrcIn那个图:显示的区域是二者交集,展示的是Src(后者)。和咱们前面结论一致。效果16种,大家可以自由组合展示不同的效果。 

好了,原理和核心代码解释完成。下面开始写自定义View。 
1、自定义属性:
 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?> 
   
<resources
   
     
   
    <attr name="borderRadius" format="dimension" /> 
   
    <attr name="type"
   
        <enum name="circle" value="0" /> 
   
        <enum name="round" value="1" /> 
   
    </attr
   
    <attr name="src" format="reference"></attr
   
     
   
    <declare-styleable name="CustomImageView"
   
        <attr name="borderRadius" /> 
   
        <attr name="type" /> 
   
        <attr name="src" /> 
   
    </declare-styleable
   
     
   
</resources>


2、构造中获取自定义的属性:
 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
   
 * TYPE_CIRCLE / TYPE_ROUND
   
 */
   
private int type; 
   
private static final int TYPE_CIRCLE = 0
   
private static final int TYPE_ROUND = 1
   
     
   
/**
   
 * 图片
   
 */
   
private Bitmap mSrc; 
   
     
   
/**
   
 * 圆角的大小
   
 */
   
private int mRadius; 
   
     
   
/**
   
 * 控件的宽度
   
 */
   
private int mWidth; 
   
/**
   
 * 控件的高度
   
 */
   
private int mHeight; 
   
     
   
public CustomImageView(Context context, AttributeSet attrs) 
   
   
    this(context, attrs, 0); 
   
   
     
   
public CustomImageView(Context context) 
   
   
    this(context, null); 
   
   
     
   
/**
   
 * 初始化一些自定义的参数
   
 
   
 * @param context
   
 * @param attrs
   
 * @param defStyle
   
 */
   
public CustomImageView(Context context, AttributeSet attrs, int defStyle) 
   
   
    super(context, attrs, defStyle); 
   
     
   
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0); 
   
     
   
    int n = a.getIndexCount(); 
   
    for (int i = 0; i < n; i++) 
   
    
   
        int attr = a.getIndex(i); 
   
        switch (attr) 
   
        
   
        case R.styleable.CustomImageView_src: 
   
            mSrc = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0)); 
   
            break
   
        case R.styleable.CustomImageView_type: 
   
            type = a.getInt(attr, 0);// 默认为Circle 
   
            break
   
        case R.styleable.CustomImageView_borderRadius: 
   
            mRadius= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, 
   
                    getResources().getDisplayMetrics()));// 默认为10DP 
   
            break
   
        
   
    
   
    a.recycle(); 
   
}

3、onMeasure中获取控件宽高:
 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
   
     * 计算控件的高度和宽度
   
     */
   
    @Override
   
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
   
    
   
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
   
     
   
        /**
   
         * 设置宽度
   
         */
   
        int specMode = MeasureSpec.getMode(widthMeasureSpec); 
   
        int specSize = MeasureSpec.getSize(widthMeasureSpec); 
   
     
   
        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate 
   
        
   
            mWidth = specSize; 
   
        else
   
        
   
            // 由图片决定的宽 
   
            int desireByImg = getPaddingLeft() + getPaddingRight() + mSrc.getWidth(); 
   
            if (specMode == MeasureSpec.AT_MOST)// wrap_content 
   
            
   
                mWidth = Math.min(desireByImg, specSize); 
   
            
   
        
   
     
   
        /***
   
         * 设置高度
   
         */
   
     
   
        specMode = MeasureSpec.getMode(heightMeasureSpec); 
   
        specSize = MeasureSpec.getSize(heightMeasureSpec); 
   
        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate 
   
        
   
            mHeight = specSize; 
   
        else
   
        
   
            int desire = getPaddingTop() + getPaddingBottom() + mSrc.getHeight(); 
   
            if (specMode == MeasureSpec.AT_MOST)// wrap_content 
   
            
   
                mHeight = Math.min(desire, specSize); 
   
            
   
        
   
        setMeasuredDimension(mWidth, mHeight); 
   
     
   
    }
4、根据Type绘制: 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
   
     * 绘制
   
     */
   
    @Override
   
    protected void onDraw(Canvas canvas) 
   
    
   
     
   
        switch (type) 
   
        
   
        // 如果是TYPE_CIRCLE绘制圆形 
   
        case TYPE_CIRCLE: 
   
     
   
            int min = Math.min(mWidth, mHeight); 
   
            /**
   
             * 长度如果不一致,按小的值进行压缩
   
             */
   
            mSrc = Bitmap.createScaledBitmap(mSrc, min, min, false); 
   
     
   
            canvas.drawBitmap(createCircleImage(mSrc, min), 00null); 
   
            break
   
        case TYPE_ROUND: 
   
            canvas.drawBitmap(createRoundConerImage(mSrc), 00null); 
   
            break
   
     
   
        
   
     
   
    
   
     
   
    /**
   
     * 根据原图和变长绘制圆形图片
   
     
   
     * @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); 
   
        /**
   
         * 首先绘制圆形
   
         */
   
        canvas.drawCircle(min / 2, min / 2, min / 2, paint); 
   
        /**
   
         * 使用SRC_IN,参考上面的说明
   
         */
   
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
   
        /**
   
         * 绘制图片
   
         */
   
        canvas.drawBitmap(source, 00, paint); 
   
        return target; 
   
    
   
     
   
    /**
   
     * 根据原图添加圆角
   
     
   
     * @param source
   
     * @return
   
     */
   
    private Bitmap createRoundConerImage(Bitmap source) 
   
    
   
        final Paint paint = new Paint(); 
   
        paint.setAntiAlias(true); 
   
        Bitmap target = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888); 
   
        Canvas canvas = new Canvas(target); 
   
        RectF rect =