Here are the examples of the java api android.graphics.PathMeasure taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
175 Examples
19
Source : CircularSeekBar.java
with Apache License 2.0
from vpaliy
with Apache License 2.0
from vpaliy
private void calculatePointerXYPosition() {
PathMeasure pm = new PathMeasure(mCircleProgressPath, false);
boolean returnValue = pm.getPosTan(pm.getLength(), mPointerPositionXY, null);
if (!returnValue) {
pm = new PathMeasure(mCirclePath, false);
returnValue = pm.getPosTan(0, mPointerPositionXY, null);
}
}
19
Source : CubeLoadingView.java
with MIT License
from thunderpunch
with MIT License
from thunderpunch
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
final int horizontalSpace = w - getPaddingLeft() - getPaddingRight();
final int verticalSpace = h - getPaddingTop() - getPaddingBottom();
int[] tempSize = calculateSizeByHorizontalSpace(getMinimumHorizontalSpace());
if (horizontalSpace < tempSize[0] || verticalSpace < tempSize[1]) {
// 给到空间小于所需最小宽高则按最小宽高计算
} else {
tempSize = calculateSizeByVerticalSpace(verticalSpace);
if (tempSize[0] > horizontalSpace) {
tempSize = calculateSizeByHorizontalSpace(horizontalSpace);
}
}
mCubeLength = tempSize[2];
mOrigin.x = (w - tempSize[0]) / 2;
mOrigin.y = (h - tempSize[1]) / 2;
final int diagonalHorizontal = (int) (2 * mCubeLength * Math.sin(Math.toRadians(DEGREE)));
final int diagonalVertical = (int) (2 * mCubeLength * Math.cos(Math.toRadians(DEGREE)));
mPath = new Path();
mPath.moveTo(diagonalHorizontal, 0);
mPath.lineTo(2 * diagonalHorizontal, diagonalVertical);
mPath.lineTo(diagonalHorizontal * 3 / 2, diagonalVertical * 3 / 2);
mPath.lineTo(diagonalHorizontal / 2, diagonalVertical / 2);
mPath.close();
PathMeasure pathMeasure = new PathMeasure(mPath, false);
mCubes.clear();
for (int i = 0; i < 4; i++) {
mCubes.add(new Cube((1.0f / 4) * i, pathMeasure, diagonalHorizontal, diagonalVertical, mCubeLength));
}
}
19
Source : CircularSeekBar.java
with Apache License 2.0
from RajneeshSingh007
with Apache License 2.0
from RajneeshSingh007
protected void calculatePointerXYPosition() {
PathMeasure pm = new PathMeasure(mCircleProgressPath, false);
boolean returnValue = pm.getPosTan(pm.getLength(), mPointerPositionXY, null);
if (!returnValue) {
pm = new PathMeasure(mCirclePath, false);
returnValue = pm.getPosTan(0, mPointerPositionXY, null);
}
}
19
Source : MusicAnimBean.java
with GNU Affero General Public License v3.0
from qwsem
with GNU Affero General Public License v3.0
from qwsem
public void setPathMeasure(PathMeasure pathMeasure) {
mPathMeasure = pathMeasure;
}
19
Source : PathModel.java
with GNU General Public License v3.0
from MrIkso
with GNU General Public License v3.0
from MrIkso
public void trimPath() {
if (scaleMatrix != null) {
if (trimPathStart == 0 && trimPathEnd == 1 && trimPathOffset == 0) {
path = new Path(originalPath);
path.transform(scaleMatrix);
} else {
PathMeasure pathMeasure = new PathMeasure(originalPath, false);
float length = pathMeasure.getLength();
trimmedPath = new Path();
pathMeasure.getSegment((trimPathStart + trimPathOffset) * length, (trimPathEnd + trimPathOffset) * length, trimmedPath, true);
path = new Path(trimmedPath);
path.transform(scaleMatrix);
}
}
}
19
Source : EditGraphView.java
with MIT License
from jsuyash1514
with MIT License
from jsuyash1514
private void calcPoints() {
PathMeasure pathMeasure = new PathMeasure(mPath, false);
float[] pos = new float[2];
float[] tan = new float[2];
points_On_Graph = new ArrayList<>();
normalized_points = new ArrayList<>();
for (int i = 0; i <= pathMeasure.getLength(); i++) {
pathMeasure.getPosTan(i, pos, tan);
points_On_Graph.add(new PointF(pos[0], pos[1]));
normalized_points.add(new PointF(pos[0] / (vW - 100.0f), 1.0f - (pos[1] / vH)));
}
}
19
Source : ArrowDrawable.java
with Apache License 2.0
from Ifxcyr
with Apache License 2.0
from Ifxcyr
/**
* 分解Path
*
* @return Path上的全部坐标点
*/
private float[] decomposePath(PathMeasure pathMeasure) {
if (pathMeasure.getLength() == 0) {
return new float[0];
}
final float pathLength = pathMeasure.getLength();
int numPoints = (int) (pathLength / mPrecision) + 1;
float[] points = new float[numPoints * 2];
final float[] position = new float[2];
int index = 0;
float distance;
for (int i = 0; i < numPoints; ++i) {
distance = (i * pathLength) / (numPoints - 1);
pathMeasure.getPosTan(distance, position, null);
points[index] = position[0];
points[index + 1] = position[1];
index += 2;
}
return points;
}
19
Source : FloatAnimation.java
with Apache License 2.0
from hexingbo
with Apache License 2.0
from hexingbo
/**
* @author Vondear
* @date 2018/6/19
*/
public clreplaced FloatAnimation extends Animation {
private PathMeasure mPm;
private View mView;
private float mDistance;
private float mRotation;
public FloatAnimation(Path path, float rotation, View parent, View child) {
mPm = new PathMeasure(path, false);
mDistance = mPm.getLength();
mView = child;
mRotation = rotation;
parent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
private static float scale(double a, double b, double c, double d, double e) {
return (float) ((a - b) / (c - b) * (e - d) + d);
}
@Override
protected void applyTransformation(float factor, Transformation transformation) {
Matrix matrix = transformation.getMatrix();
mPm.getMatrix(mDistance * factor, matrix, PathMeasure.POSITION_MATRIX_FLAG);
mView.setRotation(mRotation * factor);
float scale = 1F;
if (3000.0F * factor < 200.0F) {
scale = scale(factor, 0.0D, 0.06666667014360428D, 0.20000000298023224D, 1.100000023841858D);
} else if (3000.0F * factor < 300.0F) {
scale = scale(factor, 0.06666667014360428D, 0.10000000149011612D, 1.100000023841858D, 1.0D);
}
mView.setScaleX(scale);
mView.setScaleY(scale);
transformation.setAlpha(1.0F - factor);
}
}
19
Source : FloatAnimation.java
with Apache License 2.0
from Geekince
with Apache License 2.0
from Geekince
public clreplaced FloatAnimation extends Animation {
private PathMeasure mPm;
private View mView;
private float mDistance;
private float mRotation;
public FloatAnimation(Path path, float rotation, View parent, View child) {
mPm = new PathMeasure(path, false);
mDistance = mPm.getLength();
mView = child;
mRotation = rotation;
parent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
@Override
protected void applyTransformation(float factor, Transformation transformation) {
Matrix matrix = transformation.getMatrix();
mPm.getMatrix(mDistance * factor, matrix, PathMeasure.POSITION_MATRIX_FLAG);
mView.setRotation(mRotation * factor);
float scale = 1F;
if (3000.0F * factor < 200.0F) {
scale = scale(factor, 0.0D, 0.066D, 0.2D, 1.1D);
} else if (3000.0F * factor < 300.0F) {
scale = scale(factor, 0.066D, 0.1D, 1.1D, 1.0D);
}
mView.setScaleX(scale);
mView.setScaleY(scale);
transformation.setAlpha(1.0F - factor);
}
private float scale(double a, double b, double c, double d, double e) {
return (float) ((a - b) / (c - b) * (e - d) + d);
}
}
19
Source : Smoke.java
with MIT License
from florent37
with MIT License
from florent37
private void matchVertsToPath(float wind) {
PathMeasure pm = new PathMeasure(smokePath, false);
for (int i = 0; i < staticVerts.length / 2; i++) {
float yIndexValue = staticVerts[i * 2 + 1];
float xIndexValue = staticVerts[i * 2];
float percentOffsetY = (0.000001f + yIndexValue) / bitmap.getHeight();
float percentOffsetY2 = (0.000001f + yIndexValue) / (bitmap.getHeight() + ((bitmap.getHeight() / numberOfTurns) * 4f));
percentOffsetY2 += pathPointOffset;
pm.getPosTan(pm.getLength() * (1f - percentOffsetY), coords, null);
pm.getPosTan(pm.getLength() * (1f - percentOffsetY2), coords2, null);
if (xIndexValue == 0) {
float desiredXCoord = coords2[0] - (bitmap.getWidth()) / 2;
desiredXCoord -= (desiredXCoord - x) * percentOffsetY;
desiredXCoord += (wind / 3f) * density + ((wind * WIND_SENSITIVITY) * (1f - smokeExponentionWindStuff.getInterpolation(percentOffsetY)));
setXY(drawingVerts, i, desiredXCoord, coords[1]);
} else {
float desiredXCoord = coords2[0] + (bitmap.getWidth()) / 2;
desiredXCoord -= (desiredXCoord - x) * percentOffsetY;
desiredXCoord += (wind / 3f) * density + ((wind * WIND_SENSITIVITY) * (1f - smokeExponentionWindStuff.getInterpolation(percentOffsetY)));
setXY(drawingVerts, i, desiredXCoord, coords[1]);
}
}
}
19
Source : RenderableThree.java
with MIT License
from florent37
with MIT License
from florent37
private void matchVertsToPath() {
PathMeasure pmLeft = new PathMeasure(pathLeft, false);
PathMeasure pmRight = new PathMeasure(pathRight, false);
float[] coords = new float[2];
for (int i = 0; i < staticVerts.length / 2; i++) {
float yIndexValue = staticVerts[i * 2 + 1];
float xIndexValue = staticVerts[i * 2];
if (xIndexValue == 0) {
float percentOffsetY = (0.000001f + yIndexValue) / bitmap.getHeight();
pmLeft.getPosTan(pmLeft.getLength() * (1f - percentOffsetY), coords, null);
setXY(drawingVerts, i, coords[0], coords[1]);
} else {
float percentOffsetY = (0.000001f + yIndexValue) / bitmap.getHeight();
pmRight.getPosTan(pmRight.getLength() * (1f - percentOffsetY), coords, null);
setXY(drawingVerts, i, coords[0], coords[1]);
}
}
}
19
Source : AnimationRouteHelper.java
with MIT License
from amalChandran
with MIT License
from amalChandran
@Override
public void onPathMeasureChange() {
PathMeasure pathMeasure = new PathMeasure(overlayPolyline.getDrawPath(), false);
length = pathMeasure.getLength();
dashValue = new float[] { length, length };
}
19
Source : AnimationArcHelper.java
with MIT License
from amalChandran
with MIT License
from amalChandran
@Override
public void onPathMeasureChange() {
PathMeasure pathMeasure = new PathMeasure(overlayPolyline.getDrawPath(), false);
arcLength = pathMeasure.getLength();
arcdDashValue = new float[] { arcLength, arcLength };
}
18
Source : StairsPathBuilder.java
with MIT License
from zyao89
with MIT License
from zyao89
/**
* Created by zyao89 on 2018/3/10.
* Contact me at [email protected] or [email protected]
* For more projects: https://github.com/zyao89
* My Blog: https://zyao89.cn
*/
public clreplaced StairsPathBuilder extends BaseStateBuilder {
private final int FLOOR_NUM = 6;
private Paint mPaint;
private float mR;
private Path mPath;
private Path mPathFinal;
private PathMeasure mPathMeasure;
private Path mDrawPath;
@Override
protected int getStateCount() {
return 3;
}
@Override
protected void initParams(Context context, Paint paint) {
mPaint = paint;
mR = getAllSize();
initPathMeasure();
initPaths();
}
private void initPaths() {
mPath = new Path();
float space = mR * 2 / FLOOR_NUM;
float startXP = getViewCenterX() - mR;
float startYP = getViewCenterY() + mR;
mPath.moveTo(startXP, startYP);
for (int i = 0; i < FLOOR_NUM; i++) {
mPath.lineTo((i) * space + startXP, startYP - space * (i + 1));
mPath.lineTo((i + 1) * space + startXP, startYP - space * (i + 1));
}
mPathFinal = new Path(mPath);
mPathFinal.lineTo((FLOOR_NUM) * space + startXP, startYP);
mPathFinal.lineTo(startXP, startYP);
}
private void initPathMeasure() {
mDrawPath = new Path();
mPathMeasure = new PathMeasure();
}
@Override
protected void onComputeUpdateValue(ValueAnimator animation, float animatedValue, int state) {
switch(state) {
case 0:
case 1:
resetDrawPath();
mPathMeasure.setPath(mPath, false);
float stop = mPathMeasure.getLength() * animatedValue;
float start = (float) (stop - ((0.5 - Math.abs(animatedValue - 0.5)) * 200f));
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
case 2:
resetDrawPath();
mPathMeasure.setPath(mPathFinal, false);
stop = mPathMeasure.getLength() * animatedValue;
start = 0;
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
case 3:
resetDrawPath();
mPathMeasure.setPath(mPathFinal, false);
stop = mPathMeasure.getLength() * (1 - animatedValue);
start = 0;
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
default:
break;
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mDrawPath, mPaint);
}
@Override
protected void prepareStart(ValueAnimator valueAnimator) {
valueAnimator.setInterpolator(new DecelerateInterpolator());
}
@Override
protected void prepareEnd() {
}
private void resetDrawPath() {
mDrawPath.reset();
mDrawPath.lineTo(0, 0);
}
}
18
Source : SearchPathBuilder.java
with MIT License
from zyao89
with MIT License
from zyao89
/**
* Created by zyao89 on 2017/4/11.
* Contact me at [email protected] or [email protected]
* For more projects: https://github.com/zyao89
* My Blog: http://zyao89.me
*/
public clreplaced SearchPathBuilder extends ZLoadingBuilder {
// 最终阶段
private static final int FINAL_STATE = 3;
// 当前动画阶段
private int mCurrAnimatorState = 0;
private float mR;
private Paint mPaint;
private Path mPath;
private Path mPathZoom;
private PathMeasure mPathMeasure;
private Path mDrawPath;
@Override
protected void initParams(Context context) {
mR = getAllSize();
initPaint();
initPathMeasure();
initPaths();
}
private void initPaint() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(15);
mPaint.setColor(Color.BLACK);
mPaint.setDither(true);
mPaint.setFilterBitmap(true);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
}
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 initPathMeasure() {
mDrawPath = new Path();
mPathMeasure = new PathMeasure();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mDrawPath, mPaint);
}
@Override
protected void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
protected void prepareStart(ValueAnimator floatValueAnimator) {
floatValueAnimator.setInterpolator(new DecelerateInterpolator());
}
@Override
protected void prepareEnd() {
}
@Override
protected void computeUpdateValue(ValueAnimator animation, @FloatRange(from = 0.0, to = 1.0) float animatedValue) {
switch(mCurrAnimatorState) {
case 0:
case 1:
resetDrawPath();
mPathMeasure.setPath(mPath, false);
float stop = mPathMeasure.getLength() * animatedValue;
float start = (float) (stop - ((0.5 - Math.abs(animatedValue - 0.5)) * 200f));
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
case 2:
resetDrawPath();
mPathMeasure.setPath(mPath, false);
stop = mPathMeasure.getLength() * animatedValue;
start = 0;
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
case 3:
mPathMeasure.setPath(mPathZoom, false);
stop = mPathMeasure.getLength();
start = stop * (1 - animatedValue);
mPathMeasure.getSegment(start, stop, mDrawPath, true);
break;
default:
break;
}
}
@Override
public void onAnimationRepeat(Animator animation) {
if (++mCurrAnimatorState > FINAL_STATE) {
// 还原到第一阶段
mCurrAnimatorState = 0;
}
}
@Override
protected void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
private void resetDrawPath() {
mDrawPath.reset();
// 不知道什么坑
mDrawPath.lineTo(0, 0);
}
}
18
Source : MusicPathBuilder.java
with MIT License
from zyao89
with MIT License
from zyao89
/**
* Created by zyao89 on 2018/3/11.
* Contact me at [email protected] or [email protected]
* For more projects: https://github.com/zyao89
* My Blog: https://zyao89.cn
*/
public clreplaced MusicPathBuilder extends BaseStateBuilder {
private final int MUSIC_LINE_COUNT = 5;
private Paint mPaint;
private float mR;
private LinkedList<Path> mMusicPaths;
private LinkedList<Path> mMusicDrawPaths;
private PathMeasure mPathMeasure;
private LinkedList<MusicParam> mMusicParams;
private boolean mOpenJump = false;
private DecelerateInterpolator mDecelerateInterpolator;
private BounceInterpolator mBounceInterpolator;
@Override
protected int getStateCount() {
return 3;
}
@Override
protected void initParams(Context context, Paint paint) {
mPaint = paint;
mPaint.setStrokeWidth(2);
mR = getAllSize();
initPaths();
initPathMeasure();
initMusicParams();
initInterpolator();
}
private void initPaths() {
mMusicPaths = new LinkedList<Path>();
// 线长
float lineW = mR * 2;
// 线间距
float space = mR * 2 / MUSIC_LINE_COUNT;
// 起点
float startXP = getViewCenterX() - mR;
float startYP = getViewCenterY() + mR;
// 五线谱
for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
Path path = new Path();
path.moveTo(startXP, startYP - (i * space));
path.lineTo(startXP + lineW, startYP - (i * space));
mMusicPaths.add(path);
}
}
private void initPathMeasure() {
mMusicDrawPaths = new LinkedList<>();
// 五线谱
for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
Path drawPath = new Path();
mMusicDrawPaths.add(drawPath);
}
mPathMeasure = new PathMeasure();
}
private void initMusicParams() {
float musicWidth = mR * 0.2f;
float musicHeight = mR;
mMusicParams = new LinkedList<>();
float musicPointHeight = mR * 2 / MUSIC_LINE_COUNT;
float left = getViewCenterX() - musicWidth / 2;
float right = getViewCenterX() + musicWidth / 2;
float top = getViewCenterY() + musicHeight - musicPointHeight * 1.5f;
float bottom = getViewCenterY() + musicHeight - musicPointHeight * 0.5f;
RectF rectF = new RectF(left - mR * 0.5f, top, right - mR * 0.5f, bottom);
float offsetX = (float) (musicWidth * 0.5 * Math.cos(75));
PointF sPointF = new PointF(rectF.right + offsetX, rectF.centerY());
PointF ePointF = new PointF(rectF.right + offsetX, rectF.centerY() - musicHeight);
MusicParam musicParam = new MusicParam(rectF, sPointF, ePointF);
mMusicParams.add(musicParam);
rectF = new RectF(left + mR * 0.5f, top - musicPointHeight, right + mR * 0.5f, bottom - musicPointHeight);
offsetX = (float) (musicWidth * 0.5 * Math.cos(75));
sPointF = new PointF(rectF.right + offsetX, rectF.centerY());
ePointF = new PointF(rectF.right + offsetX, rectF.centerY() - musicHeight);
musicParam = new MusicParam(rectF, sPointF, ePointF);
mMusicParams.add(musicParam);
}
private void initInterpolator() {
mDecelerateInterpolator = new DecelerateInterpolator();
mBounceInterpolator = new BounceInterpolator();
}
@Override
protected void onComputeUpdateValue(ValueAnimator animation, float animatedValue, int state) {
switch(state) {
case 0:
animation.setInterpolator(mDecelerateInterpolator);
resetDrawPath();
for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
mPathMeasure.setPath(mMusicPaths.get(i), false);
if (i % 2 == 0) {
float stop = mPathMeasure.getLength() * animatedValue;
float start = (float) (stop - ((0.5 - Math.abs(animatedValue - 0.5)) * 200f));
mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
} else {
float stop = mPathMeasure.getLength() * (1 - animatedValue);
float start = (float) (stop - ((0.5 - Math.abs((1 - animatedValue) - 0.5)) * 200f));
mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
}
}
break;
case 1:
resetDrawPath();
for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
mPathMeasure.setPath(mMusicPaths.get(i), false);
if (i % 2 == 0) {
float stop = mPathMeasure.getLength() * animatedValue;
float start = 0;
mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
} else {
float stop = mPathMeasure.getLength();
float start = mPathMeasure.getLength() * (1 - animatedValue);
mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
}
}
break;
case 2:
animation.setInterpolator(mBounceInterpolator);
// jump
mOpenJump = true;
// 线间距
float space = mR * 2 / MUSIC_LINE_COUNT;
for (int i = 0; i < mMusicParams.size(); i++) {
MusicParam musicParam = mMusicParams.get(i);
if (i % 2 == 0) {
musicParam.setOffsetY(animatedValue * space);
} else {
musicParam.setOffsetY((1 - animatedValue) * space);
}
}
break;
case 3:
// jump
mOpenJump = true;
// 线间距
space = mR * 2 / MUSIC_LINE_COUNT;
for (int i = 0; i < mMusicParams.size(); i++) {
MusicParam musicParam = mMusicParams.get(i);
if (i % 2 == 0) {
musicParam.setOffsetY((1 - animatedValue) * space);
} else {
musicParam.setOffsetY(animatedValue * space);
}
}
break;
default:
break;
}
}
@Override
protected void onDraw(Canvas canvas) {
for (Path drawPath : mMusicDrawPaths) {
canvas.drawPath(drawPath, mPaint);
}
if (mOpenJump) {
drawMusic(canvas);
}
}
private void drawMusic(Canvas canvas) {
for (MusicParam musicParam : mMusicParams) {
mPaint.setStrokeWidth(4);
canvas.save();
RectF oldCircleRectF = musicParam.getCircleRectF();
RectF circleRectF = new RectF(oldCircleRectF);
float offsetY = musicParam.getOffsetY();
circleRectF.set(oldCircleRectF.left, oldCircleRectF.top - offsetY, oldCircleRectF.right, oldCircleRectF.bottom - offsetY);
canvas.rotate(75, circleRectF.centerX(), circleRectF.centerY());
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawOval(circleRectF, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
canvas.restore();
PointF startPointF = musicParam.getLineStartPointF();
PointF endPointF = musicParam.getLineEndPointF();
canvas.drawLine(startPointF.x, startPointF.y - offsetY, endPointF.x, endPointF.y - offsetY, mPaint);
mPaint.setStrokeWidth(2);
}
}
@Override
protected void prepareStart(ValueAnimator animation) {
animation.setInterpolator(mDecelerateInterpolator);
}
@Override
protected void prepareEnd() {
}
private void resetDrawPath() {
mOpenJump = false;
for (Path path : mMusicDrawPaths) {
path.reset();
path.lineTo(0, 0);
}
for (MusicParam musicParam : mMusicParams) {
musicParam.clear();
}
}
static clreplaced MusicParam {
private final RectF mCircleRectF;
private final PointF mLineStartPointF;
private final PointF mLineEndPointF;
private float mOffsetY = 0;
MusicParam(RectF rectF, PointF sPointF, PointF ePointF) {
mCircleRectF = rectF;
mLineStartPointF = sPointF;
mLineEndPointF = ePointF;
}
RectF getCircleRectF() {
return mCircleRectF;
}
PointF getLineStartPointF() {
return mLineStartPointF;
}
PointF getLineEndPointF() {
return mLineEndPointF;
}
float getOffsetY() {
return mOffsetY;
}
void setOffsetY(float v) {
mOffsetY = v;
}
void clear() {
mOffsetY = 0;
}
}
}
18
Source : PathBitmapMesh.java
with Apache License 2.0
from xujiaji
with Apache License 2.0
from xujiaji
public void matchVertsToPath(Path path, float bottomCoord, float extraOffset) {
PathMeasure pm = new PathMeasure(path, false);
for (int i = 0; i < staticVerts.length / 2; i++) {
float yIndexValue = staticVerts[i * 2 + 1];
float xIndexValue = staticVerts[i * 2];
float percentOffsetX = (0.000001f + xIndexValue) / bitmap.getWidth();
float percentOffsetX2 = (0.000001f + xIndexValue) / (bitmap.getWidth() + extraOffset);
percentOffsetX2 += pathOffsetPercent;
pm.getPosTan(pm.getLength() * (1f - percentOffsetX), coords, null);
pm.getPosTan(pm.getLength() * (1f - percentOffsetX2), coords2, null);
if (yIndexValue == 0) {
setXY(drawingVerts, i, coords[0], coords2[1]);
} else {
float desiredYCoord = bottomCoord;
setXY(drawingVerts, i, coords[0], desiredYCoord);
}
}
}
18
Source : ObjectAnimatorCompatBase.java
with Apache License 2.0
from xuexiangjys
with Apache License 2.0
from xuexiangjys
private static void calculateXYValues(Path path, @Size(NUM_POINTS) float[] xValues, @Size(NUM_POINTS) float[] yValues) {
PathMeasure pathMeasure = new PathMeasure(path, false);
float pathLength = pathMeasure.getLength();
float[] position = new float[2];
for (int i = 0; i < NUM_POINTS; ++i) {
float distance = (i * pathLength) / (NUM_POINTS - 1);
pathMeasure.getPosTan(distance, position, null);
xValues[i] = position[0];
yValues[i] = position[1];
}
}
18
Source : ObjectAnimatorCompatBase.java
with Apache License 2.0
from xuexiangjys
with Apache License 2.0
from xuexiangjys
private static void calculateXYValues(Path path, @Size(NUM_POINTS) int[] xValues, @Size(NUM_POINTS) int[] yValues) {
PathMeasure pathMeasure = new PathMeasure(path, false);
float pathLength = pathMeasure.getLength();
float[] position = new float[2];
for (int i = 0; i < NUM_POINTS; ++i) {
float distance = (i * pathLength) / (NUM_POINTS - 1);
pathMeasure.getPosTan(distance, position, null);
xValues[i] = Math.round(position[0]);
yValues[i] = Math.round(position[1]);
}
}
18
Source : OBAnimPath.java
with Apache License 2.0
from XPRIZE
with Apache License 2.0
from XPRIZE
/**
* OBAnimPath
* Animates an OBControl along a Path.
*
* @see Path
* @see OBControl
* Created by alan on 07/06/16.
*/
public clreplaced OBAnimPath extends OBAnim {
float angleOffset, angleStart;
boolean changeAngle;
Path path;
PathMeasure pathMeasure;
float pathLength;
public OBAnimPath(Object obj, String ky, int ty) {
super(obj, ky, ty);
}
public OBAnimPath(Object obj, Path p, boolean changle, float radians) {
this(obj, "positionAndAngle", ANIM_TYPE_PATH);
path = p;
pathMeasure = new PathMeasure(p, false);
pathLength = pathMeasure.getLength();
changeAngle = changle;
angleOffset = radians;
angleStart = ((OBControl) obj).rotation;
}
public Object valueForT(float t) {
float thisLen = t * pathLength;
float[] pos = { 0, 0 }, ftan = { 0, 0 };
pathMeasure.getPosTan(thisLen, pos, ftan);
PointF vpt = new PointF(pos[0], pos[1]);
if (changeAngle) {
float radians = (float) Math.atan2(ftan[1], ftan[0]);
radians += angleOffset;
return Arrays.asList(vpt, radians);
}
return Arrays.asList(vpt, angleStart);
}
}
18
Source : OBShapeLayer.java
with Apache License 2.0
from XPRIZE
with Apache License 2.0
from XPRIZE
/**
* Created by alan on 21/04/16.
*/
public clreplaced OBShapeLayer extends OBLayer {
public Path path;
public Paint fillPaint, strokePaint;
public OBStroke stroke;
public int fillColour;
public float currX, currY;
float strokeStart, strokeEnd;
PathMeasure pathMeasure;
public OBShapeLayer() {
super();
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fillPaint.setStyle(Paint.Style.FILL);
strokePaint.setStyle(Paint.Style.STROKE);
opacity = 1;
stroke = new OBStroke();
strokeStart = 0;
strokeEnd = 1;
}
public OBShapeLayer(Path p) {
this();
if (p == null)
path = new Path();
else
path = p;
}
@Override
public OBLayer copy() {
OBShapeLayer obj = (OBShapeLayer) super.copy();
obj.path = new Path(path);
obj.fillPaint = new Paint(fillPaint);
obj.strokePaint = new Paint(strokePaint);
obj.stroke = stroke.copy();
obj.fillColour = fillColour;
obj.strokeStart = strokeStart;
obj.strokeEnd = strokeEnd;
obj.currX = currX;
obj.currY = currY;
return obj;
}
@Override
public void draw(Canvas canvas) {
if (path != null) {
setUpPaint();
if (fillColour != 0)
canvas.drawPath(path, fillPaint);
if (stroke != null)
canvas.drawPath(path, strokePaint);
}
}
public void setUpPaint() {
if (stroke != null) {
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint.setStrokeWidth(stroke.lineWidth);
// int col = OBUtils.applyColourOpacity(stroke.colour,opacity);
strokePaint.setColor(stroke.colour);
strokePaint.setStrokeCap(stroke.paintLineCap());
strokePaint.setStrokeJoin(stroke.paintLineJoin());
DashPathEffect dpe = stroke.dashPathEffect();
if (dpe == null)
strokePaint.setPathEffect(null);
else
strokePaint.setPathEffect(dpe);
strokePaint.setStyle(Paint.Style.STROKE);
if (colourFilter == null)
strokePaint.setColorFilter(null);
else
strokePaint.setColorFilter(colourFilter);
}
if (fillColour != 0) {
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// int col = OBUtils.applyColourOpacity(fillColour,opacity);
fillPaint.setColor(fillColour);
// fillPaint.setMaskFilter(new BlurMaskFilter(7, BlurMaskFilter.Blur.NORMAL));
fillPaint.setStyle(Paint.Style.FILL);
if (colourFilter == null)
fillPaint.setColorFilter(null);
else
fillPaint.setColorFilter(colourFilter);
}
}
public PathMeasure pathMeasure() {
if (pathMeasure == null)
pathMeasure = new PathMeasure(path, false);
return pathMeasure;
}
public float length() {
return pathMeasure().getLength();
}
public float strokeEnd() {
return strokeEnd;
}
public void setStrokeEnd(float f) {
strokeEnd = OB_Maths.clamp01(f);
setupStrokeDashes();
}
public void setStrokeStart(float f) {
strokeStart = OB_Maths.clamp01(f);
setupStrokeDashes();
}
private void setupStrokeDashes() {
float len = length();
if (strokeEnd < 1 || strokeStart > 0) {
List<Float> lst = new ArrayList<>(4);
lst.add(0f);
lst.add(strokeStart * len);
lst.add(OB_Maths.clamp01(strokeEnd - strokeStart) * len);
lst.add(32767f);
stroke.setDashes(lst);
} else
stroke.setDashes(null);
}
public void moveToPoint(float x, float y) {
path.moveTo(currX = x, currY = y);
}
public void addLineToPoint(float x, float y) {
path.lineTo(currX = x, currY = y);
}
}
18
Source : CustomStatusView.java
with GNU General Public License v3.0
from xmmmmmovo
with GNU General Public License v3.0
from xmmmmmovo
/**
*/
public clreplaced CustomStatusView extends View {
// 进度颜色
private int progressColor;
// 成功的颜色
private int loadSuccessColor;
// 失败的颜色
private int loadFailureColor;
// 进度宽度
private float progressWidth;
// 圆环半径
private float progressRadius;
private Paint mPaint;
// 状态
private StatusEnum mStatus;
private int startAngle = -90;
private int minAngle = -90;
private int sweepAngle = 120;
private int curAngle = 0;
// 追踪Path的坐标
private PathMeasure mPathMeasure;
// 画圆的Path
private Path mPathCircle;
// 截取PathMeasure中的path
private Path mPathCircleDst;
private Path successPath;
private Path failurePathLeft;
private Path failurePathRight;
private ValueAnimator circleAnimator;
private float circleValue;
private float successValue;
private float failValueRight;
private float failValueLeft;
public CustomStatusView(Context context) {
this(context, null);
}
public CustomStatusView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomStatusView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomStatusView, defStyleAttr, 0);
progressColor = array.getColor(R.styleable.CustomStatusView_progress_color, ContextCompat.getColor(context, R.color.colorPrimary));
loadSuccessColor = array.getColor(R.styleable.CustomStatusView_load_success_color, ContextCompat.getColor(context, R.color.load_success));
loadFailureColor = array.getColor(R.styleable.CustomStatusView_load_failure_color, ContextCompat.getColor(context, R.color.load_failure));
progressWidth = array.getDimension(R.styleable.CustomStatusView_progress_width, 6);
progressRadius = array.getDimension(R.styleable.CustomStatusView_progress_radius, 100);
array.recycle();
initPaint();
initPath();
initAnim();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(progressColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(progressWidth);
// 设置画笔为圆角笔触
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
private void initPath() {
mPathCircle = new Path();
mPathMeasure = new PathMeasure();
mPathCircleDst = new Path();
successPath = new Path();
failurePathLeft = new Path();
failurePathRight = new Path();
}
private void initAnim() {
circleAnimator = ValueAnimator.ofFloat(0, 1);
circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
circleValue = (float) animation.getAnimatedValue();
invalidate();
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 将当前画布的点移到getPaddingLeft,getPaddingTop,后面的操作都以该点作为参照点
canvas.translate(getPaddingLeft(), getPaddingTop());
if (mStatus == StatusEnum.Loading) {
// 正在加载
if (startAngle == minAngle) {
sweepAngle += 6;
}
if (sweepAngle >= 300 || startAngle > minAngle) {
startAngle += 6;
if (sweepAngle > 20) {
sweepAngle -= 6;
}
}
if (startAngle > minAngle + 300) {
startAngle %= 360;
minAngle = startAngle;
sweepAngle = 20;
}
// 旋转的弧长为4
canvas.rotate(curAngle += 4, progressRadius, progressRadius);
canvas.drawArc(new RectF(0, 0, progressRadius * 2, progressRadius * 2), startAngle, sweepAngle, false, mPaint);
invalidate();
} else if (mStatus == StatusEnum.LoadSuccess) {
// 加载成功
mPaint.setColor(loadSuccessColor);
mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, progressRadius, Path.Direction.CW);
mPathMeasure.setPath(mPathCircle, false);
// 截取path并保存到mPathCircleDst中
mPathMeasure.getSegment(0, circleValue * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);
if (circleValue == 1) {
// 表示圆画完了,可以钩了
successPath.moveTo(getWidth() / 8 * 3, getWidth() / 2);
successPath.lineTo(getWidth() / 2, getWidth() / 5 * 3);
successPath.lineTo(getWidth() / 3 * 2, getWidth() / 5 * 2);
mPathMeasure.nextContour();
mPathMeasure.setPath(successPath, false);
mPathMeasure.getSegment(0, successValue * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);
}
} else {
// 加载失败
mPaint.setColor(loadFailureColor);
mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, progressRadius, Path.Direction.CW);
mPathMeasure.setPath(mPathCircle, false);
mPathMeasure.getSegment(0, circleValue * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);
if (circleValue == 1) {
// 表示圆画完了,可以画叉叉的右边部分
failurePathRight.moveTo(getWidth() / 3 * 2, getWidth() / 3);
failurePathRight.lineTo(getWidth() / 3, getWidth() / 3 * 2);
mPathMeasure.nextContour();
mPathMeasure.setPath(failurePathRight, false);
mPathMeasure.getSegment(0, failValueRight * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);
}
if (failValueRight == 1) {
// 表示叉叉的右边部分画完了,可以画叉叉的左边部分
failurePathLeft.moveTo(getWidth() / 3, getWidth() / 3);
failurePathLeft.lineTo(getWidth() / 3 * 2, getWidth() / 3 * 2);
mPathMeasure.nextContour();
mPathMeasure.setPath(failurePathLeft, false);
mPathMeasure.getSegment(0, failValueLeft * mPathMeasure.getLength(), mPathCircleDst, true);
canvas.drawPath(mPathCircleDst, mPaint);
}
}
}
// 重制路径
private void resetPath() {
successValue = 0;
circleValue = 0;
failValueLeft = 0;
failValueRight = 0;
mPathCircle.reset();
mPathCircleDst.reset();
failurePathLeft.reset();
failurePathRight.reset();
successPath.reset();
}
private void setStatus(StatusEnum status) {
mStatus = status;
}
public void loadLoading() {
setStatus(StatusEnum.Loading);
invalidate();
}
public void loadSuccess() {
resetPath();
setStatus(StatusEnum.LoadSuccess);
startSuccessAnim();
}
public void loadFailure() {
resetPath();
setStatus(StatusEnum.LoadFailure);
startFailAnim();
}
private void startSuccessAnim() {
ValueAnimator success = ValueAnimator.ofFloat(0f, 1.0f);
success.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
successValue = (float) animation.getAnimatedValue();
invalidate();
}
});
// 组合动画,一先一后执行
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(success).after(circleAnimator);
animatorSet.setDuration(500);
animatorSet.start();
}
private void startFailAnim() {
ValueAnimator failLeft = ValueAnimator.ofFloat(0f, 1.0f);
failLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
failValueRight = (float) animation.getAnimatedValue();
invalidate();
}
});
ValueAnimator failRight = ValueAnimator.ofFloat(0f, 1.0f);
failRight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
failValueLeft = (float) animation.getAnimatedValue();
invalidate();
}
});
// 组合动画,一先一后执行
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(failLeft).after(circleAnimator).before(failRight);
animatorSet.setDuration(500);
animatorSet.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width;
int height;
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
width = size;
} else {
width = (int) (2 * progressRadius + progressWidth + getPaddingLeft() + getPaddingRight());
}
mode = MeasureSpec.getMode(heightMeasureSpec);
size = MeasureSpec.getSize(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
height = size;
} else {
height = (int) (2 * progressRadius + progressWidth + getPaddingTop() + getPaddingBottom());
}
setMeasuredDimension(width, height);
}
}
18
Source : Brain.java
with GNU General Public License v3.0
from Xipher7934
with GNU General Public License v3.0
from Xipher7934
public synchronized void removeByPath(Path path, float dist) {
PathMeasure pm = new PathMeasure(path, false);
float[] mpl = new float[2];
for (int i = 0; i < pm.getLength(); i = i + 5) {
pm.getPosTan(i, mpl, null);
for (int j = neurons.size() - 1; j >= 0; j--) if (neurons.get(j).distance(mpl) < dist) {
for (int k = axons.size() - 1; k >= 0; k--) if ((axons.get(k).start_distance(neurons.get(j).getLocation()) <= dist) || (axons.get(k).end_distance(neurons.get(j).getLocation()) <= dist))
axons.remove(k);
neurons.remove(j);
}
for (int j = axons.size() - 1; j >= 0; j--) if (axons.get(j).first_contact(mpl, dist / 2) > 0)
axons.remove(j);
}
update_CTM();
}
18
Source : PathKeyframesSupport.java
with GNU General Public License v3.0
from wuyr
with GNU General Public License v3.0
from wuyr
@Override
void init(MyPath path) {
final PathMeasure pathMeasure = new PathMeasure(path, false);
final float pathLength = pathMeasure.getLength();
numPoints = (int) (pathLength / PRECISION) + 1;
mX = new float[numPoints];
mY = new float[numPoints];
final float[] position = new float[2];
for (int i = 0; i < numPoints; ++i) {
final float distance = (i * pathLength) / (numPoints - 1);
pathMeasure.getPosTan(distance, position, null);
mX[i] = position[0];
mY[i] = position[1];
}
mPath = path;
}
18
Source : CheckBox.java
with Apache License 2.0
from wuyinlei
with Apache License 2.0
from wuyinlei
/**
* Created by bigmercu on 16/7/23.
* Email:[email protected]
*/
public clreplaced CheckBox extends View implements Checkable {
private static final String TAG = CheckBox.clreplaced.getSimpleName();
private int hSize = dp2px(15);
private int wSize = dp2px(15);
private int textSize = dp2px(15);
private int wStart = dp2px(1);
private int hStart = dp2px(1);
private int Duration = 300;
private int strokeWidth = dp2px(2);
private int mPaintColor;
private String boxText = "CheckBox";
private Paint mPaint;
private Paint mPaintAfter;
private Paint mPaintText;
private Path mPath;
private Path mDst;
private PathMeasure pathMeasure;
// 用于外圆边框动画
private float pathLenthBorder;
private Path mPathBorder;
private Path mDstBorder;
private PathMeasure pathMeasureBorder;
private float pathLenth;
private int AnimationValue = 255;
private int AnimationValueBorder;
private int AnimationValue1;
private float AnimationValue2;
private float AnimationValue3;
private float AnimationValue4;
private ValueAnimator valueAnimator;
private ValueAnimator valueAnimatorBorder;
private ValueAnimator valueAnimator1;
private ValueAnimator valueAnimator2;
private ValueAnimator valueAnimator3;
private ValueAnimator valueAnimator4;
private float cAnimationValue = 0;
private float cAnimationValue1 = 0;
private int cAnimationValue2 = 255;
private ValueAnimator cValueAnimator;
private ValueAnimator cValueAnimator1;
private ValueAnimator cValueAnimator2;
private boolean checked = false;
private boolean isHook = true;
private boolean isShowBorder = false;
private int mScreenWidth, mSreenHeight;
private OnCheckedChangeListener mOnCheckedChangeListener;
private int redAfter;
private int greenAfter;
private int blueAfter;
private int redBefore;
private int greenBefore;
private int blueBefore;
private boolean isCircle;
public CheckBox(Context context) {
super(context);
}
public CheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
int textColor = 0;
if (attrs != null) {
TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.BBox);
int colorAfter = array.getColor(R.styleable.BBox_color_after, Color.GRAY);
int colorBefore = array.getColor(R.styleable.BBox_color_before, Color.GRAY);
textColor = array.getColor(R.styleable.BBox_text_color, Color.BLUE);
redAfter = (colorAfter & 0xff0000) >> 16;
greenAfter = (colorAfter & 0x00ff00) >> 8;
blueAfter = (colorAfter & 0x0000ff);
redBefore = (colorBefore & 0xff0000) >> 16;
greenBefore = (colorBefore & 0x00ff00) >> 8;
blueBefore = (colorBefore & 0x0000ff);
boxText = array.getString(R.styleable.BBox_check_text);
isHook = array.getInt(R.styleable.BBox_check_style, 1) == 1;
isShowBorder = array.getBoolean(R.styleable.BBox_show_border, false);
isCircle = array.getBoolean(R.styleable.BBox_is_circle_border, true);
if (boxText == null) {
boxText = "CheckBox";
}
array.recycle();
}
mPaint.setStrokeWidth(strokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setDither(true);
mPaintText = new Paint();
if (textColor == 0) {
mPaintText.setColor(Color.WHITE);
} else {
mPaintText.setColor(textColor);
}
// mPaintText.setStrokeWidth(strokeWidth);
mPaintText.setAntiAlias(true);
mPaintText.setStyle(Paint.Style.STROKE);
mPaintText.setTextSize(textSize);
mPaintText.setAntiAlias(true);
mPath = new Path();
mPathBorder = new Path();
pathMeasure = new PathMeasure();
pathMeasureBorder = new PathMeasure();
mPath.addRect(wStart, hStart, wSize + wStart, hSize + hStart, Path.Direction.CW);
pathMeasure.setPath(mPath, true);
pathLenth = pathMeasure.getLength();
mPathBorder.addCircle(wStart + wSize / 2, hStart + hSize / 2, (float) Math.sqrt((wSize / 2) * (wSize / 2) + (hSize / 2) * (hSize / 2)), Path.Direction.CCW);
pathMeasureBorder.setPath(mPathBorder, true);
pathLenthBorder = pathMeasureBorder.getLength();
mDst = new Path();
mDstBorder = new Path();
valueAnimator = ValueAnimator.ofInt(255, 0);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValue = (int) animation.getAnimatedValue();
postInvalidate();
}
});
valueAnimatorBorder = ValueAnimator.ofInt(0, (int) pathLenthBorder);
valueAnimatorBorder.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValueBorder = (int) animation.getAnimatedValue();
}
});
if (isHook) {
valueAnimator1 = ValueAnimator.ofInt(180, 225);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValue1 = (int) animation.getAnimatedValue();
}
});
valueAnimator2 = ValueAnimator.ofFloat(hSize + wSize, wSize * 2 / 5);
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValue2 = (float) animation.getAnimatedValue();
}
});
valueAnimator3 = ValueAnimator.ofFloat(hSize + wSize, hSize + wSize * 2);
valueAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValue3 = (float) animation.getAnimatedValue();
}
});
valueAnimator4 = ValueAnimator.ofFloat((float) 0.0, (float) 0.207555);
valueAnimator4.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
AnimationValue4 = (float) animation.getAnimatedValue();
}
});
} else {
cValueAnimator = ValueAnimator.ofFloat(0, (int) (hSize * 0.4));
cValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
cAnimationValue = (float) animation.getAnimatedValue();
}
});
cValueAnimator1 = ValueAnimator.ofFloat(0, wSize / 2);
cValueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
cAnimationValue1 = (float) animation.getAnimatedValue();
}
});
}
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setChecked(!checked);
}
});
}
public CheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int paddingLeft = getPaddingLeft() + 10;
int paddingRight = getPaddingRight() + 10;
int paddingTop = getPaddingTop() + 10;
int paddingBottom = getPaddingBottom() + 10;
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(2 * strokeWidth + wStart + wSize + 20 + paddingLeft + textSize * boxText.length(), hStart + hSize + paddingTop + paddingBottom + 2 * strokeWidth);
Log.d(TAG, wStart + " " + wSize + " " + textSize * boxText.length() + " " + boxText.length());
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(2 * strokeWidth + wStart + wSize + paddingLeft + 20 + textSize * boxText.length(), widthSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(heightSpecSize, hStart + hSize + paddingTop + paddingBottom + 2 * strokeWidth);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
public void setChecked(boolean set) {
if (checked == set) {
return;
} else {
if (checked) {
animationReverse();
} else {
animationStart();
}
checked = set;
}
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onChange(checked);
}
postInvalidate();
}
public boolean isChecked() {
return checked;
}
@Override
public void toggle() {
setChecked(!checked);
}
public void setText(String text) {
boxText = text;
postInvalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mScreenWidth = w;
mSreenHeight = h;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
mDstBorder.reset();
mDstBorder.lineTo(0, 0);
mDst.lineTo(0, 0);
int paddingLeft = getPaddingLeft() + 10;
int paddingRight = getPaddingRight() + 10;
int paddingTop = getPaddingTop() + 10;
int paddingBottom = getPaddingBottom() + 10;
int r = (int) ((1 - (float) AnimationValue / 255) * redBefore + (float) AnimationValue / 255 * redAfter);
int g = (int) ((1 - (float) AnimationValue / 255) * greenBefore + (float) AnimationValue / 255 * greenAfter);
int b = (int) ((1 - (float) AnimationValue / 255) * blueBefore + (float) AnimationValue / 255 * blueAfter);
mPaintColor = Color.rgb(r, g, b);
mPaint.setColor(mPaintColor);
if (isHook) {
canvas.translate(wStart + paddingLeft, hStart + paddingTop);
if (isShowBorder) {
canvas.save();
}
canvas.drawText(boxText, wStart + wSize + 18, (hSize + textSize) / 2, mPaintText);
// 确保图形在正中
canvas.translate(-AnimationValue4 * wSize, (float) (-AnimationValue4 * hSize * 1.5));
/**
* 如果 startWithMoveTo 为 true, 则被截取出来到Path片段保持原状,如果 startWithMoveTo 为 false,
* 则会将截取出来的 Path 片段的起始点移动到 dst 的最后一个点,以保证 dst 的连续性。
*/
pathMeasure.getSegment(AnimationValue3, pathLenth, mDst, true);
pathMeasure.getSegment(0, wSize * 2 / 5, mDst, true);
pathMeasure.getSegment(wSize * 2 / 5, AnimationValue2, mDst, true);
canvas.rotate(AnimationValue1, wStart + wSize / 2, hStart + hSize / 2);
canvas.drawPath(mDst, mPaint);
if (isShowBorder) {
canvas.restore();
if (isCircle) {
pathMeasureBorder.getSegment(0, AnimationValueBorder, mDstBorder, true);
canvas.drawPath(mDstBorder, mPaintText);
} else {
canvas.drawRect(wStart, hStart, wStart + wSize, hSize + hStart, mPaintText);
}
}
} else {
canvas.translate(wStart + paddingLeft, hStart + paddingTop);
if (isShowBorder) {
canvas.save();
}
canvas.drawText(boxText, wStart + wSize + 18, (hSize + textSize) / 2, mPaintText);
mDst.moveTo((float) (wStart + cAnimationValue * 0.3), (float) (hStart + cAnimationValue * 0.3));
mDst.lineTo(wStart + wSize / 2, (float) (hStart + cAnimationValue + cAnimationValue * 0.2));
mDst.lineTo((float) (wStart + wSize - cAnimationValue * 0.2), (float) (hStart + cAnimationValue * 0.2));
mDst.lineTo((float) (wStart + wSize - cAnimationValue - cAnimationValue * 0.2), hSize / 2 + hStart);
mDst.lineTo((float) (wStart + wSize - cAnimationValue * 0.2), (float) (hStart + hSize - cAnimationValue * 0.2));
mDst.lineTo(wStart + wSize / 2, (float) (hStart + hSize - cAnimationValue - cAnimationValue * 0.2));
mDst.lineTo((float) (wStart + cAnimationValue * 0.2), (float) (hStart + hSize - cAnimationValue * 0.2));
mDst.lineTo((float) (wStart + cAnimationValue + cAnimationValue * 0.2), hStart + hSize / 2);
mDst.lineTo((float) (wStart + cAnimationValue * 0.3), (float) (hStart + cAnimationValue * 0.3));
canvas.drawPath(mDst, mPaint);
if (isShowBorder) {
canvas.restore();
if (isCircle) {
pathMeasureBorder.getSegment(0, AnimationValueBorder, mDstBorder, true);
canvas.drawPath(mDstBorder, mPaintText);
} else {
canvas.drawRect(wStart, hStart, wStart + wSize, hSize + hStart, mPaintText);
}
}
}
}
private void animationStart() {
if (isHook) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(valueAnimator1, valueAnimator2, valueAnimator3, valueAnimator4, valueAnimatorBorder, valueAnimator);
animatorSet.setInterpolator(new DecelerateInterpolator());
valueAnimatorBorder.setInterpolator(new AccelerateInterpolator());
animatorSet.setDuration(Duration);
animatorSet.start();
} else {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(cValueAnimator, cValueAnimator1, valueAnimatorBorder, valueAnimator);
animatorSet.setInterpolator(new DecelerateInterpolator());
valueAnimatorBorder.setInterpolator(new AccelerateInterpolator());
animatorSet.setDuration(Duration);
animatorSet.start();
}
}
private void animationReverse() {
if (isHook) {
valueAnimator1.reverse();
valueAnimator2.reverse();
valueAnimator3.reverse();
valueAnimator4.reverse();
} else {
cValueAnimator.reverse();
cValueAnimator1.reverse();
}
valueAnimatorBorder.reverse();
valueAnimator.reverse();
}
public int dp2px(float value) {
float density = getResources().getDisplayMetrics().density;
return (int) (value * density + 0.5f);
}
public interface OnCheckedChangeListener {
void onChange(boolean checked);
}
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
this.mOnCheckedChangeListener = listener;
}
}
18
Source : PathEvaluator.java
with Apache License 2.0
from wirecube
with Apache License 2.0
from wirecube
public float evaluate(float fraction, PathMode pathMode, Path path) {
if (fraction == lastEvaluatedFraction) {
return getResult(pathMode);
}
float[] tan = new float[2];
PathMeasure pathMeasure = new PathMeasure(path, true);
pathMeasure.getPosTan(pathMeasure.getLength() * fraction, lastPoint, tan);
lastAngle = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
lastEvaluatedFraction = fraction;
return getResult(pathMode);
}
18
Source : ArrowPathFooterDrawer.java
with Apache License 2.0
from uin3566
with Apache License 2.0
from uin3566
/**
* Created by Administrator on 2016/12/1.
*/
public clreplaced ArrowPathFooterDrawer extends BaseFooterDrawer {
private static final String TAG = "ArrowPathFooterDrawer";
// arrow
private boolean hasInitArrowPath = false;
private PathMeasure arrowPathMeasure;
private Path arrowPath;
private Path drawingArrowPath = new Path();
private IconRotateController rotateController;
private ArrowPathParams arrowPathParams;
// hintText string
private String hintText;
private ArrayList<float[]> hintLineList;
private ArrayList<Path> hintPathList;
private PathMeasure hintPathMeasure;
private Path drawingHintPath;
private float hintOffsetX, hintOffsetY;
private float hintWidth, hintHeight;
private boolean hasBeginDrawArrowPath;
private Paint pathPaint;
private Paint bgPaint;
private float rotateThreshold;
private static clreplaced ArrowPathParams {
float finishDrawArrowPathDragDistance;
float arrowHeadLength;
float arrowHeadHeight;
float arrowTailHeight;
float arrowTailLength;
float arrowSmallRectLength;
float arrowSmallRectMargin;
float arrowMarginLeft;
float arrowMarginRight;
float arrowRightMostPosX;
float arrowTailPosY;
}
private ArrowPathFooterDrawer(Builder builder) {
hintText = builder.hintText;
footerColor = builder.footerColor;
footerRegion = new RectF();
rotateThreshold = DimenUtil.dp2px(builder.context, builder.rotateThreshold);
rotateController = new IconRotateController(rotateThreshold, builder.rotateDuration);
pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
pathPaint.setStyle(Paint.Style.STROKE);
pathPaint.setColor(builder.pathColor);
pathPaint.setStrokeWidth(DimenUtil.dp2px(builder.context, builder.pathWidth));
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bgPaint.setColor(footerColor);
bgPaint.setStyle(Paint.Style.FILL);
setArrowPathParams(builder);
setHintString();
}
private void setArrowPathParams(Builder builder) {
arrowPathParams = new ArrowPathParams();
Context context = builder.context;
arrowPathParams.finishDrawArrowPathDragDistance = DimenUtil.dp2px(context, builder.finishDrawArrowPathDragDistance);
arrowPathParams.arrowHeadLength = DimenUtil.dp2px(context, builder.arrowHeadLength);
arrowPathParams.arrowHeadHeight = DimenUtil.dp2px(context, builder.arrowHeadHeight);
arrowPathParams.arrowTailHeight = DimenUtil.dp2px(context, builder.arrowTailHeight);
arrowPathParams.arrowTailLength = DimenUtil.dp2px(context, builder.arrowTailLength);
arrowPathParams.arrowSmallRectLength = DimenUtil.dp2px(context, builder.arrowSmallRectLength);
arrowPathParams.arrowSmallRectMargin = DimenUtil.dp2px(context, builder.arrowSmallRectMargin);
arrowPathParams.arrowMarginLeft = DimenUtil.dp2px(context, builder.arrowMarginLeft);
arrowPathParams.arrowMarginRight = DimenUtil.dp2px(context, builder.arrowMarginRight);
}
public void setHintString() {
if (hintText == null || hintText.isEmpty()) {
return;
}
hintPathMeasure = new PathMeasure();
drawingHintPath = new Path();
hintLineList = StoreHousePath.getPath(hintText, 65 * 0.01f, 24);
setHintWidthAndHeight();
initHintPathArray();
}
private void setHintWidthAndHeight() {
for (int i = 0; i < hintLineList.size(); i++) {
float[] line = hintLineList.get(i);
hintWidth = Math.max(hintWidth, line[0]);
hintWidth = Math.max(hintWidth, line[2]);
hintHeight = Math.max(hintHeight, line[1]);
hintHeight = Math.max(hintHeight, line[3]);
}
}
private void initHintPathArray() {
hintPathList = new ArrayList<>(hintLineList.size());
for (int i = 0; i < hintLineList.size(); i++) {
float[] line = hintLineList.get(i);
Path path = new Path();
path.moveTo(line[0], line[1]);
path.lineTo(line[2], line[3]);
hintPathList.add(path);
}
}
@Override
public void drawFooter(Canvas canvas, float left, float top, float right, float bottom) {
super.drawFooter(canvas, left, top, right, bottom);
drawRect(canvas);
drawArrow(canvas);
drawHintText(canvas);
}
private void drawRect(Canvas canvas) {
canvas.drawRect(footerRegion, bgPaint);
}
private void drawArrow(Canvas canvas) {
initArrowPath();
drawArrowPath(canvas);
}
private void drawHintText(Canvas canvas) {
if (hintText == null || !hasBeginDrawArrowPath) {
return;
}
setStringOffset();
float moveX = getDragDistance() - getArrowTotalLength() - arrowPathParams.arrowMarginLeft;
float percent = getDragPercent(moveX);
canvas.save();
canvas.translate(hintOffsetX, hintOffsetY);
for (int i = 0; i < hintLineList.size(); i++) {
Path path = hintPathList.get(i);
drawingHintPath.reset();
hintPathMeasure.setPath(path, false);
hintPathMeasure.getSegment(0, percent * hintPathMeasure.getLength(), drawingHintPath, true);
canvas.drawPath(drawingHintPath, pathPaint);
}
canvas.restore();
}
private void setStringOffset() {
hintOffsetX = arrowPathParams.arrowRightMostPosX + arrowPathParams.arrowMarginRight;
hintOffsetY = footerRegion.top + (footerRegion.bottom - footerRegion.top - hintHeight) / 2;
}
private void initArrowPath() {
if (hasInitArrowPath) {
return;
}
arrowPathMeasure = new PathMeasure();
arrowPath = new Path();
arrowPathParams.arrowRightMostPosX = footerRegion.right;
arrowPathParams.arrowTailPosY = (footerRegion.bottom - footerRegion.top) / 2 - arrowPathParams.arrowTailHeight / 2;
setArrowPath(arrowPathParams.arrowRightMostPosX, arrowPathParams.arrowTailPosY);
hasInitArrowPath = true;
}
// set arrow path
private void setArrowPath(float rightMostPosX, float tailPosY) {
arrowPath.reset();
float arrowHeadDy = (arrowPathParams.arrowHeadHeight - arrowPathParams.arrowTailHeight) / 2;
float arrowTailLength = arrowPathParams.arrowTailLength;
float arrowTailHeight = arrowPathParams.arrowTailHeight;
float rectLength = arrowPathParams.arrowSmallRectLength;
float rectMargin = arrowPathParams.arrowSmallRectMargin;
float tailPos = rightMostPosX - (arrowPathParams.arrowSmallRectLength + arrowPathParams.arrowSmallRectMargin) * 2;
arrowPath.moveTo(tailPos, tailPosY);
arrowPath.lineTo(tailPos - arrowTailLength, tailPosY);
arrowPath.lineTo(tailPos - arrowTailLength, tailPosY - arrowHeadDy);
arrowPath.lineTo(tailPos - arrowTailLength - arrowPathParams.arrowHeadLength, tailPosY + arrowTailHeight / 2);
arrowPath.lineTo(tailPos - arrowTailLength, tailPosY + arrowTailHeight + arrowHeadDy);
arrowPath.lineTo(tailPos - arrowTailLength, tailPosY + arrowTailHeight);
arrowPath.lineTo(tailPos, tailPosY + arrowTailHeight);
arrowPath.lineTo(tailPos, tailPosY);
arrowPath.addRect(tailPos + rectMargin, tailPosY, tailPos + rectMargin + rectLength, tailPosY + arrowTailHeight, Path.Direction.CCW);
arrowPath.addRect(tailPos + rectMargin * 2 + rectLength, tailPosY, tailPos + 2 * (rectMargin + rectLength), tailPosY + arrowTailHeight, Path.Direction.CW);
arrowPathMeasure.setPath(arrowPath, false);
}
private float getDragDistance() {
return footerRegion.right - footerRegion.left;
}
private float getArrowTotalLength() {
return arrowPathParams.arrowHeadLength + arrowPathParams.arrowTailLength + arrowPathParams.arrowSmallRectMargin * 2 + arrowPathParams.arrowSmallRectLength * 2;
}
private float getDragPercent(float moveX) {
float percent;
if (moveX < arrowPathParams.finishDrawArrowPathDragDistance) {
percent = moveX / arrowPathParams.finishDrawArrowPathDragDistance;
} else {
percent = 1.0f;
}
return percent;
}
private void drawArrowPath(Canvas canvas) {
float arrowTotalLength = getArrowTotalLength();
float arrowMarginLeft = arrowPathParams.arrowMarginLeft;
float dragDx = getDragDistance();
hasBeginDrawArrowPath = false;
if (dragDx < arrowMarginLeft + arrowTotalLength) {
return;
}
hasBeginDrawArrowPath = true;
drawingArrowPath.reset();
float moveX = dragDx - arrowTotalLength - arrowMarginLeft;
float percent = getDragPercent(moveX);
// move arrow
arrowPathParams.arrowRightMostPosX = footerRegion.right - moveX;
setArrowPath(arrowPathParams.arrowRightMostPosX, arrowPathParams.arrowTailPosY);
arrowPathMeasure.getSegment(0, percent * arrowPathMeasure.getLength(), drawingArrowPath, true);
while (arrowPathMeasure.nextContour()) {
arrowPathMeasure.getSegment(0, percent * arrowPathMeasure.getLength(), drawingArrowPath, true);
}
// rotate arrow
canvas.save();
rotateController.calculateRotateDegree(dragState, getDragDistance());
float degree = rotateController.getRotateDegree();
float centerX = arrowPathParams.arrowRightMostPosX - arrowTotalLength / 2;
float centerY = arrowPathParams.arrowTailPosY + arrowPathParams.arrowTailHeight / 2;
canvas.rotate(degree, centerX, centerY);
canvas.drawPath(drawingArrowPath, pathPaint);
canvas.restore();
}
@Override
public void updateDragState(int dragState) {
super.updateDragState(dragState);
if (dragState == DragContainer.RELEASE) {
rotateController.reset();
}
}
@Override
public boolean shouldTriggerEvent(float dragDistance) {
return dragDistance > rotateThreshold;
}
public static clreplaced Builder {
private static final int DEFAULT_ROTATE_DURATION = 150;
private static final float DEFAULT_ARROW_MARGIN = 8;
private static final float DEFAULT_ROTATE_THRESHOLD = 100;
private static final float DEFAULT_ARROW_HEAD_LENGTH = 15;
private static final float DEFAULT_ARROW_HEAD_HEIGHT = 15;
private static final float DEFAULT_ARROW_TAIL_LENGTH = 10;
private static final float DEFAULT_ARROW_TAIL_HEIGHT = 5;
private static final float DEFAULT_ARROW_SMALL_RECT_LENGTH = 2.5f;
private static final float DEFAULT_ARROW_SMALL_RECT_MARGIN = 2.5f;
private static final float DEFAULT_FINISH_DRAW_ARROW_PATH_DRAG_DISTANCE = 60;
private static final float DEFAULT_PATH_WIDTH = 1;
private static final int DEFAULT_PATH_COLOR = 0xffcdcdcd;
private static final String DEFAULT_HINT_TEXT = "MORE";
private final int footerColor;
private final Context context;
// length in dp
private float arrowMarginLeft = DEFAULT_ARROW_MARGIN;
private float arrowMarginRight = DEFAULT_ARROW_MARGIN;
private float arrowHeadLength = DEFAULT_ARROW_HEAD_LENGTH;
private float arrowHeadHeight = DEFAULT_ARROW_HEAD_HEIGHT;
private float arrowTailLength = DEFAULT_ARROW_TAIL_LENGTH;
private float arrowTailHeight = DEFAULT_ARROW_TAIL_HEIGHT;
private float arrowSmallRectLength = DEFAULT_ARROW_SMALL_RECT_LENGTH;
private float arrowSmallRectMargin = DEFAULT_ARROW_SMALL_RECT_MARGIN;
private float finishDrawArrowPathDragDistance = DEFAULT_FINISH_DRAW_ARROW_PATH_DRAG_DISTANCE;
private float rotateThreshold = DEFAULT_ROTATE_THRESHOLD;
private float pathWidth = DEFAULT_PATH_WIDTH;
private int rotateDuration = DEFAULT_ROTATE_DURATION;
private String hintText = DEFAULT_HINT_TEXT;
private int pathColor = DEFAULT_PATH_COLOR;
public Builder(Context context, int footerColor) {
this.context = context;
this.footerColor = footerColor;
}
public Builder setPathColor(int pathColor) {
this.pathColor = pathColor;
return this;
}
public Builder setArrowMarginLeft(float arrowMarginLeft) {
this.arrowMarginLeft = arrowMarginLeft;
return this;
}
public Builder setArrowMarginRight(float arrowMarginRight) {
this.arrowMarginRight = arrowMarginRight;
return this;
}
public Builder setArrowHeadLength(float arrowHeadLength) {
this.arrowHeadLength = arrowHeadLength;
return this;
}
public Builder setArrowHeadHeight(float arrowHeadHeight) {
this.arrowHeadHeight = arrowHeadHeight;
return this;
}
public Builder setArrowTailLength(float arrowTailLength) {
this.arrowTailLength = arrowTailLength;
return this;
}
public Builder setArrowTailHeight(float arrowTailHeight) {
this.arrowTailHeight = arrowTailHeight;
return this;
}
public Builder setArrowSmallRectLength(float arrowSmallRectLength) {
this.arrowSmallRectLength = arrowSmallRectLength;
return this;
}
public Builder setArrowSmallRectMargin(float arrowSmallRectMargin) {
this.arrowSmallRectMargin = arrowSmallRectMargin;
return this;
}
public Builder setFinishDrawArrowPathDragDistance(float finishDrawArrowPathDragDistance) {
this.finishDrawArrowPathDragDistance = finishDrawArrowPathDragDistance;
return this;
}
public Builder setRotateThreshold(float rotateThreshold) {
this.rotateThreshold = rotateThreshold;
return this;
}
public Builder setPathWidth(float pathWidth) {
this.pathWidth = pathWidth;
return this;
}
public Builder setRotateDuration(int rotateDuration) {
this.rotateDuration = rotateDuration;
return this;
}
public Builder setHintText(String hintText) {
this.hintText = hintText;
return this;
}
public ArrowPathFooterDrawer build() {
return new ArrowPathFooterDrawer(this);
}
}
}
18
Source : FloatingPath.java
with Apache License 2.0
from UFreedom
with Apache License 2.0
from UFreedom
/**
* Author UFreedom
*/
public clreplaced FloatingPath {
private Path mPath;
private PathMeasure mPathMeasure;
protected FloatingPath() {
this.mPath = new Path();
}
protected FloatingPath(Path path) {
this.mPath = path;
}
public static FloatingPath create(Path path, boolean forceClose) {
FloatingPath floatingPath = new FloatingPath(path);
floatingPath.mPathMeasure = new PathMeasure(path, forceClose);
return floatingPath;
}
public Path getPath() {
return mPath;
}
public PathMeasure getPathMeasure() {
return mPathMeasure;
}
}
18
Source : WinSearch.java
with Apache License 2.0
from stytooldex
with Apache License 2.0
from stytooldex
/**
* Created by zhangml on 2016/9/12 0012.
*/
public clreplaced WinSearch extends View {
private Paint mPaint;
private Path mPath;
private PathMeasure mPathMeasure;
private int mWidth, mHeight;
private ValueAnimator valueAnimator;
// 用这个来接受ValueAnimator的返回值,代表整个动画的进度
private float t;
public WinSearch(Context context) {
super(context);
}
public WinSearch(Context context, AttributeSet attrs) {
super(context, attrs);
init();
valueAnimator.start();
}
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();
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(mWidth / 2, mHeight / 2);
Path dst = new Path();
if (t >= 0.95) {
canvas.drawPoint(0, -150, mPaint);
}
int num = (int) (t / 0.05);
float s, y, x;
switch(num) {
default:
case 3:
x = t - 0.15f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 2:
x = t - 0.10f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 1:
x = t - 0.05f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 0:
x = t;
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
break;
}
canvas.drawPath(dst, mPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
}
18
Source : WinSearch.java
with MIT License
from stytooldex
with MIT License
from stytooldex
/**
* Created by zhangml on 2016/9/12 0012.
*/
public clreplaced WinSearch extends View {
private Paint mPaint;
private Path mPath;
private PathMeasure mPathMeasure;
private int mWidth, mHeight;
private ValueAnimator valueAnimator;
// 用这个来接受ValueAnimator的返回值,代表整个动画的进度
private float t;
public WinSearch(Context context) {
super(context);
}
public WinSearch(Context context, AttributeSet attrs) {
super(context, attrs);
init();
valueAnimator.start();
}
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();
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(mWidth / 2, mHeight / 2);
Path dst = new Path();
if (t >= 0.95) {
canvas.drawPoint(0, -150, mPaint);
}
int num = (int) (t / 0.05);
float s, y, x;
switch(num) {
default:
case 3:
x = t - 0.15f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 2:
x = t - 0.10f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 1:
x = t - 0.05f * (1 - t);
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
case 0:
x = t;
s = mPathMeasure.getLength();
y = -s * x * x + 2 * s * x;
mPathMeasure.getSegment(y, y + 1, dst, true);
break;
}
canvas.drawPath(dst, mPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
}
18
Source : AlipayFailureView.java
with Apache License 2.0
from REBOOTERS
with Apache License 2.0
from REBOOTERS
/**
* Created by rookie on 2016/10/19.
*/
public clreplaced AlipayFailureView extends View {
private String TAG = AlipayFailureView.clreplaced.getSimpleName();
private static final float PADDING = 20;
private static final int DEFAULT_RADIUS = 150;
private Paint mCirclePanit;
private Paint mLinePaint;
private float mStrokeWidth = 10;
private float factor = 0.8f;
private float temp;
private float mCenterX, mCenterY;
private float mRadius = 250;
private final RectF mRectF = new RectF();
private int mDegree;
private Float mLeftValue = 0f;
private Float mRightValue = 0f;
private AnimatorSet mAnimatorSet = new AnimatorSet();
private ValueAnimator mCircleAnim;
private ValueAnimator mLineLeftAnimator;
private ValueAnimator mLineRightAnimator;
private boolean mIsCanHide;
private PathMeasure pathLeftMeasure;
private PathMeasure pathRightMeasure;
private float[] mLeftPos = new float[2];
private float[] mRightPos = new float[2];
public AlipayFailureView(Context context) {
this(context, null);
}
public AlipayFailureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AlipayFailureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCirclePanit = new Paint();
mCirclePanit.setAntiAlias(true);
mCirclePanit.setStrokeJoin(Paint.Join.ROUND);
mCirclePanit.setStrokeWidth(mStrokeWidth);
mCirclePanit.setColor(Color.WHITE);
mCirclePanit.setStyle(Paint.Style.STROKE);
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeJoin(Paint.Join.ROUND);
mLinePaint.setStrokeWidth(mStrokeWidth);
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStyle(Paint.Style.STROKE);
reset();
reMeasure();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRectF.left = mCenterX - mRadius;
mRectF.top = mCenterY - mRadius;
mRectF.right = mCenterX + mRadius;
mRectF.bottom = mCenterY + mRadius;
canvas.drawArc(mRectF, 0, mDegree, false, mCirclePanit);
if (mLeftPos[1] > (mCenterY - temp) && mRightPos[1] > (mCenterY - temp)) {
canvas.drawLine(mCenterX - temp, mCenterY - temp, mLeftPos[0], mLeftPos[1], mLinePaint);
canvas.drawLine(mCenterX + temp, mCenterY - temp, mRightPos[0], mRightPos[1], mLinePaint);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
reMeasure();
}
private void reMeasure() {
int mViewWidth = getWidth();
int mViewHeight = getHeight();
mCenterX = mViewWidth / 2;
mCenterY = mViewHeight / 2;
temp = mRadius / 2.0f * factor;
Path path = new Path();
path.moveTo(mCenterX - temp, mCenterY - temp);
path.lineTo(mCenterX + temp, mCenterY + temp);
pathLeftMeasure = new PathMeasure(path, false);
path = new Path();
path.moveTo(mCenterX + temp, mCenterY - temp);
path.lineTo(mCenterX - temp, mCenterY + temp);
pathRightMeasure = new PathMeasure(path, false);
}
public void startAnim(int mRadius) {
mRadius = mRadius <= 0 ? DEFAULT_RADIUS : mRadius;
this.mRadius = mRadius - PADDING;
if (null != mAnimatorSet && mAnimatorSet.isRunning()) {
return;
}
reset();
reMeasure();
mCircleAnim = ValueAnimator.ofInt(0, 360);
mLineLeftAnimator = ValueAnimator.ofFloat(0, pathLeftMeasure.getLength());
mLineRightAnimator = ValueAnimator.ofFloat(0, pathRightMeasure.getLength());
mCircleAnim.setDuration(700);
mLineLeftAnimator.setDuration(350);
mLineRightAnimator.setDuration(350);
mCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDegree = (Integer) animation.getAnimatedValue();
invalidate();
}
});
mLineLeftAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mLeftValue = (Float) valueAnimator.getAnimatedValue();
Log.e("left", "-------->" + mLeftValue);
pathLeftMeasure.getPosTan(mLeftValue, mLeftPos, null);
invalidate();
}
});
mLineRightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRightValue = (Float) animation.getAnimatedValue();
pathRightMeasure.getPosTan(mRightValue, mRightPos, null);
invalidate();
}
});
mAnimatorSet.play(mCircleAnim).before(mLineLeftAnimator);
mAnimatorSet.play(mLineRightAnimator).after(mLineLeftAnimator);
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
stop();
if (mEndListner != null) {
mEndListner.onCircleDone();
failureAnim();
}
}
});
mAnimatorSet.start();
}
private void failureAnim() {
float currentX = this.getTranslationX();
ObjectAnimator tansXAnim = ObjectAnimator.ofFloat(this, "translationX", currentX + 20);
tansXAnim.setDuration(1000);
tansXAnim.setInterpolator(new CycleInterpolator(3));
tansXAnim.start();
}
public void stop() {
if (null != mCircleAnim) {
mCircleAnim.end();
}
if (null != mLineLeftAnimator) {
mLineLeftAnimator.end();
}
if (null != mLineRightAnimator) {
mLineRightAnimator.end();
}
clearAnimation();
}
public void reset() {
mDegree = 0;
mLeftValue = 0f;
mRightValue = 0f;
pathLeftMeasure = null;
pathRightMeasure = null;
}
private OnCircleFinishListener mEndListner;
public void addCircleAnimatorEndListner(OnCircleFinishListener endListenr) {
if (null == mEndListner) {
this.mEndListner = endListenr;
}
}
public interface OnCircleFinishListener {
void onCircleDone();
}
public void setPaintColor(int color) {
mCirclePanit.setColor(color);
mLinePaint.setColor(color);
invalidate();
}
}
18
Source : MusicAnimBean.java
with GNU Affero General Public License v3.0
from qwsem
with GNU Affero General Public License v3.0
from qwsem
/**
* Created by cxf on 2018/7/2.
*/
public clreplaced MusicAnimBean {
private static final int STATUS_START = 0;
private static final int STATUS_MIDDLE = 1;
private static final int STATUS_END = 2;
private ImageView mImageView;
private ValueAnimator mAnimator;
private PathMeasure mPathMeasure;
private float mLength;
private float[] mPos;
private int mOffest;
private int mStatus = STATUS_START;
private boolean mAnimStarted;
private int mRotateDirection;
public MusicAnimBean(int offest) {
mPos = new float[2];
mOffest = offest;
}
public void setPathMeasure(PathMeasure pathMeasure) {
mPathMeasure = pathMeasure;
}
public void setImageView(ImageView imageView) {
mImageView = imageView;
mImageView.setAlpha(0f);
}
public void setAnimator(ValueAnimator animator, float length, int rotateDirection) {
mLength = length;
mAnimator = animator;
mRotateDirection = rotateDirection;
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float v = (float) animation.getAnimatedValue();
if (mPathMeasure != null) {
mPathMeasure.getPosTan(v, mPos, null);
mImageView.setX(mPos[0] - mOffest);
mImageView.setY(mPos[1] - mOffest);
if (mStatus == STATUS_START) {
float rate = (int) (v / mLength / 0.3f * 100f);
if (rate >= 100) {
rate = 100;
mStatus = STATUS_MIDDLE;
}
float r = rate / 100f;
mImageView.setAlpha(r);
mImageView.setScaleX(0.2f + r);
mImageView.setScaleY(0.2f + r);
mImageView.setRotation(mRotateDirection * 30 * r);
}
if (mStatus == STATUS_MIDDLE) {
float rate = (int) ((1 - v / mLength) / 0.3f * 100f);
if (rate <= 100) {
mStatus = STATUS_END;
}
}
if (mStatus == STATUS_END) {
float rate = (int) ((1 - v / mLength) / 0.3f * 100f);
if (rate <= 0.1f) {
rate = 0;
mStatus = STATUS_START;
}
float r = rate / 100f;
mImageView.setAlpha(r);
// mImageView.setScaleX(0.3f + r);
// mImageView.setScaleY(0.3f + r);
mImageView.setRotation(mRotateDirection * 30 * r);
}
}
}
});
}
public void startAnim() {
if (mAnimator != null) {
if (mAnimStarted) {
if (mAnimator.isPaused()) {
mAnimator.resume();
}
} else {
mStatus = STATUS_START;
mAnimator.start();
mAnimStarted = true;
}
}
}
public void pauseAnim() {
if (mAnimator != null && mAnimator.isStarted()) {
mAnimator.pause();
}
}
public void cancelAnim() {
if (mAnimator != null) {
mImageView.setAlpha(0f);
mAnimator.cancel();
mAnimStarted = false;
}
}
}
18
Source : PathMeasureSubject.java
with Apache License 2.0
from pkware
with Apache License 2.0
from pkware
/**
* Propositions for {@link PathMeasure} subjects.
*/
public clreplaced PathMeasureSubject extends Subject {
@Nullable
private final PathMeasure actual;
public PathMeasureSubject(@Nonnull FailureMetadata failureMetadata, @Nullable PathMeasure actual) {
super(failureMetadata, actual);
this.actual = actual;
}
public void hasLength(float length, float tolerance) {
check("getLength()").that(actual.getLength()).isWithin(tolerance).of(length);
}
public void isClosed() {
check("isClosed()").that(actual.isClosed()).isTrue();
}
public void isNotClosed() {
check("isClosed()").that(actual.isClosed()).isFalse();
}
}
18
Source : MaterialDesignProgressBar.java
with Apache License 2.0
from pinguo-sunjianfei
with Apache License 2.0
from pinguo-sunjianfei
/**
* time:2016/7/22
* description:匀加速的圆形进度条
*
* @author sunjianfei
*/
public clreplaced MaterialDesignProgressBar extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
ValueAnimator valueAnimator;
boolean isInit;
private int mStokeWidth;
private int mStrokeColor;
public MaterialDesignProgressBar(Context context) {
super(context);
}
public MaterialDesignProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MaterialDesignProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttr(context, attrs, defStyleAttr);
}
private void initAttr(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaterialDesignProgressBar, defStyle, 0);
mStokeWidth = a.getDimensionPixelSize(R.styleable.MaterialDesignProgressBar_progress_stroke_width, (int) PixelUtil.dp2px(2));
mStrokeColor = a.getColor(R.styleable.MaterialDesignProgressBar_progress_stroke_color, 0xff000000);
}
private void init(int width) {
isInit = true;
float size = width * 1.0f / 2;
mPathMeasure = new PathMeasure();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStokeWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setColor(mStrokeColor);
mPath = new Path();
mPath.addCircle(size, size, size - mStokeWidth, Path.Direction.CW);
mPathMeasure.setPath(mPath, true);
mLength = mPathMeasure.getLength();
mDst = new Path();
valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(1500);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInit) {
int width = View.MeasureSpec.getSize(widthMeasureSpec);
init(width);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
// 硬件加速的BUG
mDst.lineTo(0, 0);
float stop = mLength * mAnimatorValue;
float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));
mPathMeasure.getSegment(start, stop, mDst, true);
canvas.drawPath(mDst, mPaint);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
// 如果View状态发生变化,开/关插值计算
if (null != valueAnimator) {
if (visibility == GONE) {
valueAnimator.end();
} else {
valueAnimator.start();
}
}
}
}
18
Source : PopupLayer.java
with MIT License
from panshen
with MIT License
from panshen
/**
* 用来给每一个button设置一个中心点
*
* @param orbit 一个特定角度的path
*/
private void setPos(Path orbit) {
PathMeasure measure = new PathMeasure(orbit, false);
TextLableView tv;
for (int i = 0; i < mButtons.size(); i++) {
PopupButton pp = mButtons.get(i);
tv = kvs.get(pp);
float[] coords = new float[] { 0f, 0f };
int length = (int) ((i) * measure.getLength() / mButtons.size());
measure.getPosTan(length, coords, null);
int px = (int) coords[0] - pp.getMeasuredWidth() / 2;
int py = (int) coords[1] - pp.getMeasuredHeight() / 2;
int tvx = (int) coords[0] - tv.getMeasuredWidth() / 2;
tv.x = tvx;
tv.y = py - 60;
pp.x = px;
pp.y = py;
}
}
18
Source : ScopeView.java
with GNU General Public License v3.0
from mmbuw
with GNU General Public License v3.0
from mmbuw
private int channelOnCount() {
int count = 0;
PathMeasure measure = new PathMeasure(mPathChan1, false);
count += measure.getLength() > 0 ? 1 : 0;
measure.setPath(mPathChan2, false);
count += measure.getLength() > 0 ? 1 : 0;
return count;
}
18
Source : ScopeView.java
with GNU General Public License v3.0
from mmbuw
with GNU General Public License v3.0
from mmbuw
private float smallestDistanceToPath(Path path, float x, float y) {
PathMeasure measure = new PathMeasure(path, false);
float[] pos = { 0f, 0f };
float minDist = 1000f;
float dist;
for (int i = 0; i < measure.getLength(); ++i) {
measure.getPosTan(i, pos, null);
dist = (float) Math.hypot(x - pos[0], y - pos[1]);
if (dist < minDist)
minDist = dist;
}
return minDist;
}
18
Source : OutsideLineRenderer.java
with Apache License 2.0
from LineChen
with Apache License 2.0
from LineChen
/**
* Created by chenliu on 2017/1/12.<br/>
* 描述:
* </br>
*/
public clreplaced OutsideLineRenderer extends AbsRenderer {
/**
* 填充画笔*
*/
private Paint fillPaint;
private PathMeasure measure;
/**
* 动画结束标志
*/
private boolean isAnimateEnd;
/**
* 是否开始绘制,防止动画绘制之前绘制一次
*/
private boolean isShow;
private float phase;
private LinearGradient fillShader;
public OutsideLineRenderer(Context context, View view) {
super(context, view);
}
@Override
protected void initPaint() {
super.initPaint();
fillPaint = new Paint();
fillPaint.setStyle(Paint.Style.FILL);
}
/**
* 画坐标轴 刻度值
* @param canvas
*/
public void drawCoordinateText(Canvas canvas, Axis axisX, Axis axisY, int moveX) {
if (axisX != null && axisY != null) {
// ////// X 轴
// 1.刻度
coordPaint.setColor(axisX.getTextColor());
coordPaint.setTextSize(LeafUtil.sp2px(mContext, axisX.getTextSize()));
// 获取标题文字的高度(fontMetrics.descent - fontMetrics.ascent)
Paint.FontMetrics fontMetrics = coordPaint.getFontMetrics();
float textH = fontMetrics.descent - fontMetrics.ascent;
List<AxisValue> valuesX = axisX.getValues();
if (axisX.isShowText()) {
for (int i = 0; i < valuesX.size(); i++) {
AxisValue value = valuesX.get(i);
if (value.isShowLabel()) {
float textW = coordPaint.measureText(value.getLabel());
canvas.drawText(value.getLabel(), value.getPointX() - textW / 2 + moveX, value.getPointY() - textH / 2, coordPaint);
}
}
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ///// Y 轴
coordPaint.setColor(axisY.getTextColor());
coordPaint.setTextSize(LeafUtil.sp2px(mContext, axisY.getTextSize()));
List<AxisValue> valuesY = axisY.getValues();
if (axisY.isShowText()) {
for (AxisValue value : valuesY) {
float textW = coordPaint.measureText(value.getLabel());
float pointx = value.getPointX() - 1.1f * textW;
canvas.drawText(value.getLabel(), pointx, value.getPointY(), coordPaint);
}
}
}
}
/**
* 画折线
*
* @param canvas
*/
public void drawLines(Canvas canvas, Line line, Axis axisY, int moveX) {
if (line != null && isShow) {
linePaint.setColor(line.getLineColor());
linePaint.setStrokeWidth(LeafUtil.dp2px(mContext, line.getLineWidth()));
linePaint.setStyle(Paint.Style.STROKE);
List<PointValue> values = line.getValues();
Path path = line.getPath();
int size = values.size();
for (int i = 0; i < size; i++) {
PointValue point = values.get(i);
if (i == 0)
path.moveTo(point.getOriginX() + moveX, point.getOriginY());
else
path.lineTo(point.getOriginX() + moveX, point.getOriginY());
}
measure = new PathMeasure(path, false);
linePaint.setPathEffect(createPathEffect(measure.getLength(), phase, 0.0f));
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(axisY.getStartX(), 0, mWidth, mHeight);
canvas.drawPath(path, linePaint);
canvas.restore();
}
}
/**
* 填充
* @param canvas
*/
public void drawFillArea(Canvas canvas, Line line, Axis axisX, int moveX) {
// 继续使用前面的 path
if (line != null && line.getValues().size() > 1 && isShow) {
List<PointValue> values = line.getValues();
PointValue firstPoint = values.get(0);
float firstX = firstPoint.getOriginX();
Path path = line.getPath();
PointValue lastPoint = values.get(values.size() - 1);
float lastX = lastPoint.getOriginX();
path.lineTo(lastX + moveX, axisX.getStartY());
path.lineTo(firstX + moveX, axisX.getStartY());
path.close();
if (fillShader == null) {
fillShader = new LinearGradient(0, 0, 0, mHeight, line.getFillColor(), Color.TRANSPARENT, Shader.TileMode.CLAMP);
fillPaint.setShader(fillShader);
}
if (line.getFillColor() == 0)
fillPaint.setAlpha(100);
else
fillPaint.setColor(line.getFillColor());
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(firstX, 0, phase * (lastX - firstX) + firstX + moveX, mHeight);
canvas.drawPath(path, fillPaint);
canvas.restore();
path.reset();
}
}
/**
* 画圆点
* @param canvas
*/
public void drawPoints(Canvas canvas, Line line, Axis axisY, int moveX) {
if (line != null && line.isHasPoints() && isShow) {
List<PointValue> values = line.getValues();
float radius = LeafUtil.dp2px(mContext, line.getPointRadius());
float strokeWidth = LeafUtil.dp2px(mContext, 1);
PointValue point;
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(axisY.getStartX(), 0, mWidth, mHeight);
for (int i = 0, size = values.size(); i < size; i++) {
point = values.get(i);
labelPaint.setStyle(Paint.Style.FILL);
labelPaint.setColor(line.getPointColor());
canvas.drawCircle(point.getOriginX() + moveX, point.getOriginY(), radius, labelPaint);
labelPaint.setStyle(Paint.Style.STROKE);
labelPaint.setColor(Color.WHITE);
labelPaint.setStrokeWidth(strokeWidth);
canvas.drawCircle(point.getOriginX() + moveX, point.getOriginY(), radius, labelPaint);
}
canvas.restore();
}
}
public void drawLabels(Canvas canvas, ChartData chartData, Axis axisY, int moveX) {
if (isAnimateEnd) {
if (chartData != null) {
if (chartData.isHasLabels()) {
labelPaint.setTextSize(LeafUtil.sp2px(mContext, 12));
List<PointValue> values = chartData.getValues();
int size = values.size();
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(axisY.getStartX(), 0, mWidth, mHeight);
for (int i = 0; i < size; i++) {
PointValue point = values.get(i);
String label = point.getLabel();
Rect bounds = new Rect();
int length = label.length();
labelPaint.getTextBounds(label, 0, length, bounds);
float textW = bounds.width();
float textH = bounds.height();
float left, top, right, bottom;
if (length == 1) {
left = point.getOriginX() - textW * 2.2f;
right = point.getOriginX() + textW * 2.2f;
} else if (length == 2) {
left = point.getOriginX() - textW * 1.0f;
right = point.getOriginX() + textW * 1.0f;
} else {
left = point.getOriginX() - textW * 0.6f;
right = point.getOriginX() + textW * 0.6f;
}
top = point.getOriginY() - 2.5f * textH;
bottom = point.getOriginY() - 0.5f * textH;
// 控制位置
if (left < axisY.getStartX()) {
left = axisY.getStartX();
right += left;
}
if (top < 0) {
top = topPadding;
bottom += topPadding;
}
if (right > mWidth) {
right -= rightPadding;
left -= rightPadding;
}
RectF rectF = new RectF(left + moveX, top, right + moveX, bottom);
float labelRadius = LeafUtil.dp2px(mContext, chartData.getLabelRadius());
labelPaint.setColor(chartData.getLabelColor());
labelPaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rectF, labelRadius, labelRadius, labelPaint);
// drawText
labelPaint.setColor(Color.WHITE);
float xCoordinate = left + (right - left - textW) / 2 + moveX;
float yCoordinate = bottom - (bottom - top - textH) / 2;
canvas.drawText(point.getLabel(), xCoordinate, yCoordinate, labelPaint);
}
canvas.restore();
}
}
}
}
/**
* 带动画的绘制
* @param duration
*/
public void showWithAnimation(int duration) {
isAnimateEnd = false;
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "phase", 0.0f, 1.0f);
animator.setDuration(duration);
animator.start();
isShow = true;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
phase = (float) animation.getAnimatedValue();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isAnimateEnd = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
// showWithAnimation动画开启后会调用该方法
public void setPhase(float phase) {
chartView.invalidate();
}
private PathEffect createPathEffect(float pathLength, float phase, float offset) {
return new DashPathEffect(new float[] { phase * pathLength, pathLength }, 0);
}
}
18
Source : LeafLineRenderer.java
with Apache License 2.0
from LineChen
with Apache License 2.0
from LineChen
/**
* Created by chenliu on 2017/1/9.<br/>
* 描述:
* </br>
*/
public clreplaced LeafLineRenderer extends AbsRenderer {
private static final float LINE_SMOOTHNESS = 0.16f;
/**
* 填充画笔
*/
private Paint fillPaint;
private PathMeasure measure;
/**
* 动画结束标志
*/
private boolean isAnimateEnd;
/**
* 是否开始绘制,防止动画绘制之前绘制一次
*/
private boolean isShow;
private float phase;
private LinearGradient fillShader;
public LeafLineRenderer(Context context, View view) {
super(context, view);
}
@Override
protected void initPaint() {
super.initPaint();
fillPaint = new Paint();
fillPaint.setStyle(Paint.Style.FILL);
}
/**
* 画折线
*
* @param canvas
*/
public void drawLines(Canvas canvas, Line line) {
if (line != null && isShow) {
linePaint.setColor(line.getLineColor());
linePaint.setStrokeWidth(LeafUtil.dp2px(mContext, line.getLineWidth()));
linePaint.setStyle(Paint.Style.STROKE);
List<PointValue> values = line.getValues();
Path path = line.getPath();
int size = values.size();
for (int i = 0; i < size; i++) {
PointValue point = values.get(i);
if (i == 0)
path.moveTo(point.getOriginX(), point.getOriginY());
else
path.lineTo(point.getOriginX(), point.getOriginY());
}
measure = new PathMeasure(path, false);
linePaint.setPathEffect(createPathEffect(measure.getLength(), phase, 0.0f));
canvas.drawPath(path, linePaint);
}
}
/**
* 画曲线
*
* @param canvas
*/
public void drawCubicPath(Canvas canvas, Line line) {
if (line != null && isShow) {
linePaint.setColor(line.getLineColor());
linePaint.setStrokeWidth(LeafUtil.dp2px(mContext, line.getLineWidth()));
linePaint.setStyle(Paint.Style.STROKE);
Path path = line.getPath();
float prePreviousPointX = Float.NaN;
float prePreviousPointY = Float.NaN;
float previousPointX = Float.NaN;
float previousPointY = Float.NaN;
float currentPointX = Float.NaN;
float currentPointY = Float.NaN;
float nextPointX = Float.NaN;
float nextPointY = Float.NaN;
List<PointValue> values = line.getValues();
final int lineSize = values.size();
for (int valueIndex = 0; valueIndex < lineSize; ++valueIndex) {
if (Float.isNaN(currentPointX)) {
PointValue linePoint = values.get(valueIndex);
currentPointX = linePoint.getOriginX();
currentPointY = linePoint.getOriginY();
}
if (Float.isNaN(previousPointX)) {
if (valueIndex > 0) {
PointValue linePoint = values.get(valueIndex - 1);
previousPointX = linePoint.getOriginX();
previousPointY = linePoint.getOriginY();
} else {
previousPointX = currentPointX;
previousPointY = currentPointY;
}
}
if (Float.isNaN(prePreviousPointX)) {
if (valueIndex > 1) {
PointValue linePoint = values.get(valueIndex - 2);
prePreviousPointX = linePoint.getOriginX();
prePreviousPointY = linePoint.getOriginY();
} else {
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
}
}
// nextPoint is always new one or it is equal currentPoint.
if (valueIndex < lineSize - 1) {
PointValue linePoint = values.get(valueIndex + 1);
nextPointX = linePoint.getOriginX();
nextPointY = linePoint.getOriginY();
} else {
nextPointX = currentPointX;
nextPointY = currentPointY;
}
if (valueIndex == 0) {
// Move to start point.
path.moveTo(currentPointX, currentPointY);
} else {
// Calculate control points.
final float firstDiffX = (currentPointX - prePreviousPointX);
final float firstDiffY = (currentPointY - prePreviousPointY);
final float secondDiffX = (nextPointX - previousPointX);
final float secondDiffY = (nextPointY - previousPointY);
final float firstControlPointX = previousPointX + (LINE_SMOOTHNESS * firstDiffX);
final float firstControlPointY = previousPointY + (LINE_SMOOTHNESS * firstDiffY);
final float secondControlPointX = currentPointX - (LINE_SMOOTHNESS * secondDiffX);
final float secondControlPointY = currentPointY - (LINE_SMOOTHNESS * secondDiffY);
if (currentPointY == previousPointY) {
path.lineTo(currentPointX, currentPointY);
} else {
path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY, currentPointX, currentPointY);
}
}
// Shift values by one back to prevent recalculation of values that have
// been already calculated.
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
previousPointX = currentPointX;
previousPointY = currentPointY;
currentPointX = nextPointX;
currentPointY = nextPointY;
}
measure = new PathMeasure(path, false);
linePaint.setPathEffect(createPathEffect(measure.getLength(), phase, 0.0f));
canvas.drawPath(path, linePaint);
}
}
/**
* 填充
*
* @param canvas
*/
public void drawFillArea(Canvas canvas, Line line, Axis axisX) {
// 继续使用前面的 path
if (line != null && line.getValues().size() > 1 && isShow) {
List<PointValue> values = line.getValues();
PointValue firstPoint = values.get(0);
float firstX = firstPoint.getOriginX();
Path path = line.getPath();
PointValue lastPoint = values.get(values.size() - 1);
float lastX = lastPoint.getOriginX();
path.lineTo(lastX, axisX.getStartY());
path.lineTo(firstX, axisX.getStartY());
path.close();
if (fillShader == null) {
fillShader = new LinearGradient(0, 0, 0, mHeight, line.getFillColor(), Color.TRANSPARENT, Shader.TileMode.CLAMP);
fillPaint.setShader(fillShader);
}
if (line.getFillColor() == 0)
fillPaint.setAlpha(100);
else
fillPaint.setColor(line.getFillColor());
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(firstX, 0, phase * (lastX - firstX) + firstX, mHeight);
canvas.drawPath(path, fillPaint);
canvas.restore();
path.reset();
}
}
/**
* 画圆点
*
* @param canvas
*/
public void drawPoints(Canvas canvas, Line line) {
if (line != null && line.isHasPoints() && isShow) {
List<PointValue> values = line.getValues();
float radius = LeafUtil.dp2px(mContext, line.getPointRadius());
float strokeWidth = LeafUtil.dp2px(mContext, 1);
PointValue point;
for (int i = 0, size = values.size(); i < size; i++) {
point = values.get(i);
labelPaint.setStyle(Paint.Style.FILL);
labelPaint.setColor(line.getPointColor());
canvas.drawCircle(point.getOriginX(), point.getOriginY(), radius, labelPaint);
labelPaint.setStyle(Paint.Style.STROKE);
labelPaint.setColor(Color.WHITE);
labelPaint.setStrokeWidth(strokeWidth);
canvas.drawCircle(point.getOriginX(), point.getOriginY(), radius, labelPaint);
}
}
}
/**
* 带动画的绘制
*
* @param duration
*/
public void showWithAnimation(int duration) {
isAnimateEnd = false;
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "phase", 0.0f, 1.0f);
animator.setDuration(duration);
animator.start();
isShow = true;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
phase = (float) animation.getAnimatedValue();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isAnimateEnd = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
// showWithAnimation动画开启后会调用该方法
public void setPhase(float phase) {
chartView.invalidate();
}
private PathEffect createPathEffect(float pathLength, float phase, float offset) {
return new DashPathEffect(new float[] { phase * pathLength, pathLength }, 0);
}
@Override
public void drawLabels(Canvas canvas, ChartData chartData, Axis axisY) {
if (isAnimateEnd)
super.drawLabels(canvas, chartData, axisY);
}
}
18
Source : OkView.java
with MIT License
from lihangleo2
with MIT License
from lihangleo2
/**
* Created by leo
* on 2019/11/21.
*/
public clreplaced OkView extends View {
// 绘制一个小圆圈
private Paint paint;
// 绘制打勾paint
private Paint okPaint;
// 背景圆圈的半径
private int myRadius;
// 绘制打勾的路径
private Path path = new Path();
// 绘制路径的长度,也可以理解为完成度
private PathMeasure pathMeasure;
// 绘制对勾(√)的动画
private ValueAnimator animator_draw_ok;
// 对路径处理实现绘制动画效果
private PathEffect effect;
private boolean startDrawOk;
public OkView(Context context) {
this(context, null);
}
public OkView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public OkView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
okPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
okPaint.setStrokeWidth(5);
okPaint.setStyle(Paint.Style.STROKE);
okPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, myRadius, paint);
if (startDrawOk) {
canvas.drawPath(path, okPaint);
}
}
public void setOkColor(int color) {
okPaint.setColor(color);
}
public void setCircleColor(int color) {
paint.setColor(color);
}
public void setRadius(int radius) {
myRadius = radius;
// 对勾的路径
int cHeight = radius * 2;
path.moveTo(+cHeight / 8 * 3, cHeight / 2);
path.lineTo(+cHeight / 2, cHeight / 5 * 3);
path.lineTo(+cHeight / 3 * 2, cHeight / 5 * 2);
pathMeasure = new PathMeasure(path, true);
invalidate();
}
public void start(int duration) {
animator_draw_ok = ValueAnimator.ofFloat(1, 0);
animator_draw_ok.setDuration(duration);
animator_draw_ok.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
startDrawOk = true;
float value = (Float) animation.getAnimatedValue();
effect = new DashPathEffect(new float[] { pathMeasure.getLength(), pathMeasure.getLength() }, value * pathMeasure.getLength());
okPaint.setPathEffect(effect);
invalidate();
}
});
animator_draw_ok.start();
}
}
18
Source : OvercastType.java
with Apache License 2.0
from li-yu
with Apache License 2.0
from li-yu
/**
* Created by liyu on 2017/8/19.
*/
public clreplaced OvercastType extends BaseWeatherType {
// 山坡的颜色
private static final int hillColor = 0xFF59789D;
private Paint mPaint;
// 近处的山坡
private Path mPathFront;
// 远处的山坡
private Path mPathRear;
// 旋转的风扇的扇叶
private Path fanPath = new Path();
// 旋转的风扇的柱子
private Path fanPillarPath = new Path();
private float fanPillerHeight;
// 旋转的风扇的角度
private float curRotate;
// 当前点的实际位置
private float[] pos;
// 当前点的tangent值,用于计算图片所需旋转的角度
private float[] tan;
PathMeasure measure;
private String windSpeed;
private Shader cloudShader;
private Path cloudPath;
private float cloudTransFactor;
private float hillTransFactor;
private float cloudOffset = 0;
public OvercastType(Context context, ShortWeatherInfo info) {
super(context);
setColor(0xFF6D8DB1);
mPathFront = new Path();
mPathRear = new Path();
mPaint = new Paint();
pos = new float[2];
tan = new float[2];
measure = new PathMeasure();
windSpeed = info.getWindSpeed();
cloudPath = new Path();
cloudOffset = SizeUtils.dp2px(context, 32);
}
@Override
public void onDrawElements(Canvas canvas) {
mPaint.reset();
mPaint.setColor(hillColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
clearCanvas(canvas);
canvas.drawColor(getDynamicColor());
mPaint.setAlpha(100);
mPathRear.reset();
mPathRear.moveTo(getWidth(), getHeight() - getHeight() * 1 / 7 * hillTransFactor);
mPathRear.rQuadTo(-getWidth() / 2, -20 * hillTransFactor, -getWidth(), getHeight() / 10 * hillTransFactor);
mPathRear.lineTo(0, getHeight());
mPathRear.lineTo(getWidth(), getHeight());
mPathRear.close();
canvas.drawPath(mPathRear, mPaint);
mPaint.setAlpha(255);
mPathFront.reset();
mPathFront.moveTo(0, getHeight() - getHeight() * 1 / 7 * hillTransFactor);
mPathFront.rQuadTo(getWidth() / 2, -20 * hillTransFactor, getWidth(), getHeight() / 10 * hillTransFactor);
mPathFront.lineTo(getWidth(), getHeight());
mPathFront.lineTo(0, getHeight());
mPathFront.close();
drawFan(canvas, mPathFront, 0.618f * hillTransFactor, 1f);
drawFan(canvas, mPathRear, 0.15f * hillTransFactor, 0.4f);
mPaint.reset();
mPaint.setColor(hillColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(mPathFront, mPaint);
mPaint.setShader(cloudShader);
cloudPath.reset();
cloudPath.addCircle(getWidth() * cloudTransFactor, getHeight() * 0.618f - cloudOffset, getHeight() / 22, Path.Direction.CW);
cloudPath.addCircle(getWidth() * cloudTransFactor, getHeight() * 0.618f, getHeight() / 22, Path.Direction.CW);
cloudPath.addCircle(getWidth() * cloudTransFactor - getHeight() / 19, getHeight() * 0.618f - cloudOffset * 2 / 3, getHeight() / 26, Path.Direction.CW);
cloudPath.addCircle(getWidth() * cloudTransFactor + getHeight() / 20, getHeight() * 0.618f - cloudOffset * 2 / 3, getHeight() / 30, Path.Direction.CW);
canvas.drawPath(cloudPath, mPaint);
}
private void drawFan(Canvas canvas, Path path, float location, float scale) {
int saveCount = canvas.save();
measure.setPath(path, false);
measure.getPosTan(getWidth() * location, pos, tan);
canvas.translate(pos[0], pos[1] - fanPillerHeight * scale);
canvas.scale(scale, scale);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.WHITE);
canvas.drawPath(fanPillarPath, mPaint);
canvas.rotate(curRotate * 360f);
float speed = 0f;
try {
speed = Float.valueOf(windSpeed);
} catch (Exception e) {
e.printStackTrace();
}
speed = Math.max(speed, 0.75f);
curRotate += 0.0002f * speed;
if (curRotate > 1f) {
curRotate = 0f;
}
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(fanPath, mPaint);
canvas.rotate(120f);
canvas.drawPath(fanPath, mPaint);
canvas.rotate(120f);
canvas.drawPath(fanPath, mPaint);
canvas.restoreToCount(saveCount);
}
@Override
public void generateElements() {
cloudShader = new LinearGradient(getWidth() / 2, 0, getWidth() / 2, getHeight() * 0.618f, 0xFFFFFFFF, 0x00FFFFFF, Shader.TileMode.CLAMP);
final float textSize = getHeight() / 32f;
fanPath.reset();
// 风扇底部半圆的半径
final float fanSize = textSize * 0.2f;
final float fanHeight = textSize * 2f;
final float fanCenterOffsetY = fanSize * 1.6f;
fanPath.addArc(new RectF(-fanSize, -fanSize - fanCenterOffsetY, fanSize, fanSize - fanCenterOffsetY), 0, 180);
fanPath.quadTo(-fanSize * 1f, -fanHeight * 0.5f - fanCenterOffsetY, 0, -fanHeight - fanCenterOffsetY);
fanPath.quadTo(fanSize * 1f, -fanHeight * 0.5f - fanCenterOffsetY, fanSize, -fanCenterOffsetY);
fanPath.close();
fanPillarPath.reset();
// 柱子的宽度
final float fanPillarSize = textSize * 0.20f;
fanPillarPath.moveTo(0, 0);
// 柱子的高度
fanPillerHeight = textSize * 4f;
fanPillarPath.lineTo(2, 0);
fanPillarPath.lineTo(fanPillarSize, fanPillerHeight);
fanPillarPath.lineTo(-fanPillarSize, fanPillerHeight);
fanPillarPath.lineTo(-2, 0);
fanPillarPath.close();
}
@Override
public void startAnimation(final DynamicWeatherView dynamicWeatherView, int fromColor) {
super.startAnimation(dynamicWeatherView, fromColor);
ValueAnimator animator = ValueAnimator.ofFloat(-0.2f, 1.2f);
animator.setDuration(30000);
animator.setRepeatCount(-1);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
cloudTransFactor = (float) animation.getAnimatedValue();
}
});
animator.start();
ValueAnimator animator2 = ValueAnimator.ofFloat(0, 1);
animator2.setDuration(1000);
animator2.setRepeatCount(0);
animator2.setInterpolator(new OvershootInterpolator());
animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
hillTransFactor = (float) animation.getAnimatedValue();
}
});
animator2.start();
}
@Override
public void endAnimation(DynamicWeatherView dynamicWeatherView, Animator.AnimatorListener listener) {
super.endAnimation(dynamicWeatherView, listener);
ValueAnimator animator = ValueAnimator.ofFloat(1, -1);
animator.setDuration(1000);
animator.setRepeatCount(0);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
hillTransFactor = (float) animation.getAnimatedValue();
}
});
if (listener != null) {
animator.addListener(listener);
}
animator.start();
}
}
18
Source : PlayAndPauseView.java
with MIT License
from Jzvd
with MIT License
from Jzvd
/**
* 仿爱奇艺客户端播放暂停按钮动画
*/
public clreplaced PlayAndPauseView extends View {
private int animationStep = 1;
private int animationType = 2;
// 左边动画时间
private long leftDuration = 300;
// 右边动画时间
private long rightDuration = 2 * leftDuration / 3;
private Path leftPath;
private PathMeasure leftPathMeasure;
private float leftZoomValue;
// 线的间隔
private float mLineInterval = Utils.dp2px(15);
// 线的长度
private float mLineLength = Utils.dp2px(18);
private Paint linePaint;
// 线的粗度
private float lineThickness = Utils.dp2px(4);
private Float mLeftCurAnimValue;
private Path mLeftDstPath;
private Float mRightCurAnimValue;
private Path mRightDstPath;
private AnimatorSet orderAnimatorSet;
private AnimatorSet reverseAnimatorSet;
private Path rightPath;
private PathMeasure rightPathMeasure;
private float rightZoomValue;
public PlayAndPauseView(Context paramContext) {
super(paramContext);
}
public PlayAndPauseView(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
init();
}
private void init() {
leftPath = new Path();
rightPath = new Path();
mLeftDstPath = new Path();
mRightDstPath = new Path();
leftPathMeasure = new PathMeasure();
rightPathMeasure = new PathMeasure();
linePaint = new Paint(1);
linePaint.setColor(getResources().getColor(R.color.colorWhite));
linePaint.setStrokeCap(Paint.Cap.ROUND);
linePaint.setStrokeWidth(lineThickness);
mLeftCurAnimValue = 1.0f;
mRightCurAnimValue = 1.0f;
initOrderAnimation();
initReverseAnimation();
}
private void initOrderAnimation() {
// 左边线条缩放隐藏动画
final ObjectAnimator leftZoomHideAnimation = ObjectAnimator.ofFloat(this, "leftZoomValue", 0f, 1.0f);
// 左边线条缩放动画
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(this, "leftZoomValue", 0f, 0.2f);
objectAnimator1.setDuration(200);
objectAnimator1.addListener(new Animator.AnimatorListener() {
public void onAnimationCancel(Animator param1Animator) {
}
public void onAnimationEnd(Animator param1Animator) {
// 左边线条缩放结束后开始左边线条的缩放隐藏动画
animationStep = 2;
leftZoomHideAnimation.start();
}
public void onAnimationRepeat(Animator param1Animator) {
}
public void onAnimationStart(Animator param1Animator) {
}
});
// 左边线条动画
ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(0f, 1.0f);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator param1ValueAnimator) {
mLeftCurAnimValue = (Float) param1ValueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator1.setDuration(leftDuration);
// 右边线条动画
ValueAnimator valueAnimator2 = ValueAnimator.ofFloat(0f, 1.0f);
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator param1ValueAnimator) {
mRightCurAnimValue = (Float) param1ValueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator2.setDuration(rightDuration);
AnimatorSet animatorSet = new AnimatorSet();
// 左边动画和右边动画一起执行
animatorSet.playTogether(valueAnimator1, valueAnimator2);
animatorSet.start();
orderAnimatorSet = new AnimatorSet();
// 先执行左边缩放动画,再执行animatorSet
orderAnimatorSet.playSequentially(objectAnimator1, animatorSet);
}
private void initReverseAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "leftZoomValue", 0.2f, 0f);
objectAnimator.setDuration(200);
ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(0f, 1.0f);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator param1ValueAnimator) {
mLeftCurAnimValue = (Float) param1ValueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator1.setDuration(leftDuration);
ValueAnimator valueAnimator2 = ValueAnimator.ofFloat(0f, 1.0f);
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator param1ValueAnimator) {
mRightCurAnimValue = (Float) param1ValueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator2.setDuration(leftDuration);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(valueAnimator1, valueAnimator2);
animatorSet.addListener(new Animator.AnimatorListener() {
public void onAnimationCancel(Animator param1Animator) {
}
public void onAnimationEnd(Animator param1Animator) {
animationStep = 1;
}
public void onAnimationRepeat(Animator param1Animator) {
}
public void onAnimationStart(Animator param1Animator) {
}
});
animatorSet.start();
reverseAnimatorSet = new AnimatorSet();
reverseAnimatorSet.playSequentially(animatorSet, objectAnimator);
}
private void pause() {
animationType = 2;
reverseAnimatorSet.start();
}
private void play() {
animationType = 1;
orderAnimatorSet.start();
}
public void playOrPause() {
if (animationType == 1) {
pause();
} else if (animationType == 2) {
play();
}
}
public float getLeftZoomValue() {
return leftZoomValue;
}
public void setLeftZoomValue(float paramFloat) {
leftZoomValue = paramFloat;
postInvalidate();
}
public float getRightZoomValue() {
return rightZoomValue;
}
public void setRightZoomValue(float paramFloat) {
rightZoomValue = paramFloat;
postInvalidate();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
protected void onDraw(Canvas canvas) {
float leftWidth = (getWidth() - mLineInterval + 2 * lineThickness) / 2;
float height = getHeight();
float lineLength = mLineLength;
float startHeight = (height - lineLength) / 2;
if (animationStep == 1) {
// 画左边线条
canvas.drawLine(leftWidth, startHeight + lineLength * leftZoomValue, leftWidth, startHeight + lineLength, linePaint);
// 画右边线条
canvas.drawLine(leftWidth + mLineInterval, startHeight - mLineLength * leftZoomValue, leftWidth + mLineInterval, startHeight + mLineLength * (1 - leftZoomValue), linePaint);
}
if (animationStep == 2) {
// 绘制左边线条动画轨迹
leftPath.moveTo(leftWidth, startHeight + mLineLength);
leftPath.lineTo(leftWidth, startHeight + (1 - leftZoomValue) * mLineLength);
leftPath.lineTo(leftWidth, startHeight);
leftPath.cubicTo(leftWidth, startHeight, leftWidth + Utils.dp2px(1), startHeight - Utils.dp2px(2), leftWidth + Utils.dp2px(4), startHeight - Utils.dp2px(1));
leftPath.lineTo(leftWidth + mLineInterval, startHeight + mLineLength / 2 - Utils.dp2px(1));
leftPath.cubicTo(leftWidth + mLineInterval, startHeight + mLineLength / 2.0F - Utils.dp2px(1), leftWidth + mLineInterval + Utils.dp2px(2), startHeight + mLineLength / 2 - Utils.dp2px(1) + Utils.dp2px(2), leftWidth + mLineInterval, startHeight + mLineLength / 2.0F - Utils.dp2px(1.0F) + Utils.dp2px(4.0F));
leftPath.lineTo(leftWidth + Utils.dp2px(4), startHeight + mLineLength + Utils.dp2px(1));
leftPath.cubicTo(leftWidth + Utils.dp2px(4), startHeight + mLineLength + Utils.dp2px(1), leftWidth + Utils.dp2px(1), startHeight + mLineLength + Utils.dp2px(2), leftWidth, startHeight + mLineLength);
leftPath.lineTo(leftWidth, startHeight + mLineLength / 2);
leftPathMeasure.setPath(leftPath, false);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeCap(Paint.Cap.ROUND);
mLeftDstPath.reset();
float leftPathMeasureLength = leftPathMeasure.getLength();
if (animationType == 1) {
leftPathMeasure.getSegment(mLineLength / 2 * mLeftCurAnimValue, leftPathMeasureLength * mLeftCurAnimValue + mLineLength, mLeftDstPath, true);
} else {
leftPathMeasure.getSegment(mLineLength / 2.0F * (1 - mLeftCurAnimValue), leftPathMeasureLength - leftPathMeasureLength * mLeftCurAnimValue + mLineLength, mLeftDstPath, true);
}
canvas.drawPath(mLeftDstPath, linePaint);
// 绘制右边线条动画轨迹
rightPath.moveTo(leftWidth + mLineInterval, (float) (startHeight - mLineLength * 0.2));
rightPath.lineTo(leftWidth + mLineInterval, startHeight + mLineLength);
rightPath.arcTo(leftWidth, startHeight + mLineLength - Utils.dp2px(8), leftWidth + mLineInterval, startHeight + mLineLength + Utils.dp2px(8), 0, 180, false);
rightPath.lineTo(leftWidth, startHeight);
rightPathMeasure.setPath(rightPath, false);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeJoin(Paint.Join.ROUND);
float rightPathMeasureLength = rightPathMeasure.getLength();
mRightDstPath.reset();
if (animationType == 1) {
rightPathMeasure.getSegment(rightPathMeasureLength * mRightCurAnimValue, rightPathMeasureLength * mRightCurAnimValue + mLineLength, mRightDstPath, true);
} else {
rightPathMeasure.getSegment(rightPathMeasureLength - rightPathMeasureLength * mRightCurAnimValue, rightPathMeasureLength - rightPathMeasureLength * mRightCurAnimValue + mLineLength * mRightCurAnimValue, mRightDstPath, true);
}
canvas.drawPath(mRightDstPath, linePaint);
}
}
}
18
Source : PathMeasurePostTanView.java
with Apache License 2.0
from jiyouliang
with Apache License 2.0
from jiyouliang
/**
* @author YouLiang.Ji
* 通过PathMeasure.getPostTan绘制切线
*/
public clreplaced PathMeasurePostTanView extends View {
private Paint paint;
private Path mPath;
private PathMeasure mPathMeasure;
private float[] mPos;
private float[] mTan;
private ValueAnimator mAnimator;
private float mAnimValue;
public PathMeasurePostTanView(Context context) {
this(context, null);
}
public PathMeasurePostTanView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PathMeasurePostTanView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
mPos = new float[2];
mTan = new float[2];
mPath = new Path();
mPath.addCircle(0, 0, 100, Path.Direction.CW);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath, true);
mAnimator = ValueAnimator.ofFloat(0, 1);
mAnimator.setDuration(1000);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimValue = (float) animation.getAnimatedValue();
invalidate();
}
});
mAnimator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 锁定画布
canvas.save();
// 移动画布中心
canvas.translate(200, 200);
canvas.drawPath(mPath, paint);
// getPosTan方法获取摸个点上的坐标点和切线坐标,参数1:输入参数;参数2:输出参数,某点对应的坐标;参数3:输出参数,切线坐标
mPathMeasure.getPosTan(mAnimValue * mPathMeasure.getLength(), mPos, mTan);
canvas.drawCircle(mPos[0], mPos[1], 10, paint);
// 计算切线角度
float degree = (float) (Math.atan2(mTan[1], mTan[0]) * 180 / Math.PI);
// 旋转画布,不旋转切线永远固定不动
canvas.rotate(degree);
// 绘制切线
canvas.drawLine(0, -100, 100, -100, paint);
// canvas.drawLine(0, -100, -100, -100, paint);
// 释放画布
canvas.restore();
}
}
18
Source : BezierLoadingView.java
with Apache License 2.0
from jiyouliang
with Apache License 2.0
from jiyouliang
/**
* @author YouLiang.Ji
* 贝塞尔曲线实现loading效果
*/
public clreplaced BezierLoadingView extends View {
private Path mPath;
// 输出路径
private Path mDst;
private Paint paint;
// 路径测量
private PathMeasure mPathMeasure;
// 路径长度
private float mLength;
private ValueAnimator animator;
private float mAnimValue;
public BezierLoadingView(Context context) {
this(context, null);
}
public BezierLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BezierLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(6);
mPath = new Path();
mDst = new Path();
// 添加圆形路径
mPath.addCircle(400, 400, 100, Path.Direction.CW);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath, true);
// 获取路径长度
mLength = mPathMeasure.getLength();
animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(800);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimValue = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
mDst.lineTo(0, 0);
// float start = 0;
// 0 ~ 整个圆长度变化,以此形成动画效果
float stop = mLength * mAnimValue;
// 当路径绘制到半个圆时,终点快速向起点移动
float start = (float) (stop - ((0.5 - Math.abs(mAnimValue - 0.5)) * mLength));
// 获取路径片段:true代表从起点开始截取,将截取片段输出到mDst路径中
mPathMeasure.getSegment(start, stop, mDst, true);
canvas.drawPath(mDst, paint);
}
}
18
Source : SearchView.java
with Apache License 2.0
from jeanboydev
with Apache License 2.0
from jeanboydev
/**
* Created by jeanboy on 2016/11/9.
*/
public clreplaced SearchView extends View {
private int mWidth, mHeight;
private int glreplacedRadius = 50;
private int searchRadius = glreplacedRadius * 2;
private float[] glreplacedBarEnd = new float[2];
private Path mGlreplacedPath = new Path();
private Path mSearchPath = new Path();
private PathMeasure pathMeasure = new PathMeasure();
private Paint mPaint = new Paint();
// 图标颜色
public final static int COLOR_PAINT = Color.WHITE;
// 背景颜色
public final static int COLOR_BG = 0xFF0082D7;
private int nowState = STATE_NONE;
// 定义状态
public final static int STATE_NONE = 0x000;
public final static int STATE_LOAD_START = 0x001;
public final static int STATE_LOADING = 0x002;
public final static int STATE_LOAD_END = 0x003;
// 默认动画时长
private final static int ANIM_DURATION = 1500;
private float currentValue = 0f;
private ValueAnimator.AnimatorUpdateListener updateListener;
private ValueAnimator startValueAnimator;
private ValueAnimator loadingValueAnimator;
private ValueAnimator endValueAnimator;
private boolean isSearching = false;
public SearchView(Context context) {
this(context, null);
}
public SearchView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mPaint.setColor(COLOR_PAINT);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(15f);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
initPath();
initListener();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(mWidth / 2, mHeight / 2);
canvas.drawColor(COLOR_BG);
switch(nowState) {
case STATE_NONE:
canvas.drawPath(mGlreplacedPath, mPaint);
break;
case STATE_LOAD_START:
pathMeasure.setPath(mGlreplacedPath, false);
Path glreplacedStartDst = new Path();
// 获取绘制路径区间,从0-1
pathMeasure.getSegment(pathMeasure.getLength() * currentValue, pathMeasure.getLength(), glreplacedStartDst, true);
canvas.drawPath(glreplacedStartDst, mPaint);
break;
case STATE_LOADING:
pathMeasure.setPath(mSearchPath, false);
Path searchDst = new Path();
float stop = pathMeasure.getLength() * currentValue;
float start = (float) (stop - ((0.5 - Math.abs(currentValue - 0.5)) * searchRadius * 2));
pathMeasure.getSegment(start, stop, searchDst, true);
canvas.drawPath(searchDst, mPaint);
break;
case STATE_LOAD_END:
pathMeasure.setPath(mGlreplacedPath, false);
Path glreplacedEndDst = new Path();
// 获取绘制路径区间,从1-0
pathMeasure.getSegment(pathMeasure.getLength() * currentValue, pathMeasure.getLength(), glreplacedEndDst, true);
canvas.drawPath(glreplacedEndDst, mPaint);
break;
}
}
private void initPath() {
// 放大镜路径
RectF glreplacedRectF = new RectF(-glreplacedRadius, -glreplacedRadius, glreplacedRadius, glreplacedRadius);
// 不要设置360°内部会自动优化,测量不能取到需要的数值
mGlreplacedPath.addArc(glreplacedRectF, 45, 359.9f);
// 搜索路径
RectF searchRectF = new RectF(-searchRadius, -searchRadius, searchRadius, searchRadius);
mSearchPath.addArc(searchRectF, 45, 359.9f);
// 获取放大镜把的结束坐标,也就是搜索路径的结束坐标
PathMeasure searchMeasure = new PathMeasure(mSearchPath, false);
searchMeasure.getPosTan(0, glreplacedBarEnd, null);
mGlreplacedPath.lineTo(glreplacedBarEnd[0], glreplacedBarEnd[1]);
}
private void initListener() {
updateListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentValue = (float) animation.getAnimatedValue();
postInvalidate();
}
};
startValueAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIM_DURATION);
loadingValueAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIM_DURATION);
loadingValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
loadingValueAnimator.setRepeatMode(ValueAnimator.RESTART);
endValueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(ANIM_DURATION);
startValueAnimator.addUpdateListener(updateListener);
loadingValueAnimator.addUpdateListener(updateListener);
endValueAnimator.addUpdateListener(updateListener);
startValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
nowState = STATE_LOADING;
loadingValueAnimator.start();
}
});
endValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isSearching = false;
nowState = STATE_NONE;
}
});
}
public boolean isSearching() {
return isSearching;
}
public void startSearch() {
if (isSearching)
return;
isSearching = true;
nowState = STATE_LOAD_START;
startValueAnimator.start();
}
public void stopSearch() {
if (startValueAnimator.isRunning()) {
startValueAnimator.end();
}
if (loadingValueAnimator.isRunning()) {
loadingValueAnimator.end();
}
nowState = STATE_LOAD_END;
endValueAnimator.start();
}
}
18
Source : PathTracingView.java
with Apache License 2.0
from InnoFang
with Apache License 2.0
from InnoFang
/**
* Author: Inno Fang
* Time: 2017/1/12 21:40
* Description:
*/
public clreplaced PathTracingView extends View {
private static final String TAG = "PathTracingView";
private Path mDst;
private Path mPath;
private Paint mPaint;
private float mLength;
private float mAnimValue;
private PathMeasure mPathMeasure;
public PathTracingView(Context context) {
super(context);
}
public PathTracingView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath = new Path();
mDst = new Path();
mPath.addCircle(400, 400, 100, Path.Direction.CW);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath, true);
mLength = mPathMeasure.getLength();
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(1000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimValue = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}
public PathTracingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
// 若去掉,geSegment方法可能会失效
mDst.lineTo(0, 0);
float stop = mLength * mAnimValue;
float start = (float) (stop - ((0.5 - Math.abs(mAnimValue - 0.5)) * mLength));
mPathMeasure.getSegment(start, stop, mDst, true);
canvas.drawPath(mDst, mPaint);
}
}
18
Source : PathPosTanView.java
with Apache License 2.0
from InnoFang
with Apache License 2.0
from InnoFang
/**
* Author: Inno Fang
* Time: 2017/1/13 10:21
* Description:
*/
public clreplaced PathPosTanView extends View implements View.OnClickListener {
private static final String TAG = "PathPosTanView";
private Path mPath;
// 用于存放取出来的点的坐标
private float[] mPos;
// 用于取出当前点的运动趋势的坐标
private float[] mTan;
private Paint mPaint;
private PathMeasure mPathMeasure;
private ValueAnimator mValueAnimator;
private float mCurrentValue;
public PathPosTanView(Context context) {
super(context);
}
public PathPosTanView(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath.addCircle(0, 0, 200, Path.Direction.CW);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath, false);
mPos = new float[2];
mTan = new float[2];
setOnClickListener(this);
mValueAnimator = ValueAnimator.ofFloat(0, 1);
mValueAnimator.setDuration(3000);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentValue = (float) animation.getAnimatedValue();
invalidate();
}
});
}
public PathPosTanView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPathMeasure.getPosTan(mCurrentValue * mPathMeasure.getLength(), mPos, mTan);
float degree = (float) (Math.atan2(mTan[1], mTan[0]) * 180 / Math.PI);
canvas.save();
// 将画布平移到400,400的位置
canvas.translate(400, 400);
canvas.drawPath(mPath, mPaint);
canvas.drawCircle(mPos[0], mPos[1], 10, mPaint);
canvas.rotate(degree);
canvas.drawLine(0, -200, 300, -200, mPaint);
canvas.restore();
}
@Override
public void onClick(View v) {
mValueAnimator.start();
}
}
18
Source : PathPaintView.java
with Apache License 2.0
from InnoFang
with Apache License 2.0
from InnoFang
/**
* Author: Inno Fang
* Time: 2017/1/12 21:40
* Description:
*/
public clreplaced PathPaintView extends View {
private static final String TAG = "PathTracingView";
private Path mPath;
private Paint mPaint;
private float mLength;
private float mAnimValue;
private PathMeasure mPathMeasure;
private PathEffect mPathEffect;
public PathPaintView(Context context) {
super(context);
}
public PathPaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath = new Path();
mPath.moveTo(100, 100);
mPath.lineTo(100, 500);
mPath.lineTo(400, 300);
mPath.close();
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath, true);
mLength = mPathMeasure.getLength();
ValueAnimator animator = ValueAnimator.ofFloat(1, 0);
animator.setDuration(2000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimValue = (float) animation.getAnimatedValue();
mPathEffect = new DashPathEffect(new float[] { mLength, mLength }, mLength * mAnimValue);
mPaint.setPathEffect(mPathEffect);
invalidate();
}
});
animator.start();
}
public PathPaintView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}
}
18
Source : EasyPathView.java
with Apache License 2.0
from huzenan
with Apache License 2.0
from huzenan
/**
* 带动画的路径视图,将通过设置的路径pathString,自动按顺序生成路径动画,包括绘制动画与清除动画(反方向);
* 其中fixedWidth和fixedHeight属性必选,用于设置相对于所提供的pathString的固定宽高,以保证在任何实际测量出的宽高中,路径位置正确;
* strokeFixedWidth属性可选,用于设置相对于所提供的pathString的固定线段宽度,以保证在任何实际测量的宽高中,绘制路径的线段宽度显示比例一致;
* Created by huzn on 2016/12/21.
*/
public clreplaced EasyPathView extends View {
// 相对于所提供路径的固定的宽,默认为0
private int fixedWidth;
// 相对于所提供路径的固定的高,默认为0
private int fixedHeight;
// 需要解析的路径
private String pathString;
// 线段颜色,默认Color.BLACK
private int strokeColor;
// 线段宽度,默认1dp
private int strokeWidth;
// 相对于所提供路径的固定的线段宽度,提供该参数时,无视strokeWidth参数,默认为-1
private float strokeFixedWidth;
// 线段是否平滑,默认false
private boolean strokeIsRound;
// 动画时间长度集,单位ms,默认为全部500
private String animDurations;
// 动画播放模式,为ANIM_MODE_TOGETHER或ANIM_MODE_SEPARATE,默认为ANIM_MODE_TOGETHER
private int animMode;
// 状态,为STATE_SHOW或STATE_HIDE,默认为STATE_SHOW
private int state;
// 是否为动态的,设置为动态时,将只显示绘制过的路径,不显示路径本身,默认为false
private boolean dynamic;
// 最大线段数,默认为10
private int maxPathCount;
public static final int STATE_NONE = -1;
public static final int STATE_SHOW = 0;
public static final int STATE_HIDE = 1;
public static final int STATE_ANIM_SHOW = 2;
public static final int STATE_ANIM_HIDE = 3;
public static final int ANIM_MODE_TOGETHER = 0;
public static final int ANIM_MODE_SEPARATE = 1;
private int pathCount;
private static final int MAX_PATH_COUNT = 10;
private Path pathDst;
private Path[] pathDstList;
private PathMeasure pm;
private PathMeasure[] pmList;
private Paint paint;
private float factor;
// 用于在EditMode下Preview
private Path path;
// 当animMode为ANIM_MODE_SEPARATE时,记录当前播放的动画
private int curAnimIndex;
// 动画时间长度集
private long[] animDurationArr;
// 动画时间占比集
private float[] animDurationRatioArr;
// 动画默认播放时长
private static final long ANIM_DURATION_DEFAULT = 500;
// 动画是否循环
private boolean isAnimRepeat;
private ValueAnimator.AnimatorUpdateListener updateListener;
private float animatorValue;
public EasyPathView(Context context) {
this(context, null);
}
public EasyPathView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EasyPathView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EasyPathView, defStyleAttr, 0);
fixedWidth = a.getInteger(R.styleable.EasyPathView_epvFixedWidth, 0);
fixedHeight = a.getInteger(R.styleable.EasyPathView_epvFixedHeight, 0);
pathString = a.getString(R.styleable.EasyPathView_epvPathString);
strokeColor = a.getColor(R.styleable.EasyPathView_epvStrokeColor, Color.BLACK);
strokeWidth = a.getDimensionPixelOffset(R.styleable.EasyPathView_epvStrokeWidth, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
strokeFixedWidth = a.getFloat(R.styleable.EasyPathView_epvStrokeFixedWidth, -1.0f);
strokeIsRound = a.getBoolean(R.styleable.EasyPathView_epvStrokeIsRound, false);
animDurations = a.getString(R.styleable.EasyPathView_epvAnimDurations);
animMode = a.getInteger(R.styleable.EasyPathView_epvAnimMode, ANIM_MODE_TOGETHER);
state = a.getInteger(R.styleable.EasyPathView_epvState, STATE_SHOW);
dynamic = a.getBoolean(R.styleable.EasyPathView_epvDynamic, false);
maxPathCount = a.getInteger(R.styleable.EasyPathView_epvMaxPathCount, MAX_PATH_COUNT);
a.recycle();
initPath();
initPaint();
initListener();
initDuration();
}
private void initPath() {
pathCount = 0;
pathDst = new Path();
pathDstList = new Path[maxPathCount];
for (int i = 0; i < maxPathCount; i++) pathDstList[i] = new Path();
pm = new PathMeasure();
pmList = new PathMeasure[maxPathCount];
for (int i = 0; i < maxPathCount; i++) pmList[i] = new PathMeasure();
}
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setColor(strokeColor);
paint.setStyle(Paint.Style.STROKE);
if (strokeIsRound) {
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
}
}
private void initListener() {
updateListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animatorValue = (float) animation.getAnimatedValue();
invalidate();
}
};
}
private void initDuration() {
if (TextUtils.isEmpty(animDurations))
animDurations = String.valueOf(ANIM_DURATION_DEFAULT);
// 获取动画时间长度集
String[] splitDur = animDurations.split(",");
animDurationArr = new long[maxPathCount];
int splitLen = Math.min(splitDur.length, maxPathCount);
for (int i = 0; i < splitLen; i++) animDurationArr[i] = Long.parseLong(splitDur[i]);
for (int i = splitLen; i < maxPathCount; i++) animDurationArr[i] = ANIM_DURATION_DEFAULT;
animDurationRatioArr = new float[maxPathCount];
isAnimRepeat = false;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
rebuildPathData();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
width = width + getPaddingLeft() + getPaddingRight();
if (mode != MeasureSpec.EXACTLY) {
// wrap_content
width = fixedWidth;
}
int height = MeasureSpec.getSize(heightMeasureSpec);
mode = MeasureSpec.getMode(heightMeasureSpec);
height = height + getPaddingTop() + getPaddingBottom();
if (mode != MeasureSpec.EXACTLY) {
// wrap_content
height = fixedHeight;
}
// 得到实际测量大小与指定大小的比例factor,当宽、高计算出的比例不同时,使用较小值
float f1 = 1.0f * width / fixedWidth;
float f2 = 1.0f * height / fixedHeight;
factor = Math.min(f1, f2);
if (strokeFixedWidth != -1)
paint.setStrokeWidth(strokeFixedWidth * factor);
rebuildPathData();
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
if (state == STATE_NONE)
return;
// 支持预览
if (isInEditMode()) {
canvas.drawPath(path, paint);
return;
}
float startRatio = 0.27f * animatorValue * animatorValue + 0.73f;
if (animMode == ANIM_MODE_TOGETHER) {
float startD = 0.0f;
for (int i = 0; i < pathCount; i++) {
if (dynamic)
startD = pmList[i].getLength() * animatorValue * startRatio;
pathDst.reset();
// 兼容KITKAT的硬件加速,详见PathMeasure.getSegment()的注释
pathDst.rLineTo(0, 0);
pmList[i].getSegment(startD, pmList[i].getLength() * animatorValue, pathDst, true);
canvas.drawPath(pathDst, paint);
}
} else if (animMode == ANIM_MODE_SEPARATE) {
if (!dynamic) {
if (state == STATE_SHOW || state == STATE_ANIM_SHOW) {
// 绘制已经完成动画的路径
for (int i = 0; i < curAnimIndex; i++) canvas.drawPath(pathDstList[i], paint);
} else if (state == STATE_HIDE || state == STATE_ANIM_HIDE) {
// 绘制未播放动画的路径
for (int i = curAnimIndex - 1; i >= 0; i--) canvas.drawPath(pathDstList[i], paint);
}
}
// 绘制正在播放动画的路径
if (0 <= curAnimIndex && curAnimIndex < pathCount) {
float startD = 0.0f;
if (dynamic)
startD = pmList[curAnimIndex].getLength() * animatorValue * startRatio;
pathDst.reset();
// 兼容KITKAT的硬件加速,详见PathMeasure.getSegment()的注释
pathDst.rLineTo(0, 0);
pmList[curAnimIndex].getSegment(startD, pmList[curAnimIndex].getLength() * animatorValue, pathDst, true);
canvas.drawPath(pathDst, paint);
}
}
}
private void rebuildPathData() {
try {
pathCount = 0;
path = EasyPathParser.getInstance().parsePath(pathString, this, factor);
pm.setPath(path, false);
while (pm.nextContour()) {
++pathCount;
if (pathCount > maxPathCount) {
pathCount = maxPathCount;
break;
}
// 存储所有轮廓
pathDstList[pathCount - 1].reset();
// 兼容KITKAT
pathDstList[pathCount - 1].rLineTo(0, 0);
pm.getSegment(0, pm.getLength(), pathDstList[pathCount - 1], true);
pmList[pathCount - 1].setPath(pathDstList[pathCount - 1], false);
}
if (state == STATE_SHOW)
animatorValue = 1.0f;
if (animMode == ANIM_MODE_SEPARATE)
curAnimIndex = pathCount;
// 计算动画时间占比集
long totalDuration = 0L;
for (int i = 0; i < pathCount; i++) totalDuration += animDurationArr[i];
for (int i = 0; i < pathCount; i++) animDurationRatioArr[i] = 1.0f * animDurationArr[i] / totalDuration;
} catch (ParseException e) {
e.printStackTrace();
pathCount = 0;
pm = null;
pathDstList = null;
pmList = null;
state = STATE_NONE;
animatorValue = 0.0f;
curAnimIndex = 0;
}
}
private ValueAnimator getDrawAnimator() {
ValueAnimator drawAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
drawAnimator.addUpdateListener(updateListener);
drawAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimStart(state);
}
@Override
public void onAnimationEnd(Animator animation) {
if (animMode == ANIM_MODE_SEPARATE) {
if (curAnimIndex < pathCount) {
++curAnimIndex;
getDrawAnimator().setDuration(animDurationArr[curAnimIndex]).start();
} else {
if (isAnimRepeat) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimRepeat(state);
startDraw();
} else {
state = STATE_SHOW;
}
}
} else if (animMode == ANIM_MODE_TOGETHER) {
if (isAnimRepeat) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimRepeat(state);
startDraw();
} else {
state = STATE_SHOW;
}
}
if (null != onAnimatorListener)
onAnimatorListener.onAnimEnd(state);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
return drawAnimator;
}
private ValueAnimator getEraseAnimator() {
ValueAnimator eraseAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
eraseAnimator.addUpdateListener(updateListener);
eraseAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimStart(state);
}
@Override
public void onAnimationEnd(Animator animation) {
if (animMode == ANIM_MODE_SEPARATE) {
if (curAnimIndex > 0) {
--curAnimIndex;
getEraseAnimator().setDuration(animDurationArr[curAnimIndex]).start();
} else {
if (isAnimRepeat) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimRepeat(state);
startErase();
} else {
state = STATE_HIDE;
}
}
} else if (animMode == ANIM_MODE_TOGETHER) {
if (isAnimRepeat) {
if (null != onAnimatorListener)
onAnimatorListener.onAnimRepeat(state);
startErase();
} else {
state = STATE_HIDE;
}
}
if (null != onAnimatorListener)
onAnimatorListener.onAnimEnd(state);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
return eraseAnimator;
}
/**
* 开始绘制路径
*/
public void startDraw() {
state = STATE_ANIM_SHOW;
if (animMode == ANIM_MODE_SEPARATE)
curAnimIndex = 0;
getDrawAnimator().setDuration(animDurationArr[curAnimIndex]).start();
}
/**
* 开始绘制路径
*
* @param repeat 动画是否循环绘制
*/
public void startDraw(boolean repeat) {
isAnimRepeat = repeat;
startDraw();
}
/**
* 开始清除路径
*/
public void startErase() {
state = STATE_ANIM_HIDE;
if (animMode == ANIM_MODE_SEPARATE)
curAnimIndex = pathCount - 1;
getEraseAnimator().setDuration(animDurationArr[curAnimIndex]).start();
}
public void startErase(boolean repeat) {
isAnimRepeat = true;
startErase();
}
/**
* 停止循环绘制
*/
public void stopRepeat() {
isAnimRepeat = false;
}
/**
* 设置路径动画当前的进度
*
* @param progress 路径动画当前的进度,范围0.0f~1.0f
*/
public void setAnimProgress(float progress) {
if (progress < 0.0f)
progress = 0.0f;
else if (progress > 1.0f)
progress = 1.0f;
if (animMode == ANIM_MODE_TOGETHER) {
animatorValue = progress;
invalidate();
} else if (animMode == ANIM_MODE_SEPARATE) {
float curTotal = 0.0f;
for (int i = 0; i < pathCount; i++) {
curTotal += animDurationRatioArr[i];
if (progress <= curTotal) {
curAnimIndex = i;
animatorValue = 1.0f - (curTotal - progress) / animDurationRatioArr[i];
invalidate();
break;
}
}
}
}
/**
* 重置,在修改参数后,startDraw之前需要调用此方法
*/
public void reset() {
initPath();
initPaint();
initListener();
initDuration();
requestLayout();
invalidate();
}
// getters and setters
public int getFixedWidth() {
return fixedWidth;
}
public void setFixedWidth(int fixedWidth) {
this.fixedWidth = fixedWidth;
}
public int getFixedHeight() {
return fixedHeight;
}
public void setFixedHeight(int fixedHeight) {
this.fixedHeight = fixedHeight;
}
public String getPathString() {
return pathString;
}
public void setPathString(String pathString) {
this.pathString = pathString;
}
public int getStrokeColor() {
return strokeColor;
}
public void setStrokeColor(int strokeColor) {
this.strokeColor = strokeColor;
}
public int getStrokeWidth() {
return strokeWidth;
}
public void setStrokeWidth(int strokeWidth) {
this.strokeWidth = strokeWidth;
}
public float getStrokeFixedWidth() {
return strokeFixedWidth;
}
public void setStrokeFixedWidth(float strokeFixedWidth) {
this.strokeFixedWidth = strokeFixedWidth;
}
public boolean getStrokeIsRound() {
return strokeIsRound;
}
public void setStrokeIsRound(boolean strokeIsRound) {
this.strokeIsRound = strokeIsRound;
}
public String getAnimDurations() {
return animDurations;
}
public void setAnimDurations(String animDurations) {
this.animDurations = animDurations;
}
public int getAnimMode() {
return animMode;
}
public void setAnimMode(int animMode) {
this.animMode = animMode;
}
public boolean isDynamic() {
return dynamic;
}
public void setDynamic(boolean dynamic) {
this.dynamic = dynamic;
}
/**
* 获取当前状态
*
* @return 返回当前状态,包括STATE_NONE,STATE_SHOW,STATE_HIDE,STATE_ANIM_SHOW和STATE_ANIM_HIDE
*/
public int getState() {
return state;
}
/**
* 用于监听路径动画,可选择监听哪些动画状态
*/
public static abstract clreplaced OnAnimatorListener {
/**
* 动画开始时回调
*
* @param state 当前动画状态,包括STATE_SHOW,STATE_HIDE,STATE_ANIM_SHOW和STATE_ANIM_HIDE
*/
protected void onAnimStart(int state) {
}
/**
* 动画结束时回调
*
* @param state 当前动画状态,包括STATE_SHOW,STATE_HIDE,STATE_ANIM_SHOW和STATE_ANIM_HIDE
*/
protected void onAnimEnd(int state) {
}
/**
* 动画重复时回调,紧接着会回调onAnimStart
*
* @param state 当前动画状态,包括STATE_SHOW,STATE_HIDE,STATE_ANIM_SHOW和STATE_ANIM_HIDE
*/
protected void onAnimRepeat(int state) {
}
}
private OnAnimatorListener onAnimatorListener;
/**
* 添加监听路径动画执行的接口
*
* @param onAnimatorListener 用于监听路径动画
*/
public void addOnAnimatorListener(OnAnimatorListener onAnimatorListener) {
this.onAnimatorListener = onAnimatorListener;
}
}
18
Source : FloatParticle.java
with Apache License 2.0
from HpWens
with Apache License 2.0
from HpWens
/**
* Created by wenshi on 2018/7/4.
* Description 浮点粒子
*/
public clreplaced FloatParticle {
// 三阶贝塞尔曲线
private Point startPoint;
private Point endPoint;
private Point controlPoint1;
private Point controlPoint2;
private Paint mPaint;
private Path mPath;
private Random mRandom;
// 圆半径
private float mRadius = 5;
// 控件宽度
private int mWidth;
// 控件高度
private int mHeight;
private float mCurDistance = 0;
private static final int DISTANCE = 255;
private static final float MOVE_PER_FRAME = 1f;
// 火花外侧阴影大小
private static final float BLUR_SIZE = 5.0F;
// 路径测量
private PathMeasure mPathMeasure;
private float mMeasureLength;
public FloatParticle(int width, int height) {
mWidth = width;
mHeight = height;
mRandom = new Random();
startPoint = new Point((int) (mRandom.nextFloat() * mWidth), (int) (mRandom.nextFloat() * mHeight));
// 抗锯齿
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.WHITE);
// 防抖动
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL);
// 设置模糊效果 边缘模糊
mPaint.setMaskFilter(new BlurMaskFilter(BLUR_SIZE, BlurMaskFilter.Blur.SOLID));
mPath = new Path();
mPathMeasure = new PathMeasure();
startPoint.x = (int) (mRandom.nextFloat() * mWidth);
startPoint.y = (int) (mRandom.nextFloat() * mHeight);
}
public void drawParticle(Canvas canvas) {
// 初始化三阶贝塞尔曲线数据
if (mCurDistance == 0) {
endPoint = getRandomPointRange(startPoint.x, startPoint.y, DISTANCE);
controlPoint1 = getRandomPointRange(startPoint.x, startPoint.y, mRandom.nextInt(Math.min(mWidth, mHeight) / 2));
controlPoint2 = getRandomPointRange(endPoint.x, endPoint.y, mRandom.nextInt(Math.min(mWidth, mHeight) / 2));
// 添加贝塞尔曲线路径
mPath.reset();
mPath.moveTo(startPoint.x, startPoint.y);
mPath.cubicTo(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
mPathMeasure.setPath(mPath, false);
mMeasureLength = mPathMeasure.getLength();
}
// 计算当前坐标点
float[] loc = new float[2];
mPathMeasure.getPosTan(mCurDistance / DISTANCE * mMeasureLength, loc, null);
startPoint.x = (int) loc[0];
startPoint.y = (int) loc[1];
// 递增1
mCurDistance += MOVE_PER_FRAME;
if (mCurDistance >= DISTANCE) {
mCurDistance = 0;
}
canvas.drawCircle(startPoint.x, startPoint.y, mRadius, mPaint);
}
/**
* @param baseX 基准坐标x
* @param baseY 基准坐标y
* @param range 指定范围长度
* @return 根据基准点获取指定范围的随机点
*/
private Point getRandomPointRange(int baseX, int baseY, int range) {
int randomX = 0;
int randomY = 0;
// range指定长度为255,可以根据实际效果调整
if (range <= 0) {
range = 1;
}
// 我们知道一点(baseX,baseY)求与它距离长度为range的另一点
// 两点x方向的距离(随机产生)
int distanceX = mRandom.nextInt(range);
// 知道x方向的距离与斜边的距离求y方向的距离
int distanceY = (int) Math.sqrt(range * range - distanceX * distanceX);
randomX = baseX + getRandomPNValue(distanceX);
randomY = baseY + getRandomPNValue(distanceY);
if (randomX > mWidth) {
randomX = mWidth - range;
} else if (randomX < 0) {
randomX = range;
} else if (randomY > mHeight) {
randomY = mHeight - range;
} else if (randomY < 0) {
randomY = range;
}
return new Point(randomX, randomY);
}
/**
* 获取随机的正负值
*
* @return
*/
private int getRandomPNValue(int value) {
return mRandom.nextBoolean() ? value : 0 - value;
}
/**
* 设置圆半径
*
* @param radius
*/
public void setRadius(float radius) {
mRadius = radius;
}
}
See More Examples