Android自定义图片集合

时间:2022-04-11 05:55:59

本文主要包括以下内容:

  • 使用xfermode设置圆角图片
  • 使用bitmapshader设置圆角图片
  • 滑动旋转缩放的bimp图片
  • 图片颜色处理(滑动)
  • 图片 + 文字

其中1,2是两种不同方式处理图片圆角的情况。3,是通过matrix进行图片缩放,旋转等。4,是通过matrix操作图片的处理,包括去饱和,四角黑影,中心突出等。5,图片加文字组合显示。
如果暂时感觉这些看不懂:
先看看这两篇:

android自定义控件深入学习 android生成随机验证码

详解android自定义控件属性typedarray以及attrs

1、使用xfermode设置圆角图片
主要代码

?
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package com.example.customimage.view;
 
import com.example.customimage.r;
 
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmap.config;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.porterduff;
import android.graphics.porterduffxfermode;
import android.graphics.rectf;
import android.util.attributeset;
import android.util.log;
import android.util.typedvalue;
import android.view.view;
 
 
/**
 * 自定义view,实现圆角,圆形等效果
 */
public class xfermodeimageview extends view
{
 //类型
 private int type;
 private static final int type_circle = 0; //圆形
 private static final int type_rect = 1; //矩形圆角
 
 //原始图片
 private bitmap msrc;
 
 //矩形圆角的幅度
 private int mradius;
 
 //控件的宽度
 private int mwidth;
 
 // 控件的高度
 private int mheight;
 
 public xfermodeimageview(context context, attributeset attrs)
 {
 this(context, attrs, 0);
 }
 
 public xfermodeimageview(context context)
 {
 this(context, null);
 }
 
 /**
 * 初始化一些自定义的参数
 *
 * @param context
 * @param attrs
 * @param defstyle
 */
 public xfermodeimageview(context context, attributeset attrs, int defstyle)
 {
 super(context, attrs, defstyle);
 
 typedarray a = context.gettheme().obtainstyledattributes(attrs,
  r.styleable.xfermodeimageview, defstyle, 0);
 
 int n = a.getindexcount();
 for (int i = 0; i < n; i++)
 {
  int attr = a.getindex(i);
  switch (attr)
  {
  //原始图片,在布局里面获取
  case r.styleable.xfermodeimageview_src:
  msrc = bitmapfactory.decoderesource(getresources(),
   a.getresourceid(attr, 0));
  break;
  //类型属性选择
  case r.styleable.xfermodeimageview_type:
  //自定义类型属性,0是圆形,1是矩形圆角
  type = a.getint(attr, 0);// 默认为circle
  break;
  //矩形圆角幅度的获取,默认是10dp
  case r.styleable.xfermodeimageview_borderradius:
  mradius = a.getdimensionpixelsize(attr, (int) typedvalue
   .applydimension(typedvalue.complex_unit_dip, 10f,
    getresources().getdisplaymetrics()));
  log.i("show", string.valueof(mradius));
  break;
  }
 }
 a.recycle();
 }
 
 /**
 * 计算控件的高度和宽度
 */
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec)
 {
 // 设置宽度
 int specmode = measurespec.getmode(widthmeasurespec);
 int specsize = measurespec.getsize(widthmeasurespec);
 
 //match_parent或者设置的精确值获取
 //measurespec.exactly
 if (specmode == measurespec.exactly)
 {
  mwidth = specsize;
 }
 else
 {
  // 由图片决定的宽
  //getpaddingleft(),getpaddingright()这两个值是控件属性的向内偏移的距离值,所以的一起计算
  //区别于layout_marginleft,两个控件的左间距值设置
  int desirebyimg = getpaddingleft() + getpaddingright()
   + msrc.getwidth();
  
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  //所以最小的值,宽度的话是左右内偏移距离之和
  mwidth = math.min(desirebyimg, specsize);
  } else
 
  mwidth = desirebyimg;
 }
 
 // 设置高度,部分解释同上
 specmode = measurespec.getmode(heightmeasurespec);
 specsize = measurespec.getsize(heightmeasurespec);
  
 //match_parent或者设置的精确值获取
 //measurespec.exactly
 if (specmode == measurespec.exactly)
 {
  mheight = specsize;
 } else
 {
  int desire = getpaddingtop() + getpaddingbottom()
   + msrc.getheight();
 
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  mheight = math.min(desire, specsize);
  } else
  mheight = desire;
 }
 
 //计算好的宽度以及高度是值,设置进去
 setmeasureddimension(mwidth, mheight);
 }
 
 /**
 * 绘制image控件
 */
 @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), 0, 0, null);
  break;
 case type_rect:
  canvas.drawbitmap(createroundconerimage(msrc), 0, 0, null);
  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);
 // 首先绘制圆形,除以2就是半径了
 //最主要设置第三个参数为min/2,圆角幅度那么大就是圆形了
 canvas.drawcircle(min / 2, min / 2, min/2, paint);
 // 使用src_in,参考上面的说明---上下层都显示。下层居上显示
 paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));
 // 绘制图片
 canvas.drawbitmap(source, 0, 0, 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 = new rectf(0, 0, source.getwidth(), source.getheight());
 //设置圆角幅度
 canvas.drawroundrect(rect, mradius, mradius, paint);
 // 使用src_in,参考上面的说明---上下层都显示。下层居上显示
 paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));
 canvas.drawbitmap(source, 0, 0, paint);
 return target;
 }
}

