自定义图片形状 圆形到多边形

最近因为项目需要找到这个demo ,顺便分享给大家。自定义图片的形状及旋转方向。

下面是自定义内容

package net.grobas.view;


import net.grobas.polygonimageview.sample.R;
import net.grobas.shapes.PolygonShape;
import net.grobas.shapes.PolygonShapeSpec;
import net.grobas.shapes.RegularPolygonShape;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;


/**
 * Construct a custom ImageView with a regular polygonal form.
 * The number of vertices determines the polygon form.
 * Special cases for vertex number are:
 * 0 -> Circle
 * 1 -> Regular ImageView
 * 2 -> Square
 * Use square images
 *
 * @author Albert Grobas
 */
public class PolygonImageView extends ImageView {


    //draws
    private Paint mPaint;
    private Paint mBorderPaint;
    private Path mPath;


    private PolygonShape mPolygonShape;
    private PolygonShapeSpec mPolygonShapeSpec;


    private int canvasWidth, canvasHeight;
    String LAYER_TYPE_SOFTWARE = "";


    public PolygonImageView(Context context) {
        this(context, null);
    }


    public PolygonImageView(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.polygonImageViewStyle);
    }


    public PolygonImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);


        mPolygonShapeSpec = new PolygonShapeSpec();


        TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.PolygonImageView, defStyle, 0);


        try {
            mPolygonShapeSpec.setRotation(attributes.getFloat(R.styleable.PolygonImageView_poly_rotation_angle, 0f));
            mPolygonShapeSpec.setNumVertex(attributes.getInteger(R.styleable.PolygonImageView_poly_vertices, 6));
            mPolygonShapeSpec.setCornerRadius(attributes.getFloat(R.styleable.PolygonImageView_poly_corner_radius, 0f));
            mPolygonShapeSpec.setHasShadow(attributes.getBoolean(R.styleable.PolygonImageView_poly_shadow, false));
            mPolygonShapeSpec.setShadowColor(attributes.getColor(R.styleable.PolygonImageView_poly_shadow_color, Color.BLACK));
            mPolygonShapeSpec.setHasBorder(attributes.getBoolean(R.styleable.PolygonImageView_poly_border, false));
            mPolygonShapeSpec.setBorderColor(attributes.getColor(R.styleable.PolygonImageView_poly_border_color, Color.WHITE));
            mPolygonShapeSpec.setBorderWidth(attributes.getDimension(R.styleable.PolygonImageView_poly_border_width, 4));


        } finally {
            attributes.recycle();
        }


        init();
    }


    /**
     * Init paints and effects
     */
    @SuppressLint("NewApi")
    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setPathEffect(new CornerPathEffect(mPolygonShapeSpec.getCornerRadius()));
        mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setPathEffect(new CornerPathEffect(mPolygonShapeSpec.getCornerRadius()));


        if(mPolygonShapeSpec.hasBorder()) {
            mBorderPaint.setColor(mPolygonShapeSpec.getBorderColor());
            mBorderPaint.setStrokeWidth(mPolygonShapeSpec.getBorderWidth());
        }


        if (mPolygonShapeSpec.hasShadow()) {
            //Shadow on border even if isBordered is false. Better effect and performance that
            //using shadow on main paint
            mBorderPaint.setShadowLayer(mPolygonShapeSpec.getShadowRadius(), mPolygonShapeSpec.getShadowXOffset(),
                    mPolygonShapeSpec.getShadowYOffset(), mPolygonShapeSpec.getShadowColor());
        }


