2017-09-15 61 views

回答

0

试试这个:

public class CircleImageView extends AppCompatImageView { 

private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; 

// Default Values 
private static final float DEFAULT_BORDER_WIDTH = 4; 
private static final float DEFAULT_SHADOW_RADIUS = 8.0f; 

// Properties 
private float borderWidth; 
private int canvasSize; 
private float shadowRadius; 
private int shadowColor = Color.BLACK; 

// Object used to draw 
private Bitmap image; 
private Drawable drawable; 
private Paint paint; 
private Paint paintBorder; 

private Context context; 

//region Constructor & Init Method 
public CircleImageView(final Context context) { 
    this(context, null); 
} 

public CircleImageView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
} 

public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    init(context, attrs, defStyleAttr); 
} 

private void init(Context context, AttributeSet attrs, int defStyleAttr) { 
    // Init paint 
    paint = new Paint(); 
    paint.setAntiAlias(true); 

    paintBorder = new Paint(); 
    paintBorder.setAntiAlias(true); 
    this.context = context; 

    // Load the styled attributes and set their properties 
    TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyleAttr, 0); 

    // Init Border 
    if (attributes.getBoolean(R.styleable.CircularImageView_civ_border, true)) { 
     float defaultBorderSize = DEFAULT_BORDER_WIDTH * getContext().getResources().getDisplayMetrics().density; 
     setBorderWidth(attributes.getDimension(R.styleable.CircularImageView_civ_border_width, defaultBorderSize)); 
     setBorderColor(attributes.getColor(R.styleable.CircularImageView_civ_border_color, Color.WHITE)); 
    } 

    // Init Shadow 
    if (attributes.getBoolean(R.styleable.CircularImageView_civ_shadow, false)) { 
     shadowRadius = DEFAULT_SHADOW_RADIUS; 
     drawShadow(attributes.getFloat(R.styleable.CircularImageView_civ_shadow_radius, shadowRadius), attributes.getColor(R.styleable.CircularImageView_civ_shadow_color, shadowColor)); 
    } 
} 
//endregion 

//region Set Attr Method 
public void setBorderWidth(float borderWidth) { 
    this.borderWidth = borderWidth; 
    requestLayout(); 
    invalidate(); 
} 

public void setBorderColor(int borderColor) { 
    if (paintBorder != null) 
     paintBorder.setColor(borderColor); 
    invalidate(); 
} 

public void addShadow() { 
    if (shadowRadius == 0) 
     shadowRadius = DEFAULT_SHADOW_RADIUS; 
    drawShadow(shadowRadius, shadowColor); 
    invalidate(); 
} 

public void setShadowRadius(float shadowRadius) { 
    drawShadow(shadowRadius, shadowColor); 
    invalidate(); 
} 

public void setShadowColor(int shadowColor) { 
    drawShadow(shadowRadius, shadowColor); 
    invalidate(); 
} 

@Override 
public ScaleType getScaleType() { 
    return SCALE_TYPE; 
} 

@Override 
public void setScaleType(ScaleType scaleType) { 
    if (scaleType != SCALE_TYPE) { 
     throw new IllegalArgumentException(String.format("ScaleType %s not supported. ScaleType.CENTER_CROP is used by default. So you don't need to use ScaleType.", scaleType)); 
    } 
} 
//endregion 

//region Draw Method 
@Override 
public void onDraw(Canvas canvas) { 
    // Load the bitmap 
    loadBitmap(); 

    // Check if image isn't null 
    if (image == null) 
     return; 

    if (!isInEditMode()) { 
     canvasSize = canvas.getWidth(); 
     if (canvas.getHeight() < canvasSize) { 
      canvasSize = canvas.getHeight(); 
     } 
    } 

    // circleCenter is the x or y of the view's center 
    // radius is the radius in pixels of the cirle to be drawn 
    // paint contains the shader that will texture the shape 
    int circleCenter = (int) (canvasSize - (borderWidth * 2))/2; 
    // Draw Border 
    canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - (shadowRadius + shadowRadius/2), paintBorder); 
    // Draw CircularImageView 
    canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - (shadowRadius + shadowRadius/2), paint); 
} 

private void loadBitmap() { 
    if (this.drawable == getDrawable()) 
     return; 

    this.drawable = getDrawable(); 
    this.image = drawableToBitmap(this.drawable); 
    updateShader(); 
} 

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 
    canvasSize = w; 
    if (h < canvasSize) 
     canvasSize = h; 
    if (image != null) 
     updateShader(); 
} 

private void drawShadow(float shadowRadius, int shadowColor) { 
    this.shadowRadius = shadowRadius; 
    this.shadowColor = shadowColor; 
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { 
     setLayerType(LAYER_TYPE_SOFTWARE, paintBorder); 
    } 
    paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius/2, shadowColor); 
} 

