下面列出了android.graphics.Path#addArc ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private Path getPreloadProgressPath(Context context) {
if (AndroidVersion.isAtLeastOreo()) {
try {
// Try to load the path from Mask Icon
Drawable icon = context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper);
icon.setBounds(0, 0,
PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE);
return (Path) icon.getClass().getMethod("getIconMask").invoke(icon);
} catch (Exception e) {
e.printStackTrace();
}
}
// Create a circle static from top center and going clockwise.
Path p = new Path();
p.moveTo(PreloadIconDrawable.PATH_SIZE / 2, 0);
p.addArc(0, 0, PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE, -90, 360);
return p;
}
protected void drawTitle(Canvas canvas, int alpha) {
if (alpha > 0 && isShowTitle) {
Path path = new Path();
float circumference = (float) (Math.PI * (outlineOval.right - outlineOval.left));
float textAngle = (360 / circumference) * titlePaint.measureText(getTitle());
float startAngle = mStartAngle + mSweepAngle / 2 - textAngle / 2;
if (isSingle) {
// when single, draw 360 the path will be a circle
path.addArc(outlineOval, startAngle - mSweepAngle / 2, mSweepAngle / 2);
} else {
path.addArc(outlineOval, startAngle, mSweepAngle);
}
titlePaint.setAlpha(alpha);
canvas.drawTextOnPath(mTitle, path, 0, textWidth / 3, titlePaint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRect = new RectF(getWidth() / 2 - RADIUS, PADDING, getWidth() / 2 + RADIUS, getHeight() - PADDING);
// 刻度的数量
Path arcPath = new Path();
arcPath.addArc(mRect, START_ANAGLE, 360 - (START_ANAGLE - 45));
PathMeasure pathMeasure = new PathMeasure(arcPath, false);
float pathMeasureLength = pathMeasure.getLength();
// 短刻度
mShortEffect = new PathDashPathEffect(mShortDash,
(pathMeasureLength - Utils.dp2px(2)) / 50,// 每个间距为多少
0,// 第一个从什么地方开始
PathDashPathEffect.Style.ROTATE);
// 长刻度
mLongEffect = new PathDashPathEffect(mLongDash,
(pathMeasureLength - Utils.dp2px(2)) / 10,// 每个间距为多少
0,// 第一个从什么地方开始
PathDashPathEffect.Style.ROTATE);
}
@Override
public Path newPath() {
Path path = ObjectPool.pathPool.checkOut();
float startingRadians = (float) Math.toRadians(this.startingAngle);
float endingRadians = (float) Math.toRadians(this.endingAngle);
path.moveTo(this.center.x, this.center.y);
// Android arc is defined differently than the iOS arc.
// TODO - Test this visually. Not so sure if the given angles are good,
// or need a conversion.
RectF oval = new RectF(center.x - radius, center.y + radius, center.x + radius, center.y
- radius);
// We keep those in degrees, not radians.
path.addArc(oval, startingRadians, endingRadians);
path.close();
return path;
}
/**
* calculate and set position to menu items
*/
private void calculateMenuItemPosition() {
float itemRadius = (expandedRadius + collapsedRadius) / 2, f;
RectF area = new RectF(
center.x - itemRadius,
center.y - itemRadius,
center.x + itemRadius,
center.y + itemRadius);
Path path = new Path();
path.addArc(area, (float) fromAngle, (float) (toAngle - fromAngle));
PathMeasure measure = new PathMeasure(path, false);
float len = measure.getLength();
int divisor = getChildCount();
float divider = len / divisor;
for (int i = 0; i < getChildCount(); i++) {
float[] coords = new float[2];
measure.getPosTan(i * divider + divider * .5f, coords, null);
FilterMenu.Item item = (FilterMenu.Item) getChildAt(i).getTag();
item.setX((int) coords[0] - item.getView().getMeasuredWidth() / 2);
item.setY((int) coords[1] - item.getView().getMeasuredHeight() / 2);
}
}
private void testArc(Canvas canvas) {
Path path=new Path();
int minWidth=400;
int br = minWidth / 2;
RectF bigCircle = new RectF(-br, -br, br, br);
int sr = minWidth / 4;
RectF smallCircle = new RectF(-sr, -sr, sr, sr);
float bigSweepAngle = 84;
float smallSweepAngle = -80;
path.addArc(bigCircle, 50, bigSweepAngle);
path.arcTo(smallCircle, 130, smallSweepAngle);
path.close();
canvas.drawPath(path, mDeafultPaint);
logRegion();
}
public CircleFramedDrawable(Bitmap icon, int size) {
super();
mSize = size;
mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(mBitmap);
final int width = icon.getWidth();
final int height = icon.getHeight();
final int square = Math.min(width, height);
final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2,
square, square);
final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
final Path fillPath = new Path();
fillPath.addArc(circleRect, 0f, 360f);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// opaque circle
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(fillPath, mPaint);
// mask in the icon where the bitmap is opaque
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
// prepare paint for frame drawing
mPaint.setXfermode(null);
mScale = 1f;
mSrcRect = new Rect(0, 0, mSize, mSize);
mDstRect = new RectF(0, 0, mSize, mSize);
}
private void initPaths()
{
float r = mR * 0.4f;
mPath = new Path();
mPath.addArc(new RectF(getViewCenterX() - mR, getViewCenterY() - mR, getViewCenterX() + mR, getViewCenterY() + mR), 45, 359.9f);
mPathMeasure.setPath(mPath, false);
float[] pos = new float[2];
mPathMeasure.getPosTan(0, pos, null);
mPathZoom = new Path();
mPathZoom.addArc(new RectF(getViewCenterX() - r, getViewCenterY() - r, getViewCenterX() + r, getViewCenterY() + r), 45, 359.9f);
mPathZoom.lineTo(pos[0], pos[1]);
}
private void createArc(Path p, RectF mRectF, float currentSweep, float startAngle, float sweepAngle) {
if (currentSweep == 360) {
p.addArc(mRectF, startAngle, sweepAngle);
} else {
p.arcTo(mRectF, startAngle, sweepAngle);
}
}
/**
* Calculates the desired positions of all items.
*/
private void calculateItemPositions() {
// Create an arc that starts from startAngle and ends at endAngle
// in an area that is as large as 4*radius^2
Point center = getActionViewCenter();
//内切弧形路径
RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
Path orbit = new Path();
orbit.addArc(area, startAngle, endAngle - startAngle);
PathMeasure measure = new PathMeasure(orbit, false);
// Prevent overlapping when it is a full circle
int divisor;
if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
divisor = subActionItems.size();
}
else {
divisor = subActionItems.size() -1;
}
// Measure this path, in order to find points that have the same distance between each other
for(int i=0; i<subActionItems.size(); i++) {
float[] coords = new float[] {0f, 0f};
measure.getPosTan((i) * measure.getLength() / divisor, coords, null);
// get the x and y values of these points and set them to each of sub action items.
subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
}
}
/**
* Initialize the {@code Path} objects with the appropriate values.
*/
private void initPaths() {
mCirclePath = new Path();
mCirclePath.addArc(mCircleRectF, mStartAngle, mTotalCircleDegrees);
mCircleProgressPath = new Path();
mCircleProgressPath.addArc(mCircleRectF, mStartAngle, mProgressDegrees);
}
/**
* Calculates the desired positions of all items.
*/
private void calculateItemPositions() {
// Create an arc that starts from startAngle and ends at endAngle
// in an area that is as large as 4*radius^2
Point center = getActionViewCenter();
RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
Path orbit = new Path();
orbit.addArc(area, startAngle, endAngle - startAngle);
PathMeasure measure = new PathMeasure(orbit, false);
// Prevent overlapping when it is a full circle
int divisor;
if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
divisor = subActionItems.size();
}
else {
divisor = subActionItems.size() -1;
}
// Measure this path, in order to find points that have the same distance between each other
for(int i=0; i<subActionItems.size(); i++) {
float[] coords = new float[] {0f, 0f};
measure.getPosTan((i) * measure.getLength() / divisor, coords, null);
// get the x and y values of these points and set them to each of sub action items.
subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
}
}
public Path newPath() {
Path path = ObjectPool.pathPool.checkOut();
// Android arc is defined differently than the iOS arc.
// TODO - Test this visually. Not so sure if the given angles are good,
// or need a conversion.
RectF oval = new RectF(center.x - radius, center.y + radius, center.x + radius, center.y
- radius);
// For Android, we need to keep those in degrees, not radians.
path.addArc(oval, startingAngle, endingAngle);
return path;
}
private void init() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(15);
mPaint.setColor(WinSearch.this.getResources().getColor(R.color.colorPrimary));
//设置画笔为园笔
mPaint.setStrokeCap(Paint.Cap.ROUND);
//抗锯齿
mPaint.setAntiAlias(true);
mPath = new Path();
RectF rect = new RectF(-150,-150,150,150);
mPath.addArc(rect,-90,359.9f);
mPathMeasure = new PathMeasure(mPath,false);
valueAnimator = ValueAnimator.ofFloat(0f,1f).setDuration(3000);
valueAnimator.setRepeatCount(-1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
t = (float) animation.getAnimatedValue();
invalidate();
}
});
}
private void initPaths()
{
float r = mR * 0.4f;
mPath = new Path();
mPath.addArc(new RectF(getViewCenterX() - mR, getViewCenterY() - mR, getViewCenterX() + mR, getViewCenterY() + mR), 45, 359.9f);
mPathMeasure.setPath(mPath, false);
float[] pos = new float[2];
mPathMeasure.getPosTan(0, pos, null);
mPathZoom = new Path();
mPathZoom.addArc(new RectF(getViewCenterX() - r, getViewCenterY() - r, getViewCenterX() + r, getViewCenterY() + r), 45, 359.9f);
mPathZoom.lineTo(pos[0], pos[1]);
}
/**
* Initialize the {@code Path} objects with the appropriate values.
*/
private void initPaths() {
mCirclePath = new Path();
mCirclePath.addArc(mCircleRectF, mStartAngle, mTotalCircleDegrees);
mCircleProgressPath = new Path();
mCircleProgressPath.addArc(mCircleRectF, mStartAngle, mProgressDegrees);
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
canvas.save();
canvas.translate(0,-Ui.cd.getHt(10));
canvas.save();
bass.draw(canvas);
float radius = 10;
final RectF oval = new RectF();
oval.set(0, 0, bass.width, bass.height);
Path ph = new Path();
ph.setFillType(Path.FillType.WINDING);
ph.moveTo(bass.width/2, bass.width/2);
if(angle > 110 - 1){
ph.addArc(oval,-(200) + 110,angle - 110);
}else{
ph.addArc(oval,-(90) - (110 - angle),(110 - angle));
}
ph.lineTo(bass.width/2,bass.width/2);
canvas.clipPath(ph);
basstop.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(-(90+20),XX,YY);
canvas.rotate(angle,XX,YY);
bassdot.draw(canvas);
canvas.restore();
int val = (angle - 110);
val = (int) ((100f / 110) * val);
levelText.setText(val+"",true);
levelText.draw(canvas);
canvas.restore();
super.drawShape(canvas);
//canvas.drawPath(ph,bass.img.maskPaint);
}
/**计算各种绘制坐标*/
private void evaluatorData(float animPre){
paintLabel.setTextSize(tagTextSize);
float tagTextLead = FontUtil.getFontLeading(paintLabel);
float tagTextHeight = FontUtil.getFontHeight(paintLabel);
float oneStartAngle = startAngle;
for(int i = 0; i < dataList.size(); i++) {
PieChartBean bean = dataList.get(i);
/* if(bean.getNum() == 0 && !showZeroPart){
continue;
}*/
/**1、绘制扇形*/
float arcLeft = centerPoint.x - chartRaidus; //扇形半径
float arcTop = centerPoint.y - chartRaidus;
float arcRight = centerPoint.x + chartRaidus;
float arcBottom = centerPoint.y + chartRaidus;
// float percentage = 360.0f / total * bean.getNum();
float percentage = (bean.getNum()==0?0:(360.0f / total * bean.getNum())*animPre);
bean.setArcRect(new RectF(arcLeft, arcTop, arcRight, arcBottom));
bean.setStartAngle(oneStartAngle);
bean.setSweepAngle(percentage);
/**2、计算扇形区域*/
arcLeft = centerPoint.x - chartSize;
arcTop = centerPoint.y - chartSize;
arcRight = centerPoint.x + chartSize;
arcBottom = centerPoint.y + chartSize;
Path allPath = new Path();
allPath.moveTo(centerPoint.x, centerPoint.y);//添加原始点
float ovalX = centerPoint.x + (float) (chartRaidus * Math.cos(Math.toRadians(oneStartAngle)));
float ovalY = centerPoint.y + (float) (chartRaidus * Math.sin(Math.toRadians(oneStartAngle)));
allPath.lineTo(ovalX, ovalY);
RectF touchOval = new RectF(arcLeft, arcTop, arcRight, arcBottom);
allPath.addArc(touchOval, oneStartAngle, percentage);
allPath.lineTo(centerPoint.x, centerPoint.y);
allPath.close();
RectF r = new RectF();
allPath.computeBounds(r, true);
Region region = new Region();
region.setPath(allPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
bean.setRegion(region);
if(MODUL_CHART == tagModul) {
/**3、绘制直线*/
//确定直线的起始和结束的点的位置
float startX = centerPoint.x + (float) (chartRaidus * Math.cos(Math.toRadians(oneStartAngle + percentage / 2)));
float startY = centerPoint.y + (float) (chartRaidus * Math.sin(Math.toRadians(oneStartAngle + percentage / 2)));
float endX = centerPoint.x + (float) ((chartRaidus + lineLenth - 20) * Math.cos(Math.toRadians(oneStartAngle + percentage / 2)));
float endY = centerPoint.y + (float) ((chartRaidus + lineLenth - 20) * Math.sin(Math.toRadians(oneStartAngle + percentage / 2)));
boolean isRight = true;
float lineAngle = oneStartAngle + percentage / 2;
if (lineAngle > 90 && lineAngle < 270) {
isRight = false;
}
// LogUtil.i(TAG, "直线坐标:start=("+startX+","+startY +") end=("+endX+","+endY+")"+" lineAngle="+lineAngle+" isRight="+isRight);
List<PointF> tagLinePoints = new ArrayList<>();
tagLinePoints.add(new PointF(startX, startY));
tagLinePoints.add(new PointF(endX, endY));
float textX = isRight ? (endX + 20) : (endX - 20);
tagLinePoints.add(new PointF(textX, endY));
bean.setTagLinePoints(tagLinePoints);
/**3、绘制指示标签*/
String tagText = "";
paintLabel.setTextSize(tagTextSize);
if (tagType == PieChartLayout.TAG_TYPE.TYPE_NUM) {
tagText = bean.getNum() + "";
} else if (tagType == PieChartLayout.TAG_TYPE.TYPE_PERCENT) {
DecimalFormat decimalFormat = new DecimalFormat("0.0%");
tagText = (total==0?"/":decimalFormat.format(((float) bean.getNum() / (float) total)));
}
float textW = FontUtil.getFontlength(paintLabel, tagText);
textX = isRight ? textX + textSpace : (textX - textW - textSpace);
float textY = endY - tagTextHeight / 2 + tagTextLead;
bean.setTagStr(tagText);
bean.setTagTextPoint(new PointF(textX, textY));
}
/*开始角度累加*/
oneStartAngle += percentage;
}
}
@Override
public void addArc(Path path, float left, float top, float right, float bottom,
float startAngle, float sweepAngle) {
path.addArc(left, top, right, bottom, startAngle, sweepAngle);
}
private static void drawArc(Path path, double x0, double y0, double x, double y, double rx,
double ry, double angle, boolean largeArcFlag, boolean sweepFlag) {
double dx2 = (x0 - x) / 2.0;
double dy2 = (y0 - y) / 2.0;
angle = Math.toRadians(angle % 360.0);
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
double x1 = (cosAngle * dx2 + sinAngle * dy2);
double y1 = (-sinAngle * dx2 + cosAngle * dy2);
rx = Math.abs(rx);
ry = Math.abs(ry);
double Prx = rx * rx;
double Pry = ry * ry;
double Px1 = x1 * x1;
double Py1 = y1 * y1;
// check that radii are large enough
double radiiCheck = Px1 / Prx + Py1 / Pry;
if (radiiCheck > 1) {
rx = Math.sqrt(radiiCheck) * rx;
ry = Math.sqrt(radiiCheck) * ry;
Prx = rx * rx;
Pry = ry * ry;
}
// Step 2 : Compute (cx1, cy1)
double sign = (largeArcFlag == sweepFlag) ? -1 : 1;
double sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1))
/ ((Prx * Py1) + (Pry * Px1));
sq = (sq < 0) ? 0 : sq;
double coef = (sign * Math.sqrt(sq));
double cx1 = coef * ((rx * y1) / ry);
double cy1 = coef * -((ry * x1) / rx);
double sx2 = (x0 + x) / 2.0;
double sy2 = (y0 + y) / 2.0;
double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);
// Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
double ux = (x1 - cx1) / rx;
double uy = (y1 - cy1) / ry;
double vx = (-x1 - cx1) / rx;
double vy = (-y1 - cy1) / ry;
double p, n;
// Compute the angle start
n = Math.sqrt((ux * ux) + (uy * uy));
p = ux; // (1 * ux) + (0 * uy)
sign = (uy < 0) ? -1.0 : 1.0;
double angleStart = Math.toDegrees(sign * Math.acos(p / n));
// Compute the angle extent
n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
p = ux * vx + uy * vy;
sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
double angleExtent = Math.toDegrees(sign * Math.acos(p / n));
if (!sweepFlag && angleExtent > 0) {
angleExtent -= 360f;
} else if (sweepFlag && angleExtent < 0) {
angleExtent += 360f;
}
angleExtent %= 360f;
angleStart %= 360f;
RectF oval = new RectF((float) (cx - rx), (float) (cy - ry), (float) (cx + rx), (float) (cy + ry));
path.addArc(oval, (float) angleStart, (float) angleExtent);
}