2、使用bitmapshader设置圆角图片

?
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package com.example.customimage.view;
 
import com.example.customimage.r;
 
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapshader;
import android.graphics.canvas;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.rectf;
import android.graphics.shader.tilemode;
import android.graphics.drawable.bitmapdrawable;
import android.graphics.drawable.drawable;
import android.os.bundle;
import android.os.parcelable;
import android.util.attributeset;
import android.util.log;
import android.util.typedvalue;
import android.widget.imageview;
 
/**
 *
 */
public class bitmapshaderimageview extends imageview
{
 // 图片的类型,圆形or圆角
 private int type;
 public static final int type_circle = 0;
 public static final int type_rect = 1;
 //圆角大小的默认值
 private static final int boder_radius_default = 10;
 //圆角的大小
 private int mborderradius;
 
 // 绘图的paint
 private paint mbitmappaint;
 //圆角的半径
 private int mradius;
 // 3x3 矩阵,主要用于缩小放大
 private matrix mmatrix;
 // 渲染图像,使用图像为绘制图形着色
 private bitmapshader mbitmapshader;
 // view的宽度
 private int mwidth;
 //矩形
 private rectf mroundrect;
 
 public bitmapshaderimageview(context context)
 {
 this(context, null);
 }
 
 public bitmapshaderimageview(context context, attributeset attrs)
 {
 super(context, attrs);
 mmatrix = new matrix();
 mbitmappaint = new paint();
 mbitmappaint.setantialias(true);
 
 typedarray a = context.obtainstyledattributes(attrs,
  r.styleable.bitmapshaderimageview);
 //矩形圆角幅度的获取,默认是10dp
 mborderradius = a.getdimensionpixelsize(
  r.styleable.bitmapshaderimageview_borderradius, (int) typedvalue
   .applydimension(typedvalue.complex_unit_dip,
    boder_radius_default, getresources()
     .getdisplaymetrics()));
 //自定义类型属性,0是圆形,1是矩形圆角
 type = a.getint(r.styleable.bitmapshaderimageview_type, type_circle);
 
 a.recycle();
 }
 
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec)
 {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 
 // 如果类型是圆形,则强制改变view的宽高一致,以小值为准
 if (type == type_circle)
 {
  mwidth = math.min(getmeasuredwidth(), getmeasuredheight());
  //圆形的半径
  mradius = mwidth / 2;
  setmeasureddimension(mwidth, mwidth);
 }
 
 }
 
 // 初始化bitmapshader,获取到图片资源
 // 等待画布的准备好,然后在画布上加上paint就是了
 //就是说图片的载体是paint
 private void setupshader()
 {
 drawable drawable = getdrawable();
 if (drawable == null)
 {
  return;
 }
 
 bitmap bmp = drawabletobitamp(drawable);
 // 将bmp作为着色器,就是在指定区域内绘制bmp
 //tilemode.clamp 拉伸
 mbitmapshader = new bitmapshader(bmp, tilemode.clamp, tilemode.clamp);
 float scale = 1.0f;
 if (type == type_circle)
 {
  // 拿到bitmap宽或高的小值
  int bsize = math.min(bmp.getwidth(), bmp.getheight());
  scale = mwidth * 1.0f / bsize;
 
 } else if (type == type_rect)
 {
  if (!(bmp.getwidth() == getwidth() && bmp.getheight() == getheight()))
  {
  // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;
  scale = math.max(getwidth() * 1.0f / bmp.getwidth(),
   getheight() * 1.0f / bmp.getheight());
  }
 
 }
 // shader的变换矩阵,我们这里主要用于放大或者缩小
 // scale * scale 的矩阵
 mmatrix.setscale(scale, scale);
 // 设置变换矩阵
 mbitmapshader.setlocalmatrix(mmatrix);
 // 设置shader
 mbitmappaint.setshader(mbitmapshader);
 }
 
 @override
 protected void ondraw(canvas canvas)
 {
 if (getdrawable() == null)
 {
  return;
 }
 setupshader();
 
 if (type == type_rect)
 {
  //绘制矩形
  canvas.drawroundrect(mroundrect, mborderradius, mborderradius,
   mbitmappaint);
 } else
 {
  //绘制圆形
  canvas.drawcircle(mradius, mradius, mradius, mbitmappaint);
 }
 }
 
 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh)
 {
 super.onsizechanged(w, h, oldw, oldh);
 
 // 圆角图片的范围
 if (type == type_rect)
  mroundrect = new rectf(0, 0, w, h);
 }
 
 //drawable转bitmap
 private bitmap drawabletobitamp(drawable drawable)
 {
 //从控件的src获取背景,也是drawable文件获取
 if (drawable instanceof bitmapdrawable)
 {
  bitmapdrawable bd = (bitmapdrawable) drawable;
  return bd.getbitmap();
 }
  
 //如果没有绘图一个,只不过是空白的图片
 int w = drawable.getintrinsicwidth();
 int h = drawable.getintrinsicheight();
  
 bitmap bitmap = bitmap.createbitmap(w, h, bitmap.config.argb_8888);
 canvas canvas = new canvas(bitmap);
 drawable.setbounds(0, 0, w, h);
 drawable.draw(canvas);
 return bitmap;
 }
 
 private static final string state_instance = "state_instance";
 private static final string state_type = "state_type";
 private static final string state_border_radius = "state_border_radius";
 
 //屏幕旋转后,取出保存的值
 @override
 protected parcelable onsaveinstancestate()
 {
 bundle bundle = new bundle();
 bundle.putparcelable(state_instance, super.onsaveinstancestate());
 bundle.putint(state_type, type);
 bundle.putint(state_border_radius, mborderradius);
 return bundle;
 }
 
 //屏幕旋转,变量的保存,因为外面设置值,如果不保存,一旋转就变成个xml里面设置的值
 @override
 protected void onrestoreinstancestate(parcelable state)
 {
 if (state instanceof bundle)
 {
  bundle bundle = (bundle) state;
  super.onrestoreinstancestate(((bundle) state)
   .getparcelable(state_instance));
  this.type = bundle.getint(state_type);
  this.mborderradius = bundle.getint(state_border_radius);
 } else
 {
  super.onrestoreinstancestate(state);
 }
 
 }
 
 //设置矩形圆角幅度后,重新绘制控件
 public void setborderradius(int borderradius)
 {
 int pxval = dp2px(borderradius);
 if (this.mborderradius != pxval)
 {
  this.mborderradius = pxval;
  invalidate();
 }
 }
 
 //设置是圆形还是矩形圆角
 public void settype(int type)
 {
 if (this.type != type)
 {
  this.type = type;
  if (this.type != type_rect && this.type != type_circle)
  {
  this.type = type_circle;
  }
  requestlayout();
 }
 
 }
 
 //dp转px
 public int dp2px(int dpval)
 {
 return (int) typedvalue.applydimension(typedvalue.complex_unit_dip,
  dpval, getresources().getdisplaymetrics());
 }
 
}