//        //Avoid known shadow problems
//        if (Build.VERSION.SDK_INT > 13)
//            setLayerType(LAYER_TYPE_SOFTWARE, null);


        mPolygonShape = new RegularPolygonShape();
    }


    /**
     * Gets incoming new canvas size and updates polygon form and image if needed.
     *
     * @param w    new Width
     * @param h    new Height
     * @param oldW old Width
     * @param oldH old Height
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        super.onSizeChanged(w, h, oldW, oldH);


        canvasWidth = w;
        canvasHeight = h;
        updatePolygonSize();


        if (Math.min(canvasWidth, canvasHeight) != Math.min(oldW, oldH)) {
            refreshImage();
        }
    }


    /**
     * Force Override to solve bug on Lollipop
     *
     * @param widthMeasureSpec  Width Spec Measure
     * @param heightMeasureSpec Height Spec Measure
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }


    private int measureWidth(int measureSpecWidth) {
        return measure(measureSpecWidth);
    }


    private int measureHeight(int measureSpecHeight) {
        //Force do not square measure to solve bug (use base 2 better performance)
        return (measure(measureSpecHeight) + 2);
    }


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


        if (specMode == MeasureSpec.EXACTLY || specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else {
            result = Math.min(canvasWidth, canvasHeight);
        }


        return result;
    }


    /**
     * Draw the polygon form.
     *
     * @param canvas main canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        if (getDrawable() == null || getDrawable().getIntrinsicWidth() == 0 ||
                getDrawable().getIntrinsicHeight() == 0)
            return;


        switch (mPolygonShapeSpec.getNumVertex()) {
            case 0: //CIRCLE
                if (mPolygonShapeSpec.hasShadow() || mPolygonShapeSpec.hasBorder()) {
                    canvas.drawCircle(mPolygonShapeSpec.getCenterX(), mPolygonShapeSpec.getCenterY(),
                            mPolygonShapeSpec.getDiameter() / 2, mBorderPaint);
                }
                canvas.drawCircle(mPolygonShapeSpec.getCenterX(), mPolygonShapeSpec.getCenterY(),
                        mPolygonShapeSpec.getDiameter() / 2, mPaint);
                break;
            case 1: //REGULAR IMAGE VIEW
                super.onDraw(canvas);
                break;
            case 2: //SQUARE
                if (mPolygonShapeSpec.hasShadow() || mPolygonShapeSpec.hasBorder()) {
                    canvas.drawRect(mPolygonShapeSpec.getCenterX() - mPolygonShapeSpec.getDiameter() / 2,
                        mPolygonShapeSpec.getCenterY() - mPolygonShapeSpec.getDiameter() / 2,
                        mPolygonShapeSpec.getCenterX() + mPolygonShapeSpec.getDiameter() / 2,
                        mPolygonShapeSpec.getCenterY() + mPolygonShapeSpec.getDiameter() / 2,
                        mBorderPaint);
                }
                canvas.drawRect(mPolygonShapeSpec.getCenterX() - mPolygonShapeSpec.getDiameter() / 2,
                    mPolygonShapeSpec.getCenterY() - mPolygonShapeSpec.getDiameter() / 2,
                    mPolygonShapeSpec.getCenterX() + mPolygonShapeSpec.getDiameter() / 2,
                    mPolygonShapeSpec.getCenterY() + mPolygonShapeSpec.getDiameter() / 2,
                    mPaint);
                break;
            default: //POLYGON
                if (mPolygonShapeSpec.hasShadow() || mPolygonShapeSpec.hasBorder())
                    canvas.drawPath(mPath, mBorderPaint);
                canvas.drawPath(mPath, mPaint);
        }
    }


    /**
     * Take cares about padding changes.
     *
     * @param start  start
     * @param top    top
     * @param end    end
     * @param bottom bottom
     */
    @SuppressLint("Override")
public void setPaddingRelative(int start, int top, int end, int bottom) {
        super.setPadding(start, top, end, bottom);
        updatePolygonSize();
        invalidate();
    }


    /**
     * Take cares about padding changes.
     *
     * @param left   left
     * @param top    top
     * @param right  right
     * @param bottom bottom
     */
    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(left, top, right, bottom);
        updatePolygonSize(left, top, right, bottom);
        invalidate(left, top, right, bottom);
    }


    /**
     * Update image.
     *
     * @param bm new image.
     */
    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        refreshImage();
        invalidate();
    }


    /**
     * Update image.
     *
     * @param drawable new image.
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        refreshImage();
        invalidate();
    }


    /**
     * Update image.
     *
     * @param resId new image.
     */
    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        refreshImage();
        invalidate();
    }


    /**
     * Update image.
     *
     * @param uri new image.
     */
    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        refreshImage();
        invalidate();
    }


    @Override
    public void setColorFilter(ColorFilter cf) {
        mPaint.setColorFilter(cf);
        invalidate();
    }


    public void setColorFilterWithBorder(ColorFilter cf) {
        mPaint.setColorFilter(cf);
        mBorderPaint.setColorFilter(cf);
        invalidate();
    }


    /**
     * Refresh image with new canvas size or new image.
     */
    @SuppressLint("NewApi")
