Many Android applications use rounded avatars, or some rounded pictures are more troublesome to process, so they can directly use rounded pictures tool
public class CircleImageView extends ImageView { // Zoom type private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; private static final BITMAP_CONFIG = .ARGB_8888; private static final int COLORDRAWABLE_DIMENSION = 2; // Default boundary width private static final int DEFAULT_BORDER_WIDTH = 0; // Default border color private static final int DEFAULT_BORDER_COLOR = ; private static final boolean DEFAULT_BORDER_OVERLAY = false; private final RectF mDrawableRect = new RectF(); private final RectF mBorderRect = new RectF(); private final Matrix mShaderMatrix = new Matrix(); // The most important thing about this brush is that it is associated with mBitmapShader // Make the canvas cut the original image when executing (mBitmapShader is a bitmap associated with the original image) private final Paint mBitmapPaint = new Paint(); // This stroke has no connection with the original bitmap of its own. private final Paint mBorderPaint = new Paint(); // Here is the default width and color of the circle edge private int mBorderColor = DEFAULT_BORDER_COLOR; private int mBorderWidth = DEFAULT_BORDER_WIDTH; private Bitmap mBitmap; private BitmapShader mBitmapShader; // Bitmap rendering private int mBitmapWidth; // Bitmap width private int mBitmapHeight; // Bitmap height private float mDrawableRadius;// Picture radius private float mBorderRadius;// The radius of the picture with borders private ColorFilter mColorFilter; // Initial false private boolean mReady; private boolean mSetupPending; private boolean mBorderOverlay; // Constructor public CircleImageView(Context context) { super(context); init(); } // Constructor public CircleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * Constructor */ public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // Obtain a set of values to TypedArray (array) through obtainedStyledAttributes, // This set of values comes from the declare-styleable name="CircleImageView" in res/values/. TypedArray a = (attrs, , defStyle, 0); // Get the parameter value we defined in xml through a series of methods provided by TypedArray getXXXX; // Get the width of the boundary mBorderWidth = ( .CircleImageView_border_size, DEFAULT_BORDER_WIDTH); // Get the color of the boundary mBorderColor = (.CircleImageView_border_color, DEFAULT_BORDER_COLOR); // mBorderOverlay = // (.CircleImageView_border_overlay, // DEFAULT_BORDER_OVERLAY); // Call recycle() to recycle TypedArray for later reuse (); init(); } /** * The function is to ensure that the following code in the setup function is called when the constructor is executed for the first time. */ private void init() { // Here, ScaleType is forced to be CENTER_CROP, which means centering the image horizontally and vertically to scale. (SCALE_TYPE); mReady = true; if (mSetupPending) { setup(); mSetupPending = false; } } @Override public ScaleType getScaleType() { return SCALE_TYPE; } /** * It is clearly stated here that this imageview only supports the CENTER_CROP attribute * * @param scaleType */ @Override public void setScaleType(ScaleType scaleType) { if (scaleType != SCALE_TYPE) { throw new IllegalArgumentException(( "ScaleType %s not supported.", scaleType)); } } @Override public void setAdjustViewBounds(boolean adjustViewBounds) { if (adjustViewBounds) { throw new IllegalArgumentException( "adjustViewBounds not supported."); } } @Override protected void onDraw(Canvas canvas) { // If the picture does not exist, don't draw it if (getDrawable() == null) { return; } // Draw the inner circle Picture The brush is mBitmapPaint (getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); // If the width of the circle edge is not 0, we also need to draw an outer circle with boundaries. The border brush is mBorderPaint if (mBorderWidth != 0) { (getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { (w, h, oldw, oldh); setup(); } public int getBorderColor() { return mBorderColor; } public void setBorderColor(int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; (mBorderColor); invalidate(); } public void setBorderColorResource(@ColorRes int borderColorRes) { setBorderColor(getContext().getResources().getColor(borderColorRes)); } public int getBorderWidth() { return mBorderWidth; } public void setBorderWidth(int borderWidth) { if (borderWidth == mBorderWidth) { return; } mBorderWidth = borderWidth; setup(); } public boolean isBorderOverlay() { return mBorderOverlay; } public void setBorderOverlay(boolean borderOverlay) { if (borderOverlay == mBorderOverlay) { return; } mBorderOverlay = borderOverlay; setup(); } /** * The following four functions are all rewrite the setImageXxx() method of ImageView. Note that this function is called before the constructor call. * * @param bm */ @Override public void setImageBitmap(Bitmap bm) { (bm); mBitmap = bm; setup(); } @Override public void setImageDrawable(Drawable drawable) { (drawable); mBitmap = getBitmapFromDrawable(drawable); setup(); } @Override public void setImageResource(@DrawableRes int resId) { (resId); mBitmap = getBitmapFromDrawable(getDrawable()); setup(); } @Override public void setImageURI(Uri uri) { (uri); mBitmap = getBitmapFromDrawable(getDrawable()); setup(); } @Override public void setColorFilter(ColorFilter cf) { if (cf == mColorFilter) { return; } mColorFilter = cf; (mColorFilter); invalidate(); } /** * Drawable to Bitmap * * @param drawable * @return */ private Bitmap getBitmapFromDrawable(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { // Usually our code returns after it is executed. What is returned is our most primitive bitmap return ((BitmapDrawable) drawable).getBitmap(); } try { Bitmap bitmap; if (drawable instanceof ColorDrawable) { bitmap = (COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); } else { bitmap = ((), (), BITMAP_CONFIG); } Canvas canvas = new Canvas(bitmap); (0, 0, (), ()); (canvas); return bitmap; } catch (OutOfMemoryError e) { return null; } } /** * This function is very critical, initialize some redraw parameters of the picture brush boundary brush (Paint): * Build the renderer BitmapShader to use Bitmap to fill the drawing area, set the style and calculate the radius of the inner and outer circles, etc. * and call updateShaderMatrix() and invalidate() functions; */ private void setup() { // Because mReady default value is false, the first time I enter this function, if statement is true and enters the parentheses body // Set mSetupPending to true and then return directly. The subsequent code is not executed. if (!mReady) { mSetupPending = true; return; } // Prevent null pointer exceptions if (mBitmap == null) { return; } // Build a renderer and use mBitmap bitmap to fill the drawing area. The parameter value means that if the picture is too small, it will be stretched directly mBitmapShader = new BitmapShader(mBitmap, , ); // Set picture brush anti-aliasing (true); // Set up the picture brush renderer (mBitmapShader); // Set border brush style ();// Suppose the brush is hollow (true); (mBorderColor); // Brush color (mBorderWidth);// Brush boundary width // This place is the width and height of the original picture taken mBitmapHeight = (); mBitmapWidth = (); // Set the boundary display area, take the actual layout size of the CircleImageView, which is square, and view the xml, that is, 160dp (240px) // getWidth gets the actual size of a view (0, 0, getWidth(), getHeight()); // calculate // The minimum radius of the boundary part of the circular belt (outer circle) is used, and the width and height of mBorderRect is used to subtract half of the edge size (I am more puzzled in this place why you need to subtract one edge size first to calculate the radius of the outer circle) mBorderRadius = ((() - mBorderWidth) / 2, (() - mBorderWidth) / 2); // The initial image display area is mBorderRect (the actual layout size of the CircleImageView) (mBorderRect); if (!mBorderOverlay) { // Always execute in demo // Through the inset method // Make the area displayed in the picture move up, down, left and right from the width of the boundary to form an area. Check that the boundary width of the xml is 2dp (3px), so the square side length is 160-4=156dp (234px) (mBorderWidth, mBorderWidth); } // Here we calculate the minimum radius of the inner circle, that is, the radius of the boundary width removed mDrawableRadius = (() / 2, () / 2); // Set the renderer's transformation matrix, that is, what kind of scaling form is used to fill the renderer updateShaderMatrix(); // Manually trigger the ondraw() function to complete the final drawing invalidate(); } /** * This function sets the Matrix parameter of BitmapShader, sets the minimum scaling ratio, and translates the parameters. Function: Ensure the minimum loss of the picture and always draw the part in the center of the picture. */ private void updateShaderMatrix() { float scale; float dx = 0; float dy = 0; (null); // It is not easy to understand here. This inequality is (mBitmapWidth / ()) > // (mBitmapHeight / ()) // Take the minimum scaling ratio if (mBitmapWidth * () > () * mBitmapHeight) { // Y-axis zoom x-axis translation makes the size of the edges in the y-axis direction of the picture scale to the same as mDrawableRect) scale = () / (float) mBitmapHeight; dx = (() - mBitmapWidth * scale) * 0.5f; } else { // x-axis zoom y-axis translation makes the size of the x-axis edge of the picture scale to the same as mDrawableRect)) scale = () / (float) mBitmapWidth; dy = (() - mBitmapHeight * scale) * 0.5f; } // Shaeder's transformation matrix is mainly used here to enlarge or shrink. (scale, scale); // Pan ((int) (dx + 0.5f) + , (int) (dy + 0.5f) + ); // Set the transformation matrix (mShaderMatrix); } }
How to use
< android:layout_width="45dp" android:layout_height="45dp" android:src="@mipmap/ic_header" app:border_color="@color/bg_dddddd" android:layout_gravity="center_vertical" android:layout_marginRight="10dp" app:border_size="1dp" />
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.