3、滑动旋转缩放的bimp图片

?
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
package com.example.customimage.view;
 
import android.content.context;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.paintflagsdrawfilter;
import android.graphics.pointf;
import android.graphics.drawable.bitmapdrawable;
import android.graphics.drawable.drawable;
import android.util.attributeset;
import android.view.motionevent;
import android.widget.imageview;
 
public class matriximageview extends imageview {
 private static final int mode_none = 0x00123;// 默认的触摸模式
 private static final int mode_drag = 0x00321;// 拖拽模式
 private static final int mode_zoom = 0x00132;// 缩放or旋转模式
 
 private int mode;// 当前的触摸模式
 
 private float premove = 1f;// 上一次手指移动的距离
 private float saverotate = 0f;// 保存了的角度值
 private float rotate = 0f;// 旋转的角度
 
 private float[] preeventcoor;// 上一次各触摸点的坐标集合
 
 private pointf startpointf, midpointf;// 起点、中点对象
 private matrix currentmatrix, savedmatrix;// 当前和保存了的matrix对象
 
 //原始图片
 private bitmap msrc;
 
 //控件的宽度
 private int mwidth;
 
 // 控件的高度
 private int mheight;
 
 private paintflagsdrawfilter mdrawfilter;
 
 public matriximageview(context context, attributeset attrs) {
 super(context, attrs);
 
 // 初始化
 init();
 }
 
 /**
 * 初始化
 */
 private void init() {
 // 实例化对象
 
 currentmatrix = new matrix();
 savedmatrix = new matrix();
 startpointf = new pointf();
 midpointf = new pointf();
 mdrawfilter = new paintflagsdrawfilter(0, paint.anti_alias_flag|paint.filter_bitmap_flag);
 // 模式初始化
 mode = mode_none;
 
 drawable drawable = getdrawable();
 msrc = drawabletobitamp(drawable);
  
 }
 