private void refreshImage() {
        Bitmap image = drawableToBitmap(getDrawable());
        int canvasSize = Math.min(canvasWidth, canvasHeight);
        if (canvasSize > 0 && image != null) {
            //Preserve image ratio if it is not square
            BitmapShader shader = new BitmapShader(ThumbnailUtils.extractThumbnail(image, canvasSize, canvasSize),
                    Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint.setShader(shader);
        }
    }


    /**
     * Rebuild polygon after changes, take cares about padding, border and shadow radius.
     * Rotate vertices with the variable angle.
     */
    private void rebuildPolygon() {
        //recalculate new center
        float borderNeeded = mPolygonShapeSpec.hasBorder() ? mPolygonShapeSpec.getBorderWidth() : 0;
        float shadowNeeded = mPolygonShapeSpec.hasShadow() ? mPolygonShapeSpec.getShadowRadius() : 0;
        mPolygonShapeSpec.setCenterX(mPolygonShapeSpec.getDiameter() / 2 + (float) (getPaddingLeft() +
                getPaddingRight()) / 2 + borderNeeded + shadowNeeded);
        mPolygonShapeSpec.setCenterY(mPolygonShapeSpec.getDiameter() / 2 + (float) (getPaddingTop() +
                getPaddingBottom()) / 2 + borderNeeded + shadowNeeded);


        if (mPolygonShapeSpec.getNumVertex() < 3)
            return;


        mPath = mPolygonShape.getPolygonPath(mPolygonShapeSpec);
    }


    /**
     * Update polygon size with unspecified padding.
     */
    private void updatePolygonSize() {
        updatePolygonSize(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
    }


    /**
     * Update polygon with new padding.
     *
     * @param l Left padding.
     * @param t Top padding.
     * @param r Right padding.
     * @param b Bottom padding.
     */
    private void updatePolygonSize(int l, int t, int r, int b) {
        if(mPolygonShapeSpec == null)
            return;


        float borderPadding = mPolygonShapeSpec.hasBorder() ? mPolygonShapeSpec.getBorderWidth() : 0f;
        float shadowPadding = mPolygonShapeSpec.hasShadow() ? mPolygonShapeSpec.getShadowRadius() : 0f;
        float xPadding = (l + r + (borderPadding * 2) + (shadowPadding * 2));
        float yPadding = (t + b + (borderPadding * 2) + (shadowPadding * 2));
        float diameter = Math.min((float) canvasWidth - xPadding, (float) canvasHeight - yPadding);
        //if the size is changed we need to rebuild the polygon
        if (diameter != mPolygonShapeSpec.getDiameter()) {
            mPolygonShapeSpec.setDiameter(diameter);
            rebuildPolygon();
        }
    }


    /**
     *
     * @param polygonShape set new shape
     */
    public void setPolygonShape(PolygonShape polygonShape) {
        mPolygonShape = polygonShape;
        rebuildPolygon();
        invalidate();
    }


    /**
     *
     * @return get current shape
     */
    public PolygonShape getPolygonShape() {
        return mPolygonShape;
    }


    /**
     *
     * @return get current shape spec
     */
    public PolygonShapeSpec getPolygonShapeSpec() {
        return mPolygonShapeSpec;
    }


    /**
     *
     * @param spec set shape spec
     */
    public void setPolygonShapeSpec(PolygonShapeSpec spec) {
        this.mPolygonShapeSpec = spec;
    }


    /**
     * Returns the rotate angle.
     *
     * @return angle in degrees.
     */
    public float getRotationAngle() {
        return mPolygonShapeSpec.getRotation();
    }


    /**
     * Set new rotate angle and updates polygon form.
     *
     * @param mAngle angle in degrees.
     */
    public void setRotationAngle(float mAngle) {
        mPolygonShapeSpec.setRotation(mAngle);
        rebuildPolygon();
        invalidate();
    }


    /**
     * Returns the vertex number.
     *
     * @return vertex number
     */
    public int getVertices() {
        return mPolygonShapeSpec.getNumVertex();
    }


    /**
     * Sets the new vertex number and updates polygon form.
     *
     * @param numVertices new number of vertices
     */
    public void setVertices(int numVertices) {
        mPolygonShapeSpec.setNumVertex(numVertices);
        rebuildPolygon();
        invalidate();
    }


    /**
     * Indicates if it's bordered.
     *
     * @return boolean
     */
    public boolean isBordered() {
        return mPolygonShapeSpec.hasBorder();
    }


    /**
     * Enables or disables the border option.
     *
     * @param bordered if it's bordered
     */
    public void setBorder(boolean bordered) {
        mPolygonShapeSpec.setHasBorder(bordered);
        updateBorderSpecs();
    }


    /**
     * Sets new border width.
     *
     * @param borderWidth new width.
     */
    public void setBorderWidth(float borderWidth) {
        mPolygonShapeSpec.setBorderWidth(borderWidth * (getResources().getDisplayMetrics().density));
        updateBorderSpecs();
    }


    /**
     * Sets new border width and update polygon size.
     */
    private void updateBorderSpecs() {
        if(mPolygonShapeSpec.hasBorder()) {
            mBorderPaint.setStrokeWidth(mPolygonShapeSpec.getBorderWidth());
            mBorderPaint.setColor(mPolygonShapeSpec.getBorderColor());
        } else {
            mBorderPaint.setStrokeWidth(0);
            mBorderPaint.setColor(0);
        }
        updatePolygonSize();
        invalidate();
    }


    /**
     * Sets new border color.
     *
     * @param borderColor Color class var.
     */
    public void setBorderColor(int borderColor) {
        mPolygonShapeSpec.setBorderColor(borderColor);
        mBorderPaint.setColor(borderColor);
        invalidate();
    }


    /**
     * Sets new border color
     *
     * @param resourceBorderColor Resource xml color.
     */
    public void setBorderColorResource(int resourceBorderColor) {
        setBorderColor(getResources().getColor(resourceBorderColor));
    }


    public void addBorder(float borderWidth, int borderColor) {
        mPolygonShapeSpec.setHasBorder(true);
        mPolygonShapeSpec.setBorderWidth(borderWidth * (getResources().getDisplayMetrics().density));
        mPolygonShapeSpec.setBorderColor(borderColor);
        updateBorderSpecs();
    }


    public void addBorderResource(float borderWidth, int resourceBorderColor) {
        addBorder(borderWidth, getResources().getColor(resourceBorderColor));
    }


    /**
     * Sets new radius for corners and updates view.
     *
     * @param cornerRadius new corner radius
     */
    public void setCornerRadius(float cornerRadius) {
        mPolygonShapeSpec.setCornerRadius(cornerRadius);
        mBorderPaint.setPathEffect(new CornerPathEffect(cornerRadius));
        mPaint.setPathEffect(new CornerPathEffect(cornerRadius));
        invalidate();
    }


    /**
     * Adds a default shadow
     */
    public void addShadow() {
        startShadow();
    }


    /**
     * Adds a specific shadow.
     *
     * @param radius  shadow blur size.
     * @param offsetX negative value moves shadow to left and positive to right.
     * @param offsetY negative value moves shadow down and positive towards up.
     * @param color   shadow color
     */
    public void addShadow(float radius, float offsetX, float offsetY, int color) {
        mPolygonShapeSpec.setShadowRadius(radius);
        mPolygonShapeSpec.setShadowXOffset(offsetX);
        mPolygonShapeSpec.setShadowYOffset(offsetY);
        mPolygonShapeSpec.setShadowColor(color);
        startShadow();
    }


    public void addShadowResource(float radius, float offsetX, float offsetY, int color) {
        addShadow(radius, offsetX, offsetY, getResources().getColor(color));
    }


    private void startShadow() {
        mPolygonShapeSpec.setHasShadow(true);
        mBorderPaint.setShadowLayer(mPolygonShapeSpec.getShadowRadius(), mPolygonShapeSpec.getShadowXOffset(),
                mPolygonShapeSpec.getShadowYOffset(), mPolygonShapeSpec.getShadowColor());
        updatePolygonSize();
        invalidate();
    }


    /**
     * Removes shadow
     */
    public void clearShadow() {
        if (!mPolygonShapeSpec.hasShadow())
            return;


        mPolygonShapeSpec.setHasShadow(false);
        mBorderPaint.clearShadowLayer();
        updatePolygonSize();
        invalidate();
    }


    /**
     * Transforms a drawable into a bitmap.
     *
     * @param drawable incoming drawable
     * @return new bitmap
     */
    private static Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable == null) {
            return null;
        } else if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }


        //Avoid Color Drawable special case
        int width = drawable.getIntrinsicWidth();
        width = width > 0 ? width : 1;
        int height = drawable.getIntrinsicHeight();
        height = height > 0 ? height : 1;


        Bitmap bitmap;
        try {
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        } catch (OutOfMemoryError e) {
            Log.e("PolygonImageView", "OutOfMemory during bitmap creation");
            return null;
        }


        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);


        return bitmap;
    }

}

