带边框的Android形状三角形

带边框的Android形状三角形,android,border,android-shape,Android,Border,Android Shape,我已经创建了三角形形状,如下代码所示: <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <rotate android:fromDegrees="45" android:toDegrees="45

我已经创建了三角形形状,如下代码所示:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <rotate
            android:fromDegrees="45"
            android:toDegrees="45"
            android:pivotX="13%"
            android:pivotY="-40%" >
            <shape
                android:shape="rectangle" >
                <stroke android:color="#000000" android:width="1dp"/>
                <solid
                    android:color="#000000" />
            </shape>
        </rotate>
    </item>
</layer-list>


如何使三角形的边框颜色与形状的其他部分不同?如果我改变笔画的颜色,它会起作用,我有两个不同颜色的面,没有第三个边框。我该如何纠正它

现在,我确实花了一些时间来尝试为您提供一个很好的示例,让您可以使用canvas。下面的代码仍然可以使用线性/径向渐变进行改进,如果您愿意,还可以使其更加可自定义。也许我将来会这样做,但我今天已经做了

首先将其添加到资源值中。我使用/values/attrs.xml如果您没有看到此文件,请创建它

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Triangle">
        <attr name="triangleColor" format="color"/>
        <attr name="triangleStrokeColor" format="color" />
        <attr name="triangleStrokeWidth" format="dimension" />
    </declare-styleable>
</resources>

现在创建一个三角形类,最好是在保存自定义视图的文件夹中。修复包名和R类导入

package si.kseneman.views;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.View;

import si.kseneman.mobile.R;


public class Triangle extends View {

    private int measuredWidth, measuredHeight;
    private float density;
    private Paint mTrianglePaint, mStrokePaint;
    private PointF a, b, c;
    private Path mTrianglePath;
    private float mStrokeWidth;

    // Default values
    private int mTriangleColor = 0xAA4CAF50; //ARGB int
    private int mStrokeColor = Color.BLACK; //ARGB int
    private float defaultPadding = 5; //dp

    public Triangle(Context context) {
        super(context);
        init(context, null, 0);
    }

    public Triangle(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

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

    private void init(Context context, AttributeSet attrs, int style) {

        Resources res = context.getResources();
        density = res.getDisplayMetrics().density;
        defaultPadding *= density;


        // Get the values from XML
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.Triangle, style, 0);

        int tmp;

        mTriangleColor = typedArray.getColor(R.styleable.Triangle_triangleColor, mTriangleColor);
        mStrokeColor = typedArray.getColor(R.styleable.Triangle_triangleStrokeColor, mStrokeColor);

        tmp = typedArray.getDimensionPixelSize(R.styleable.Triangle_triangleStrokeWidth, -1);
        mStrokeWidth = tmp != -1 ? tmp : 2 * density; // Use 2dp as a default value

        typedArray.recycle();

        a = new PointF();
        b = new PointF();
        c = new PointF();

        mTrianglePath = new Path();

        mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTrianglePaint.setStyle(Paint.Style.FILL);
        mTrianglePaint.setColor(mTriangleColor);

        mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setStrokeWidth(mStrokeWidth);
        mStrokePaint.setColor(mStrokeColor);

    }

    public void setTriangleColorResId(int resId) {
        // Example: setTriangleColorResId(R.color.blue);
        setTriangleColor(getContext().getResources().getColor(resId));
    }

    public void setTriangleColor(String color) {
        setTriangleColor(Color.parseColor(color));
    }

    public void setTriangleColor(int color) {
        mTriangleColor = color;
        mTrianglePaint.setColor(mTriangleColor);
        invalidate();
    }

    public void setStrokeColorResId(int resId) {
        // Example: setTriangleColorResId(R.color.blue);
        setStrokeColor(getContext().getResources().getColor(resId));
    }

    public void setStrokeColor(String color) {
        setTriangleColor(Color.parseColor(color));
    }

    public void setStrokeColor(int color) {
        mStrokeColor = color;
        mStrokePaint.setColor(mStrokeColor);
        invalidate();
    }

    public void setStrokeWidth(float strokeWidth) {
        if (strokeWidth < 0)
            throw new IllegalArgumentException("Stroke width cannot be < 0");
        //NOTE: input parameter is meant to be in pixels, you need to convert dp, sp or anything else
        // when calling this method
        mStrokeWidth = strokeWidth;
        mStrokePaint.setStrokeWidth(mStrokeWidth);
        invalidate();
    }

    public int getStrokeColor() {
        return mStrokeColor;
    }

    public float getStrokeWidth() {
        return mStrokeWidth;
    }