 /**
 * 计算控件的高度和宽度
 */
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec)
 {
 // 设置宽度
 int specmode = measurespec.getmode(widthmeasurespec);
 int specsize = measurespec.getsize(widthmeasurespec);
 
 //match_parent或者设置的精确值获取
 //measurespec.exactly
 if (specmode == measurespec.exactly)
 {
  mwidth = specsize;
 }
 else
 {
  // 由图片决定的宽
  //getpaddingleft(),getpaddingright()这两个值是控件属性的向内偏移的距离值,所以的一起计算
  //区别于layout_marginleft,两个控件的左间距值设置
  int desirebyimg = getpaddingleft() + getpaddingright()
   + msrc.getwidth();
  
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  //所以最小的值,宽度的话是左右内偏移距离之和
  mwidth = math.min(desirebyimg, specsize);
  } else
 
  mwidth = desirebyimg;
 }
 
 // 设置高度,部分解释同上
 specmode = measurespec.getmode(heightmeasurespec);
 specsize = measurespec.getsize(heightmeasurespec);
  
 //match_parent或者设置的精确值获取
 //measurespec.exactly
 if (specmode == measurespec.exactly)
 {
  mheight = specsize;
 } else
 {
  int desire = getpaddingtop() + getpaddingbottom()
   + msrc.getheight();
 
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  mheight = math.min(desire, specsize);
  } else
  mheight = desire;
 }
 
 //计算好的宽度以及高度是值,设置进去
 setmeasureddimension(mwidth, mheight);
 }
 
 //drawable转bitmap
 private bitmap drawabletobitamp(drawable drawable)
 {
 //从控件的src获取背景,也是drawable文件获取
 if (drawable instanceof bitmapdrawable)
 {
  bitmapdrawable bd = (bitmapdrawable) drawable;
  return bd.getbitmap();
 }
  
 //如果没有绘图一个,只不过是空白的图片
 int w = drawable.getintrinsicwidth();
 int h = drawable.getintrinsicheight();
  
 bitmap bitmap = bitmap.createbitmap(w, h, bitmap.config.argb_8888);
 canvas canvas = new canvas(bitmap);
 drawable.setbounds(0, 0, w, h);
 drawable.draw(canvas);
 return bitmap;
 }
 
 final paint paint = new paint();
 @override
 protected void ondraw(canvas canvas) {
 //消除锯齿, 图片旋转后的锯齿消除不成功,实在不行图片边缘加一些白色像素点
 canvas.setdrawfilter(mdrawfilter);
 //画经过matrix变化后的图
 canvas.drawbitmap(msrc, currentmatrix, null);
 }
 
 @override
 public boolean ontouchevent(motionevent event) {
 switch (event.getaction() & motionevent.action_mask) {
 case motionevent.action_down:// 单点接触屏幕时
  savedmatrix.set(currentmatrix);
  startpointf.set(event.getx(), event.gety());
  //单点触摸是移动模式
  mode = mode_drag;
  preeventcoor = null;
  break;
 case motionevent.action_pointer_down:// 第二个点接触屏幕时
  premove = calspacing(event);
  if (premove > 10f) {
  savedmatrix.set(currentmatrix);
  // 计算两个触摸点的中点坐标
  calmidpoint(midpointf, event);
  //两点是旋转或者缩放模式
  mode = mode_zoom;
  }
  preeventcoor = new float[4];
  preeventcoor[0] = event.getx(0);
  preeventcoor[1] = event.getx(1);
  preeventcoor[2] = event.gety(0);
  preeventcoor[3] = event.gety(1);
  saverotate = calrotation(event);
  break;
 case motionevent.action_up:// 单点离开屏幕时
 case motionevent.action_pointer_up:// 第二个点离开屏幕时
  mode = mode_none;
  preeventcoor = null;
  break;
 case motionevent.action_move:// 触摸点移动时
  /*
  * 单点触控拖拽平移
  */
  if (mode == mode_drag) {
  currentmatrix.set(savedmatrix);
  float dx = event.getx() - startpointf.x;
  float dy = event.gety() - startpointf.y;
  currentmatrix.posttranslate(dx, dy);
  }
  /*
  * 两点触控拖放旋转
  */
  else if (mode == mode_zoom && event.getpointercount() == 2) {
  float currentmove = calspacing(event);
  currentmatrix.set(savedmatrix);
  /*
   * 指尖移动距离大于10f缩放
   */
  if (currentmove > 10f) {
   float scale = currentmove / premove;
   currentmatrix.postscale(scale, scale, midpointf.x, midpointf.y);
  }
  /*
   * 保持两点时旋转
   */
  if (preeventcoor != null) {
   rotate = calrotation(event);
   r = rotate - saverotate;
   currentmatrix.postrotate(r, getmeasuredwidth() / 2, getmeasuredheight() / 2);
  }
  }
  break;
 }
 
 setimagematrix(currentmatrix);
 return true;
 }
 
 float r;
 
 /**
 * 计算两个触摸点间的距离
 */
 private float calspacing(motionevent event) {
 float x = event.getx(0) - event.getx(1);
 float y = event.gety(0) - event.gety(1);
 return (float) math.sqrt(x * x + y * y);
 }
 
 /**
 * 计算两个触摸点的中点坐标
 */
 private void calmidpoint(pointf point, motionevent event) {
 float x = event.getx(0) + event.getx(1);
 float y = event.gety(0) + event.gety(1);
 point.set(x / 2, y / 2);
 }
 
 /**
 * 计算旋转角度
 *
 * @param 事件对象
 * @return 角度值
 */
 private float calrotation(motionevent event) {
 double deltax = (event.getx(0) - event.getx(1));
 double deltay = (event.gety(0) - event.gety(1));
 double radius = math.atan2(deltay, deltax);
 return (float) math.todegrees(radius);
 }
 
}