private void updateShader() { 
    if (image == null) 
     return; 

    // Crop Center Image 
    image = cropBitmap(image); 

    // Create Shader 
    BitmapShader shader = new BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 

    // Center Image in Shader 
    Matrix matrix = new Matrix(); 
    matrix.setScale((float) canvasSize/(float) image.getWidth(), (float) canvasSize/(float) image.getHeight()); 
    shader.setLocalMatrix(matrix); 

    // Set Shader in Paint 
    paint.setShader(shader); 
} 

private Bitmap cropBitmap(Bitmap bitmap) { 
    Bitmap bmp; 
    if (bitmap.getWidth() >= bitmap.getHeight()) { 
     bmp = Bitmap.createBitmap(
       bitmap, 
       bitmap.getWidth()/2 - bitmap.getHeight()/2, 
       0, 
       bitmap.getHeight(), bitmap.getHeight()); 
    } else { 
     bmp = Bitmap.createBitmap(
       bitmap, 
       0, 
       bitmap.getHeight()/2 - bitmap.getWidth()/2, 
       bitmap.getWidth(), bitmap.getWidth()); 
    } 
    return bmp; 
} 

private Bitmap drawableToBitmap(Drawable drawable) { 
    if (drawable == null) { 
     return null; 
    } else if (drawable instanceof BitmapDrawable) { 
     return ((BitmapDrawable) drawable).getBitmap(); 
    } 

    int intrinsicWidth = drawable.getIntrinsicWidth(); 
    int intrinsicHeight = drawable.getIntrinsicHeight(); 

    if (!(intrinsicWidth > 0 && intrinsicHeight > 0)) 
     return null; 

    try { 
     // Create Bitmap object out of the drawable 
     Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888); 
     Canvas canvas = new Canvas(bitmap); 
     drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 
     drawable.draw(canvas); 
     return bitmap; 
    } catch (OutOfMemoryError e) { 
     // Simply return null of failed bitmap creations 
     Log.e(getClass().toString(), "Encountered OutOfMemoryError while generating bitmap!"); 
     return null; 
    } 
} 
//endregion 

//region Mesure Method 
@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    int width = measureWidth(widthMeasureSpec); 
    int height = measureHeight(heightMeasureSpec); 
    /*int imageSize = (width < height) ? width : height; 
    setMeasuredDimension(imageSize, imageSize);*/ 
    setMeasuredDimension(width, height); 
} 

private int measureWidth(int measureSpec) { 
    int result; 
    int specMode = MeasureSpec.getMode(measureSpec); 
    int specSize = MeasureSpec.getSize(measureSpec); 

    if (specMode == MeasureSpec.EXACTLY) { 
     // The parent has determined an exact size for the child. 
     result = specSize; 
    } else if (specMode == MeasureSpec.AT_MOST) { 
     // The child can be as large as it wants up to the specified size. 
     result = specSize; 
    } else { 
     // The parent has not imposed any constraint on the child. 
     result = canvasSize; 
    } 

    return result; 
} 

private int measureHeight(int measureSpecHeight) { 
    int result; 
    int specMode = MeasureSpec.getMode(measureSpecHeight); 
    int specSize = MeasureSpec.getSize(measureSpecHeight); 

    if (specMode == MeasureSpec.EXACTLY) { 
     // We were told how big to be 
     result = specSize; 
    } else if (specMode == MeasureSpec.AT_MOST) { 
     // The child can be as large as it wants up to the specified size. 
     result = specSize; 
    } else { 
     // Measure the text (beware: ascent is a negative number) 
     result = canvasSize; 
    } 

    return (result + 2); 
} 


} 

现在的XML文件中使用此:

<com.xyz.customclass.CircleImageView 
       android:id="@+id/img_event" 
       android:layout_width="55dp" 
       android:layout_height="55dp" 
       app:civ_border="true" 
       app:civ_border_color="@color/color_circular_home_image_border" 
       app:civ_border_width="1dp" 
       app:civ_shadow="true" 
       app:civ_shadow_color="@color/color_circular_home_image_border" 
       app:civ_shadow_radius="2" 
       app:srcCompat="@mipmap/ocassion_placeholder" /> 

在attr.xml添加这个(建立attr.xml:在res - > values-> attr.xml下)

<declare-styleable name="CircularImageView"> 
    <attr name="civ_border" format="boolean"/> 
    <attr name="civ_border_width" format="dimension"/> 
    <attr name="civ_border_color" format="color"/> 
    <attr name="civ_shadow" format="boolean"/> 
    <attr name="civ_shadow_color" format="color"/> 
    <attr name="civ_shadow_radius" format="float"/> 
</declare-styleable> 
+0

非常感谢Shweta肖汉,但在那里我能找到的** ** R.styleable.CircularImageView,因为没有在主CircleImageView一些值,比如CircularImageView_civ_border –

+0

香港乐施会,让我编辑 –

+0

答案值更新。 –