    public int getTriangleColor() {
        return mTriangleColor;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

        setMeasuredDimension(measuredWidth, measuredHeight);
        //Log.d(TAG, "Height: " + measuredHeight + " Width: " + measuredWidth);
    }

    private float getPaddingOrDefault(int padding, float defaultValue) {
        return padding != 0 ? padding : defaultValue;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (measuredHeight <= 0 || measuredWidth <= 0) {
            // Not much we can draw...  :/
            return;
        }

        // Define the points of the triangle... make this so that it suits your needs

        // Top point
        a.x = measuredWidth / 2f;
        a.y = getPaddingOrDefault(getPaddingTop(), defaultPadding);

        // Bottom left point
        b.x = getPaddingOrDefault(getPaddingLeft(), defaultPadding);
        b.y = measuredHeight - getPaddingOrDefault(getPaddingBottom(), defaultPadding);

        // Bottom right point
        c.x = measuredWidth - getPaddingOrDefault(getPaddingRight(), defaultPadding);
        c.y = b.y;

        // Clear the path from previous onDraw
        mTrianglePath.reset();

        // Make a path of triangle
        mTrianglePath.moveTo(a.x, a.y);
        mTrianglePath.lineTo(b.x, b.y);
        mTrianglePath.lineTo(c.x, c.y);
        mTrianglePath.lineTo(a.x, a.y);
        mTrianglePath.close();

        // Draw the triangle and the stroke
        canvas.drawPath(mTrianglePath, mTrianglePaint);
        canvas.drawPath(mTrianglePath, mStrokePaint);

    }
}
包si.kseneman.views;
导入android.content.Context;
导入android.content.res.Resources;
导入android.content.res.TypedArray;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.PointF;
导入android.util.AttributeSet;
导入android.view.view;
导入si.kseneman.mobile.R;
公共类三角形扩展视图{
专用int测量宽度、测量高度;
私有浮动密度;
私人涂料MTRIANGLEANT、mStrokePaint;
专用点F a、b、c;
私有路径mTrianglePath;
私有浮动mStrokeWidth;
//默认值
私有int mTriangleColor=0xAA4CAF50;//ARGB int
private int mStrokeColor=Color.BLACK;//ARGB int
私有浮点defaultPadding=5;//dp
公共三角形(上下文){
超级(上下文);
init(上下文,null,0);
}
公共三角形(上下文、属性集属性){
超级(上下文,attrs);
init(上下文,attrs,0);
}
公共三角形(上下文上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
init(上下文、attrs、defStyleAttr);
}
私有void init(上下文上下文、属性集属性、int样式){
Resources res=context.getResources();
密度=res.getDisplayMetrics().密度;
默认填充*=密度;
//从XML获取值
TypedArray TypedArray=getContext().ActainStyledAttributes(attrs,R.styleable.Triangle,style,0);
int tmp;
mTriangleColor=typedArray.getColor(R.styleable.Triangle\u triangleColor,mTriangleColor);
mStrokeColor=typedArray.getColor(R.styleable.Triangle\u triangleStrokeColor,mStrokeColor);
tmp=typedArray.getDimensionPixelSize(R.styleable.Triangle\U TriangelStrokewidth,-1);
mStrokeWidth=tmp!=-1?tmp:2*密度;//使用2dp作为默认值
typedArray.recycle();
a=新的点f();
b=新点f();
c=新点f();
mTrianglePath=新路径();
mTrianglePaint=新油漆(油漆.防油漆别名标志);
MtriangelPaint.setStyle(Paint.Style.FILL);
mTrianglePaint.setColor(mTriangleColor);
mStrokePaint=新油漆(油漆.防油漆别名标志);
mStrokePaint.setStyle(Paint.Style.STROKE);
mStrokePaint.setStrokeWidth(mStrokeWidth);
mStrokePaint.setColor(mStrokeColor);
}
公共无效SetTriangeleColorResid(内部剩余){
//示例:SetTriangeleColorResid(R.color.blue);
setTriangalColor(getContext().getResources().getColor(resId));
}
公共无效设置三角形颜色(字符串颜色){
setTriangalColor(Color.parseColor(Color));
}
公共无效设置三角形颜色(int颜色){
mTriangleColor=颜色;
mTrianglePaint.setColor(mTriangleColor);
使无效();
}
公共无效设置行程ColorResid(int resId){
//示例:SetTriangeleColorResid(R.color.blue);
setStrokeColor(getContext().getResources().getColor(resId));
}
公共void setStrokeColor(字符串颜色){
setTriangalColor(Color.parseColor(Color));
}
公共void setStrokeColor(内部颜色){
mStrokeColor=颜色;
mStrokePaint.setColor(mStrokeColor);
使无效();
}
公共无效设置行程宽度(浮动行程宽度){
如果(冲程宽度<0)
抛出新的IllegalArgumentException(“笔划宽度不能小于0”);
//注意:输入参数是以像素为单位的,您需要转换dp、sp或其他任何参数
//调用此方法时
mStrokeWidth=冲程宽度;
mStrokePaint.setStrokeWidth(mStrokeWidth);
使无效();
}
public int getStrokeColor(){
返回mStrokeColor;
}
公共浮点getStrokeWidth(){
返回mStrokeWidth;
}
public int getTriangelColor(){
返回mTriangleColor;
}
@凌驾
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
measuredHeight=getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);
measuredWidth=getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
设置测量尺寸(测量宽度、测量高度);
//对数d(标签“高度:”+测量高度+“宽度:”+测量宽度);
}
私有浮点GetPaddingOrdFault(整型填充,浮点默认值){
返回填充!=0?填充:默认值;
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);