4、图片颜色处理(滑动)

?
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package com.example.customimage.view;
 
import com.example.customimage.r;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.colormatrixcolorfilter;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.porterduff.mode;
import android.graphics.porterduffxfermode;
import android.graphics.radialgradient;
import android.graphics.shader.tilemode;
import android.util.attributeset;
import android.view.view;
 
public class dreameffectview extends view {
 private paint mbitmappaint, mshaderpaint;// 位图画笔和shader图形的画笔
 private porterduffxfermode mxfermode;// 图形混合模式
 private int x, y;// 位图起点坐标
 //控件的宽度
 private int mwidth;
 // 控件的高度
 private int mheight;
 //原始图片
 private bitmap msrc;
 //生成暗角的图片
 private bitmap darkcornerbitmap;
 public final static int bitmap_null = 0; //原图
 private final static int bitmap_deast = 1; //去饱和
 private final static int bitmap_center = 2; //中心突出
 private final static int bitmap_darkcorner = 3; //四角黑暗
 
 private int mnselectmode = 0;
 
 public dreameffectview(context context, attributeset attrs)
 {
 this(context, attrs, 0);
 }
 
 public dreameffectview(context context)
 {
 this(context, null);
 }
 
 public dreameffectview(context context, attributeset attrs, int defstyle) {
 super(context, attrs,defstyle);
 
 typedarray a = context.gettheme().obtainstyledattributes(attrs,
  r.styleable.dreameffectview, defstyle, 0);
  
 int n = a.getindexcount();
 for (int i = 0; i < n; i++)
 {
  int attr = a.getindex(i);
  switch (attr)
  {
  //原始图片,在布局里面获取
  case r.styleable.dreameffectview_src:
  msrc = bitmapfactory.decoderesource(getresources(),
   a.getresourceid(attr, 0));
  break;
  case r.styleable.dreameffectview_mode:
  mnselectmode = a.getint(attr, 0);
  break;
  }
 }
 a.recycle();
  
 // 实例化混合模式
 mxfermode = new porterduffxfermode(mode.screen);
 
 // 初始化画笔
 initpaint();
 }
 
