带边框的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>