如果(measuredHeight现在我确实花了一些时间来尝试为您制作一个很好的示例来使用canvas。下面的代码仍然可以使用线性/径向渐变进行改进,如果您愿意,您也可以使其更可自定义。也许我将来会这样做,但我今天已经完成了

首先将其添加到资源值中
package si.kseneman.views;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;

    public class TriangleAndArc extends View {

        private int measuredWidth, measuredHeight;
        private float density;
        private float a1Degrees;
        private float textHeight;
        private double a1Radians;

        private Paint mLinePaint, mPointPaint, mTextPaint, mCirclePaint;
        private DashPathEffect dashedEffect;
        private PointF p1, p2, m, c;


        public TriangleAndArc(Context context) {
            super(context);
            init(context);
        }

        public TriangleAndArc(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }

        public TriangleAndArc(Context context, AttributeSet attrs, int style) {
            super(context, attrs, style);
            init(context);
        }

        private void init(Context ctx) {

            p1 = new PointF();
            p2 = new PointF();
            c = new PointF();
            m = new PointF();

            Resources res = ctx.getResources();
            density = res.getDisplayMetrics().density;

            a1Degrees = 36.0f;
            a1Radians = Math.toRadians(a1Degrees);

            dashedEffect = new DashPathEffect(new float[]{5, 5}, 1.0f);
            mLinePaint = new Paint();
            mLinePaint.setAntiAlias(true);
            mLinePaint.setStyle(Paint.Style.STROKE);
            mLinePaint.setStrokeJoin(Paint.Join.ROUND);
            mLinePaint.setStrokeWidth(2 * density);
            mLinePaint.setColor(Color.BLACK);
            //mPaint.setPathEffect(dashedEffect);

            mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPointPaint.setStyle(Paint.Style.FILL);
            mPointPaint.setColor(Color.RED);

            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setTextSize(10 * density);
            mTextPaint.setTypeface(Typeface.create("Roboto-Thin", Typeface.BOLD));
            mTextPaint.setColor(Color.RED);

            if(!isInEditMode()) {
                // Shadow layer is not supported in preview mode and android studio makes an ugly warning about it!
                mTextPaint.setShadowLayer(0.1f, 0, 1, Color.GRAY);
            }

            textHeight = Math.abs(mTextPaint.descent() + mTextPaint.ascent());

            mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mCirclePaint.setColor(Color.BLUE);
            mCirclePaint.setStyle(Paint.Style.STROKE);
            mCirclePaint.setStrokeWidth(density);
        }

        // Square a number
        private double sq(double a) {
            return a * a;
        }

        private void drawIncenterAndExcenter(PointF A, PointF B, PointF C, Canvas canvas) {
            double a = Math.sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y));
            double b = Math.sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y));
            double c = Math.sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));

            double perimeter = a + b + c;
            double s = 0.5 * perimeter;
            double area = Math.sqrt(s * (s - a) * (s - b) * (s - c));

            // Inscribed Circle
            double iRadius = area / s;
            PointF iCenter = new PointF();
            iCenter.x = (float) ((a * A.x + b * B.x + c * C.x) / (perimeter));
            iCenter.y = (float) ((a * A.y + b * B.y + c * C.y) / (perimeter));

            // Circumscribed Circle
            PointF cCenter = new PointF();
            double cRadius = (a * b * c) / (4.0 * area);
            double D = 2 * (A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y));
            double sqA = sq(A.x) + sq(A.y);
            double sqB = sq(B.x) + sq(B.y);
            double sqC = sq(C.x) + sq(C.y);
            cCenter.x = (float) ((sqA * (B.y - C.y) + sqB * (C.y - A.y) + sqC * (A.y - B.y)) / D);
            cCenter.y = (float) ((sqA * (C.x - B.x) + sqB * (A.x - C.x) + sqC * (B.x - A.x)) / D);

            // Draw
            canvas.drawCircle(iCenter.x, iCenter.y, density * 5, mPointPaint);
            canvas.drawCircle(iCenter.x, iCenter.y, (float) iRadius, mCirclePaint);
            canvas.drawText("I", iCenter.x - mTextPaint.measureText("I") * 0.5f, iCenter.y - textHeight - 2 * density, mTextPaint);


            canvas.drawCircle(cCenter.x, cCenter.y, density * 5, mPointPaint);
            canvas.drawCircle(cCenter.x, cCenter.y, (float) cRadius, mCirclePaint);
            canvas.drawText("E", cCenter.x - mTextPaint.measureText("E") * 0.5f, cCenter.y - textHeight - 2 * density, mTextPaint);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
            measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

            setMeasuredDimension(measuredWidth, measuredHeight);
            //Log.d(TAG, "Height: " + measuredHeight + " Width: " + measuredWidth);
        }

        @Override
        protected void onDraw(Canvas canvas) {

            if (measuredHeight <= 0 || measuredWidth <= 0) {
                // Not much we can draw...  :/
                return;
            }

            // Orientation independent drawing
            int width = (measuredWidth > measuredHeight) ? measuredWidth : measuredHeight;
            int height = (width == measuredWidth) ? measuredHeight : measuredWidth;

            // Define points
            p1.x = width * 0.7f;
            p1.y = height * 0.2f - 20;

            p2.x = width * 0.85f;
            p2.y = 2 * height / 3.0f - 20;

            float dx = p2.x - p1.x;
            float dy = p2.y - p1.y;

            // l1 is half the length of the line from p1 to p2
            double l = Math.sqrt(dx * dx + dy * dy);
            double l1 = l / 2.0;

            // Center of the circle
            double h = l1 / (Math.tan(a1Radians / 2.0));

            // Radius of the circle
            double r = l1 / (Math.sin(a1Radians / 2.0));

            // a2 is the angle at which L intersects the x axis
            double a2 = Math.atan2(dy, dx);

            // a3 is the angle at which H intersects the x axis
            double a3 = (Math.PI / 2.0) - a2;

            // m is the midpoint of the line from e1 to e2
            m.x = (p1.x + p2.x) / 2.0f;
            m.y = (p1.y + p2.y) / 2.0f;

            // c is the the center of the circle
            c.x = (float) (m.x - (h * Math.cos(a3)));
            c.y = (float) (m.y + (h * Math.sin(a3)));

            // rect is the square RectF that bounds the "oval"
            RectF oval = new RectF((float) (c.x - r), (float) (c.y - r), (float) (c.x + r), (float) (c.y + r));

            // a4 is the starting sweep angle
            double rawA4 = Math.atan2(p1.y - c.y, p1.x - c.x);
            float a4 = (float) Math.toDegrees(rawA4);

            // Draw lines
            canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mLinePaint);
            canvas.drawLine(c.x, c.y, p1.x, p1.y, mLinePaint);
            canvas.drawLine(c.x, c.y, p2.x, p2.y, mLinePaint);
            canvas.drawLine(c.x, c.y, m.x, m.y, mLinePaint);

            // Draw arc
            mLinePaint.setPathEffect(dashedEffect);
            canvas.drawArc(oval, a4, a1Degrees, false, mLinePaint);

            // Draw dots
            canvas.drawCircle(p1.x, p1.y, density * 5, mPointPaint);
            canvas.drawCircle(p2.x, p2.y, density * 5, mPointPaint);
            canvas.drawCircle(m.x, m.y, density * 5, mPointPaint);
            canvas.drawCircle(c.x, c.y, density * 5, mPointPaint);

            // Draw text
            float halfOfTextHeight = textHeight * 0.5f; // We need an offset of a half
            canvas.drawText("p1", p1.x + density * 7, p1.y + halfOfTextHeight, mTextPaint);
            canvas.drawText("p2", p2.x + density * 7, p2.y + halfOfTextHeight, mTextPaint);
            canvas.drawText("m", m.x + density * 7, m.y + halfOfTextHeight, mTextPaint);
            canvas.drawText("c", c.x - mTextPaint.measureText("c") - density * 7, c.y + halfOfTextHeight, mTextPaint);

            drawIncenterAndExcenter(p1, p2, c, canvas);

        }
    }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:triangle="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="2">

    <si.kseneman.views.Triangle
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:padding="10dp"
        android:rotation="0"
        triangle:triangleStrokeColor="@android:color/black"
        triangle:triangleColor="#FF33B5E5"
        triangle:triangleStrokeWidth="3dp"/>

    <si.kseneman.views.TriangleAndArc
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"/>

</LinearLayout>