下面这个是工具类

package net.grobas.view.util;


import java.util.Arrays;
import java.util.Collections;
import java.util.List;


/**
 * Geometry Util
 */
public class GeometryUtil {


    /**
     * Intersection between line, determined for two points, and a circle with radius x
     * @param pointA line point a
     * @param pointB line point b
     * @param center point center circle
     * @param radius circle radius
     * @return intersection points
     */
    public static List getCircleLineIntersectionPoint(Point pointA, Point pointB, Point center, double radius) {
        double baX = pointB.x - pointA.x;
        double baY = pointB.y - pointA.y;
        double caX = center.x - pointA.x;
        double caY = center.y - pointA.y;


        double a = baX * baX + baY * baY;
        double bBy2 = baX * caX + baY * caY;
        double c = caX * caX + caY * caY - radius * radius;


        double pBy2 = bBy2 / a;
        double q = c / a;


        double disc = pBy2 * pBy2 - q;
        if (disc < 0) {
            return Collections.emptyList();
        }


        double tmpSqrt = Math.sqrt(disc);
        double abScalingFactor1 = -pBy2 + tmpSqrt;
        double abScalingFactor2 = -pBy2 - tmpSqrt;


        Point p1 = new Point(pointA.x - baX * abScalingFactor1, pointA.y
                - baY * abScalingFactor1);
        if (disc == 0) {
            return Collections.singletonList(p1);
        }
        Point p2 = new Point(pointA.x - baX * abScalingFactor2, pointA.y
                - baY * abScalingFactor2);
        return Arrays.asList(p1, p2);
    }