 /**
 * 计算控件的高度和宽度
 */
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec)
 {
 // 设置宽度
 int specmode = measurespec.getmode(widthmeasurespec);
 int specsize = measurespec.getsize(widthmeasurespec);
 
 if (specmode == measurespec.exactly)
 {
  mwidth = specsize;
 }
 else
 {
  int desirebyimg = getpaddingleft() + getpaddingright()
   + msrc.getwidth();
  
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  //所以最小的值,宽度的话是左右内偏移距离之和
  mwidth = math.min(desirebyimg, specsize);
  } else
 
  mwidth = desirebyimg;
 }
 
 // 设置高度,部分解释同上
 specmode = measurespec.getmode(heightmeasurespec);
 specsize = measurespec.getsize(heightmeasurespec);
  
 if (specmode == measurespec.exactly)
 {
  mheight = specsize;
 } else
 {
  int desire = getpaddingtop() + getpaddingbottom()
   + msrc.getheight();
 
  // wrap_content
  if (specmode == measurespec.at_most)
  {
  mheight = math.min(desire, specsize);
  } else
  mheight = desire;
 }
  
 x = mwidth / 2 - msrc.getwidth() / 2;
 y = mheight / 2 - msrc.getheight() / 2;
 
 //计算好的宽度以及高度是值,设置进去
 setmeasureddimension(mwidth, mheight);
 }
 
 /**
 * 初始化画笔
 */
 private void initpaint() {
 // 实例化画笔
 mbitmappaint = new paint(paint.anti_alias_flag);
 
 // 实例化shader图形的画笔
 mshaderpaint = new paint();
 switch (mnselectmode) {
 case bitmap_null:
  
  break;
 case bitmap_deast:
  // 去饱和、提亮、色相矫正
  mbitmappaint.setcolorfilter(new colormatrixcolorfilter(
   new float[] { 0.8587f, 0.2940f, -0.0927f, 0, 6.79f, 0.0821f, 0.9145f, 0.0634f, 0, 6.79f,
    0.2019f, 0.1097f, 0.7483f, 0, 6.79f, 0, 0, 0, 1, 0 }));
  
  break;
 case bitmap_center:
  // 去饱和、提亮、色相矫正
  mbitmappaint.setcolorfilter(new colormatrixcolorfilter(
   new float[] { 0.8587f, 0.2940f, -0.0927f, 0, 6.79f, 0.0821f, 0.9145f, 0.0634f, 0, 6.79f,
    0.2019f, 0.1097f, 0.7483f, 0, 6.79f, 0, 0, 0, 1, 0 }));
  // 设置径向渐变,渐变中心当然是图片的中心也是屏幕中心,渐变半径我们直接拿图片的高度但是要稍微小一点
  // 中心颜色为透明而边缘颜色为黑色
  mshaderpaint.setshader(new radialgradient(mwidth / 2, mwidth / 2, msrc.getheight() * 7 / 8, color.transparent,
   color.black, tilemode.clamp));
  break;
 case bitmap_darkcorner:
  // 去饱和、提亮、色相矫正
  mbitmappaint.setcolorfilter(new colormatrixcolorfilter(
   new float[] { 0.8587f, 0.2940f, -0.0927f, 0, 6.79f, 0.0821f, 0.9145f, 0.0634f, 0, 6.79f,
    0.2019f, 0.1097f, 0.7483f, 0, 6.79f, 0, 0, 0, 1, 0 }));
  // 根据我们源图的大小生成暗角bitmap
  darkcornerbitmap = bitmap.createbitmap(msrc.getwidth(), msrc.getheight(), bitmap.config.argb_8888);
 
  // 将该暗角bitmap注入canvas
  canvas canvas = new canvas(darkcornerbitmap);
 
  // 计算径向渐变半径
  float radiu = canvas.getheight() * (2f / 3f);
 
  // 实例化径向渐变
  radialgradient radialgradient = new radialgradient(canvas.getwidth() / 2f, canvas.getheight() / 2f, radiu, new int[] { 0, 0, 0xaa000000 }, new float[] { 0f, 0.7f, 1.0f }, tilemode.clamp);
 
  // 实例化一个矩阵
  matrix matrix = new matrix();
 
  // 设置矩阵的缩放
  matrix.setscale(canvas.getwidth() / (radiu * 2f), 1.0f);
 
  // 设置矩阵的预平移
  matrix.pretranslate(((radiu * 2f) - canvas.getwidth()) / 2f, 0);
 
  // 将该矩阵注入径向渐变
  radialgradient.setlocalmatrix(matrix);
 
  // 设置画笔shader
  mshaderpaint.setshader(radialgradient);
 
  // 绘制矩形
  canvas.drawrect(0, 0, canvas.getwidth(), canvas.getheight(), mshaderpaint);
  break;
 default:
  break;
 }
 }
 
 @override
 protected void ondraw(canvas canvas) {
 canvas.drawcolor(color.black);
 
 // 新建图层
 int sc = canvas.savelayer(x, y, x + msrc.getwidth(), y + msrc.getheight(), null, canvas.all_save_flag);
 
 // 绘制混合颜色
 canvas.drawcolor(0xcc1c093e);
 
 // 设置混合模式
 mbitmappaint.setxfermode(mxfermode);
 
 // 绘制位图
 canvas.drawbitmap(msrc, x, y, mbitmappaint);
 
 // 还原混合模式
 mbitmappaint.setxfermode(null);
 
 // 还原画布
 canvas.restoretocount(sc);
 
 switch (mnselectmode) {
 case bitmap_null:
  
  break;
 case bitmap_deast:
  break;
 case bitmap_center:
  // 绘制一个跟图片大小一样的矩形
  canvas.drawrect(x, y, x + msrc.getwidth(), y + msrc.getheight(),mshaderpaint);
  break;
 case bitmap_darkcorner:
  // 绘制我们画好的径向渐变图
  canvas.drawbitmap(darkcornerbitmap, x, y, null);
  break;
 default:
  break;
 }
 }
}

