111
hxb
2022-11-24 0a3e07f10937484145f33c7560607b4b2353cb81
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
263
package com.mm.android.deviceaddmodule.mobilecommon.widget;
 
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
 
import com.mm.android.deviceaddmodule.R;
 
 
/**
 * 自定义 ImageView 控件,实现了圆角和边框,以及按下变色
 * 修改设置选中 颜色和 按下颜色 的方法 ,通过系统api调用, 移除java代码依赖, 只需要依赖xml和attr配置
 */
public class MLBorderImageView extends android.support.v7.widget.AppCompatImageView {
    public static final int TYPE_SHAPE_CIRCLE = 1;
    public static final int TYPE_SHAPE_RECT = 2;
    // 图片的宽高
    private int width;
    private int height;
 
    // 定义 Bitmap 的默认配置
    private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.RGB_565;
    private static final int COLORDRAWABLE_DIMENSION = 1;
 
    // 边框颜色
    private int borderColor, borderSelectedColor,borderUnSelectedColor;
    // 边框宽度
    private int borderWidth;
 
    // 圆角半径
    private int radius;
    // 图片类型(矩形,圆形)
    private int shapeType;
 
 
    public MLBorderImageView(Context context) {
        super(context);
        init(context, null);
    }
 
    public MLBorderImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }
 
    public MLBorderImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }
 
    private void init(Context context, AttributeSet attrs) {
        //初始化默认值
        borderWidth = 0;
        borderColor = 0xffffff;
 
        radius = 16;
        shapeType = 2;
 
        // 获取控件的属性值
        if (attrs != null) {
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MLBorderImageView);
            borderColor = array.getColor(R.styleable.MLBorderImageView_border_color, borderColor);
            borderUnSelectedColor = array.getColor(R.styleable.MLBorderImageView_border_color_normal, borderColor);
            borderSelectedColor = array.getColor(R.styleable.MLBorderImageView_border_color_selected, borderColor);
            borderWidth = array.getDimensionPixelOffset(R.styleable.MLBorderImageView_border_width, borderWidth);
 
            radius = array.getDimensionPixelOffset(R.styleable.MLBorderImageView_radius, radius);
            shapeType = array.getInteger(R.styleable.MLBorderImageView_shape_type, shapeType);
            array.recycle();
        }
 
        setClickable(true);
        setDrawingCacheEnabled(true);
        setWillNotDraw(false);
    }
 
 
    @Override
    protected void onDraw(Canvas canvas) {
 
        if (shapeType == 0) {
            super.onDraw(canvas);
            return;
        }
        // 获取当前控件的 drawable
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }
        // 这里 get 回来的宽度和高度是当前控件相对应的宽度和高度(在 xml 设置)
        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        // 获取 bitmap,即传入 imageView 的 bitmap
        // Bitmap bitmap = ((BitmapDrawable) ((SquaringDrawable)
        // drawable).getCurrent()).getBitmap();
        // 获取 bitmap 方式,因为上边的获取会导致 Glide 加载的drawable 强转为 BitmapDrawable 出错
        Bitmap bitmap = getBitmapFromDrawable(drawable);
        drawDrawable(canvas, bitmap);
 
        drawBorder(canvas);
    }
 
    /**
     * 实现圆角的绘制
     *
     * @param canvas
     * @param bitmap
     */
    private void drawDrawable(Canvas canvas, Bitmap bitmap) {
        // 画笔
        Paint paint = new Paint();
        // 颜色设置
        paint.setColor(0xffffffff);
        // 抗锯齿
        paint.setAntiAlias(true);
        //Paint 的 Xfermode,PorterDuff.Mode.SRC_IN 取两层图像的交集部分, 只显示上层图像。
        PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
        canvas.saveLayer(0, 0, width, height, null);
 
        if (shapeType == 1) {
            // 画遮罩,画出来就是一个和空间大小相匹配的圆(这里在半径上 -1 是为了不让图片超出边框)
            canvas.drawCircle(width / 2, height / 2, width / 2 - 1, paint);
        } else if (shapeType == 2) {
            // 当ShapeType == 2 时 图片为圆角矩形 (这里在宽高上 -1 是为了不让图片超出边框)
            RectF rectf = new RectF(1, 1, getWidth() - 1, getHeight() - 1);
            canvas.drawRoundRect(rectf, radius + 1, radius + 1, paint);
        }
 
        paint.setXfermode(xfermode);
 
        // 空间的大小 / bitmap 的大小 = bitmap 缩放的倍数
        float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
        float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
 
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
 
        //bitmap 缩放
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
 
        //draw 上去
        canvas.drawBitmap(bitmap, 0, 0, paint);
        canvas.restore();
        bitmap.recycle();
        bitmap = null;
    }
 
    /**
     * 绘制自定义控件边框
     *
     * @param canvas
     */
    private void drawBorder(Canvas canvas) {
        if (borderWidth > 0) {
            Paint paint = new Paint();
            paint.setStrokeWidth(borderWidth);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(borderColor);
            paint.setAntiAlias(true);
            // 根据控件类型的属性去绘制圆形或者矩形
            if (shapeType == 1) {
                canvas.drawCircle(width / 2, height / 2, (width - borderWidth) / 2, paint);
            } else if (shapeType == 2) {
                // 当ShapeType = 1 时 图片为圆角矩形
                RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2,
                        getHeight() - borderWidth / 2);
                canvas.drawRoundRect(rectf, radius, radius, paint);
            }
        }
    }
 
    /**
     * 重写父类的 onSizeChanged 方法,检测控件宽高的变化
     *
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }
 
 
    /**
     * 这里是参考其他开发者获取Bitmap内容的方法, 之前是因为没有考虑到 Glide 加载的图片
     * 导致drawable 类型是属于 SquaringDrawable 类型,导致强转失败
     * 这里是通过drawable不同的类型来进行获取Bitmap
     *
     * @param drawable
     * @return
     */
    private Bitmap getBitmapFromDrawable(Drawable drawable) {
        try {
            Bitmap bitmap;
            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            } else if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
                        BITMAP_CONFIG);
            }
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }
 
    @Override
    public void setSelected(boolean selected) {
        super.setSelected(selected);
        setBorderColor(selected);
    }
 
    @Override
    public void setPressed(boolean pressed) {
        super.setPressed(pressed);
        if(isSelected()){
            return;
        }
        setBorderColor(pressed);
    }
 
    private void setBorderColor(boolean selected) {
        if(selected){
            borderColor = borderSelectedColor;
        }else{
            borderColor = borderUnSelectedColor;
        }
        invalidate();
    }
 
 
    public void setRadius(int radius){
        this.radius = radius;
        invalidate();
    }
 
    public void setShapeType(int type){
        this.shapeType = type;
    }
 
 
}