    public static class Point {
        public double x, y;


        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }




    }
}


下面是使用的方法

    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">


            android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">


                    android:id="@+id/layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical">


                            android:id="@+id/kitty01"
                android:layout_width="250dp"
                android:layout_height="250dp"
                android:src="@drawable/cat07"
                app:poly_border="true"
                app:poly_border_color="@android:color/white"
                app:poly_border_width="5dp"
                app:poly_corner_radius="25"
                app:poly_rotation_angle="0"
                app:poly_shadow="true"
                app:poly_shadow_color="#f01"
                app:poly_vertices="6" />


                            android:layout_width="250dp"
                android:layout_height="250dp"
                android:src="@drawable/cat03"
                app:poly_border="true"
                app:poly_border_color="#f01"
                app:poly_border_width="5dp"
                app:poly_corner_radius="5"
                app:poly_rotation_angle="0"
                app:poly_shadow="true"
                app:poly_vertices="0" />



   

记得加入配置文件哦






   
       
       
       
       
       
       
       
       
   



   
       
   




大功告成。可以运行看看哦!自定义图片形状 圆形到多边形_第1张图片

源码地址      http://download.csdn.net/detail/seven2729/8968161


转载请注明:http://blog.csdn.net/seven2729/article/details/47979263

你可能感兴趣的:(自定义图片形状 圆形到多边形)