1)、实现 去饱和、提亮、色相矫正 效果的部分代码

?
1
2
3
mbitmappaint.setcolorfilter(new colormatrixcolorfilter(
 new float[] { 0.8587f, 0.2940f, -0.0927f, 0, 6.79f, 0.0821f, 0.9145f, 0.0634f, 0, 6.79f,
  0.2019f, 0.1097f, 0.7483f, 0, 6.79f, 0, 0, 0, 1, 0 }));

2)、实现中心颜色为透明而边缘颜色为黑色效果的部分代码  

?
1
2
mshaderpaint.setshader(new radialgradient(mwidth / 2, mwidth / 2, msrc.getheight() * 7 / 8, color.transparent,
 color.black, tilemode.clamp));

3)、实现四角黑暗效果的部分代码

?
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
// 根据我们源图的大小生成暗角bitmap
darkcornerbitmap = bitmap.createbitmap(msrc.getwidth(), msrc.getheight(), bitmap.config.argb_8888);
 
// 将该暗角bitmap注入canvas
canvas canvas = new canvas(darkcornerbitmap);
 
// 计算径向渐变半径
float radiu = canvas.getheight() * (2f / 3f);
 
// 实例化径向渐变
radialgradient radialgradient = new radialgradient(canvas.getwidth() / 2f, canvas.getheight() / 2f, radiu, new int[] { 0, 0, 0xaa000000 }, new float[] { 0f, 0.7f, 1.0f }, tilemode.clamp);
 
// 实例化一个矩阵
matrix matrix = new matrix();
 
// 设置矩阵的缩放
matrix.setscale(canvas.getwidth() / (radiu * 2f), 1.0f);
 
// 设置矩阵的预平移
matrix.pretranslate(((radiu * 2f) - canvas.getwidth()) / 2f, 0);
 
// 将该矩阵注入径向渐变
radialgradient.setlocalmatrix(matrix);
 
// 设置画笔shader
mshaderpaint.setshader(radialgradient);
 
// 绘制矩形
canvas.drawrect(0, 0, canvas.getwidth(), canvas.getheight(), mshaderpaint);

5、图片 + 文字

?
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package com.example.customimage.view;
 
import com.example.customimage.r;
 
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.porterduff;
import android.graphics.porterduffxfermode;
import android.graphics.rectf;
import android.graphics.bitmap.config;
import android.graphics.paint.style;
import android.graphics.rect;
import android.text.textpaint;
import android.text.textutils;
import android.util.attributeset;
import android.util.log;
import android.util.typedvalue;
import android.view.view;
 
public class imageviewtext extends view{
 
 //类型
 private int type;
 private static final int type_circle = 0; //圆形
 private static final int type_rect = 1; //矩形圆角
 //原始图片
 private bitmap mimage;
 //控件的宽度
 private int mwidth;
 
 // 控件的高度
 private int mheight;
 
 //矩形圆角的幅度
 private int mradius;
 //图片下面的文字
 private string mtitle;
 private int mtextcolor;
 private int mtextsize;
 private rect rect;
 private paint mpaint;
 private rect mtextbound;
 
 public imageviewtext(context context, attributeset attrs)
 {
 this(context, attrs, 0);
 }
 
 public imageviewtext(context context)
 {
 this(context, null);
 }
 
 /**
 * 初始化所特有自定义类型
 *
 * @param context
 * @param attrs
 * @param defstyle
 */
 public imageviewtext(context context, attributeset attrs, int defstyle)
 {
 super(context, attrs, defstyle);
 
 typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.imageviewtext, defstyle, 0);
 
 int n = a.getindexcount();
 
 for (int i = 0; i < n; i++)
 {
  int attr = a.getindex(i);
 
  switch (attr)
  {
  //获取图片
  case r.styleable.imageviewtext_image:
  mimage = bitmapfactory.decoderesource(getresources(), a.getresourceid(attr, 0));
  break;
  //获取圆形还是方形
  case r.styleable.imageviewtext_type:
  type = a.getint(attr, 0);
  break;
  //获取文字
  case r.styleable.imageviewtext_titletext:
  mtitle = a.getstring(attr);
  break;
  //获取文字的图片
  case r.styleable.imageviewtext_titletextcolor:
  mtextcolor = a.getcolor(attr, color.black);
  break;
  //获取文字的大小
  case r.styleable.imageviewtext_titletextsize:
  mtextsize = a.getdimensionpixelsize(attr, (int) typedvalue.applydimension(typedvalue.complex_unit_sp,
   16, getresources().getdisplaymetrics()));
  break;
  //矩形圆角幅度的获取,默认是10dp
  case r.styleable.imageviewtext_borderradius:
  mradius = a.getdimensionpixelsize(attr, (int) typedvalue
   .applydimension(typedvalue.complex_unit_dip, 10f,
    getresources().getdisplaymetrics()));
  break;
  }
 }
 a.recycle();
 rect = new rect();
 mpaint = new paint();
 mtextbound = new rect();
 mpaint.settextsize(mtextsize);
 // 计算了描绘字体需要的范围
 mpaint.gettextbounds(mtitle, 0, mtitle.length(), mtextbound);
 
 }
 
 //测量控件的大小
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec)
 {
 
 //设置宽度
 int specmode = measurespec.getmode(widthmeasurespec);
 int specsize = measurespec.getsize(widthmeasurespec);
 // match_parent , accurate 大小
 if (specmode == measurespec.exactly)
 {
  mwidth = specsize;
 } else
 {
  // 由图片决定的宽
  int desirebyimg = getpaddingleft() + getpaddingright() + mimage.getwidth();
  // 由字体决定的宽
  int desirebytitle = getpaddingleft() + getpaddingright() + mtextbound.width();
  //wrap_content 大小
  if (specmode == measurespec.at_most)
  {
  //取小的值
  int desire = math.max(desirebyimg, desirebytitle);
  mwidth = math.min(desire, specsize);
  }
 }
 
 //设置高度
 specmode = measurespec.getmode(heightmeasurespec);
 // match_parent , accurate 大小
 if (specmode == measurespec.exactly)
 {
  mheight = specsize;
 } else
 {
  //wrap_content 大小
  mheight = getpaddingtop() + getpaddingbottom() + mimage.getheight() + mtextbound.height();
 }
 //测量好的大小设置进去
 setmeasureddimension(mwidth, mheight);
 }
 
 @override
 protected void ondraw(canvas canvas)
 {
 // 边框
 mpaint.setstrokewidth(4);
 mpaint.setstyle(paint.style.stroke);
 mpaint.setcolor(color.cyan);
 canvas.drawrect(0, 0, getmeasuredwidth(), getmeasuredheight(), mpaint);
 
 mpaint.setcolor(mtextcolor);
 mpaint.setstyle(style.fill);
 //当前设置的宽度小于字体需要的宽度,将字体改为
 //绘制文字
 if (mtextbound.width() > mwidth)
 {
  textpaint paint = new textpaint(mpaint);
  string msg = textutils.ellipsize(mtitle, paint, (float) mwidth - getpaddingleft() - getpaddingright(),
   textutils.truncateat.end).tostring();
  canvas.drawtext(msg, getpaddingleft(), mheight - getpaddingbottom(), mpaint);
 
 } else
 {
  //正常情况,将字体居中
  canvas.drawtext(mtitle, mwidth / 2 - mtextbound.width() * 1.0f / 2, mheight - getpaddingbottom(), mpaint);
 }
  
  //计算居中的矩形范围
  rect.left = mwidth / 2 - mimage.getwidth() / 2 + getpaddingleft();
  rect.right = mwidth / 2 + mimage.getwidth() / 2 + getpaddingright();
  rect.top = (mheight - mtextbound.height()) / 2 - mimage.getheight() / 2 + getpaddingtop();
  rect.bottom = (mheight - mtextbound.height()) / 2 + mimage.getheight() / 2 + getpaddingbottom();
  
 switch (type)
 {
 // 如果是type_circle绘制圆形
 case type_circle:
  //圆形宽度和高度应该一致的,所以也要比较一下大小,取小的值
  int min = math.min(mwidth, mheight);
  // 圆形宽度和高度如果不一致,按小的值进行压缩
  mimage = bitmap.createscaledbitmap(mimage, min, min, false);
  //绘制圆形
  canvas.drawbitmap(createcircleimage(mimage, min), null, rect, null);
  break;
 case type_rect:
  canvas.drawbitmap(createroundconerimage(mimage), null, rect, null);
  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);
 // 首先绘制圆形,除以2就是半径了
 //最主要设置第三个参数为min/2,圆角幅度那么大就是圆形了
 canvas.drawcircle(min / 2, min / 2, min/2, paint);
 // 使用src_in,参考上面的说明---上下层都显示。下层居上显示
 paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));
 // 绘制图片
 canvas.drawbitmap(source, 0, 0, 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 = new rectf(0, 0, source.getwidth(), source.getheight());
 //设置圆角幅度
 canvas.drawroundrect(rect, mradius, mradius, paint);
 // 使用src_in,参考上面的说明---上下层都显示。下层居上显示
 paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));
 canvas.drawbitmap(source, 0, 0, paint);
 return target;
 }
}

是不是很全的android自定义图片集合,希望大家喜欢。