我需要为折线图绘制动画。我将收到一个值数组(可能在0到10之间),并且随着时间的推移必须在图表上。我希望绘制线图,并且图形应该是可见的;动画。
我在这里查看了Anders Ericsson的教程:http://www.jayway.com/2012/08/29/creating-custom-android-views-part-3-animating-your-custom-views-smoothly/#comment-105813
此处的代码:https://github.com/andersericsson/ViewTutorialPart3
但我似乎无法摆动它以我的方式工作。
那里有另一种解决方案吗?
答案 0 :(得分:1)
我最终使用的解决方案涉及我扩展View
的课程中的一些代数。
该函数从活动中获取得分数组(值介于0和10之间),并使用2×2的值作为行的起点和终点(请注意,一行的终点是起点下一行)。
它计算线条的长度以及线条中的线条数量;还有x
方向移动的距离以及如何沿y
方向移动。
然后,它计算行中第一个段的结尾的x
和y
值,并绘制该段。
然后xDirection
和yDirection
分别添加到x
和y
点,然后再次绘制线条,现在包括第一段和第二段线。这是针对该行中的每个片段完成的,然后绘制从point A
到point B
的最后一行。
但它并不完整 - for loop
函数中的整个setData
应放在递归函数中,因为postInvalidateDelayed()
不会暂停执行for loop
。
但是,画布上根本没有画出任何内容,因此链接到我目前在SO上的另一个问题:Why are no lines drawn on my (custom View) canvas?
但对于这个问题,我认为我最终使用的解决方案可能并不那么糟糕。评论
public void setData(float[] scorePoints, float max, int totalScores){
Log.d(TAG, "Get stuff from activity");
scores = scorePoints;
numberOfScores = totalScores;
Log.d(TAG, "Number of scores = " + numberOfScores);
maxScore = max;
Log.d(TAG, "Max score = " + maxScore);
segmentToDraw = (float) 10;
//get the width of the area to draw
width = Math.abs(getWidth() - getPaddingLeft() - getPaddingRight());
//get the height of the area to draw
height = getHeight() - getPaddingTop() - getPaddingBottom();
Log.d(TAG, "Drawable area in view = " + width + " x " + height);
/*
* Now we start filling an array of points.
* The onDraw function will drawLines of groupings of four points in a given array.
*
* For the first segment, we'll draw from the x and y of the first point (which will be in the 1st and 2nd spots in our array)
* to the x and y of the first segment (which will be in the 3rd and 4th spots in our array).
* And then the 3rd and 4th spots in our array will be replaced by a new x and y
* marking the end of the second segment to be drawn from our first point.
*
* This will happen until the x and y is not smaller than the x and y of the final point of the line, any more.
* Then the 3rd and 4th spots in our array will be replaced by the x and y of the final point of the line.
*
* If there are more points to draw, the 5th and 6th spots in our array will also be created and filled with
* the x and y of the final point of the line because it'll be the first two values (x and y) for drawing the next line.
*
* So, yes, there will be duplicates in our array of points to draw, but a grouping of four spots will be used to draw one line,
* and the end point of the first line is the starting point of the second line, so we need it twice.
*/
points.add(getXPos(scores[0]));
points.add(getYPos(scores[0]));
points.add((float) 0);
points.add((float) 0);
x = points.get(0);
y = points.get(1);
startPoint = scores[0];
endPoint = scores[1];
for(int i=0; i<scores.length-1; i++){
String thePoints = "";
if(i>0){
startPoint = scores[i];
endPoint = scores[i+1];
x = points.get(i*4);
y = points.get((i*4) + 1);
}
startPointX = getXPos(startPoint);
startPointY = getYPos(startPoint);
endPointX = getXPos(endPoint);
endPointY = getYPos(endPoint);
distanceOfLine = (float) Math.sqrt(Math.pow((endPointX - startPointX), 2) + Math.pow((endPointY - startPointY), 2));
Log.d(TAG, "Distance of line = " + distanceOfLine);
//get number of segments in line
numberOfSegmentsInLine = (int) (distanceOfLine/segmentToDraw);
Log.d(TAG, "Number of segments in line = " + numberOfSegmentsInLine);
//get distance to move in Y direction
yDirection = (float) ((endPointY - startPointY)/ (float) numberOfSegmentsInLine);
Log.d(TAG, "Move " + yDirection + " in Y direction");
//get distance to move in X direction
xDirection = (float) ((endPointX - startPointX)/ (float) numberOfSegmentsInLine);
Log.d(TAG, "Move " + xDirection + " in X direction");
//loop for each segment
for(int j=0; j<numberOfSegmentsInLine; j++){
x += xDirection;
y += yDirection;
points.set(points.size()-2, Float.valueOf(x));
points.set(points.size()-1, Float.valueOf(y));
Log.d(TAG, "Line : " + (i+1) + " Segment : " + j);
Log.d(TAG, "X = "+ (x+xDirection) + " Y = " + (y+yDirection));
Log.d(TAG, "Call invalidate now!");
//invalidate();
//postInvalidateDelayed(delayMilliseconds);
}
//draw final line
points.set(points.size()-2, endPointX);
points.set(points.size()-1, endPointY);
invalidate();
//postInvalidateDelayed(delayMilliseconds);
if(i<scores.length-2){
points.add(endPointX);
points.add(endPointY);
points.add((float) 0);
points.add((float) 0);
}
for(int k =0; k<points.size(); k++){
thePoints = thePoints + " : " + points.get(k);
}
Log.d(TAG, "Points array = " + thePoints);
}
}
@Override
public void onDraw(Canvas canvas){
//setWillNotDraw(true);
Log.d(TAG, "DRAW DAMNIT!!!");
Log.d(TAG, "Width = " + (int) width + " Height = " + (int)height);
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(4);
paint.setColor(Color.RED);
//paint.setAntiAlias(true);
//paint.setShadowLayer(4, 2, 2, 0x81000000);
Bitmap bitmap = Bitmap.createBitmap((int)width, (int)height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
String drawPointsGo = "";
float[] drawPoints = new float[points.size()];
for(int i=0; i<points.size(); i++){
Float f = points.get(i);
drawPoints[i] = (float) (f != null ? f : 0.0);
drawPointsGo = drawPointsGo + " : " + drawPoints[i];
}
Log.d(TAG, "Draw Points: " + drawPointsGo);
canvas.drawLines(drawPoints, paint);
}
答案 1 :(得分:1)
尝试查看CountDownTimer或Runnable,以便onTick()或何时发布,您可以通过绘制更多像素来更新您的线。这会让你在另一行之后绘制一条线,但会产生动画效果。
答案 2 :(得分:0)
以下是尝试的一般方向:
确保您对Canvas
drawing感到满意。
然后,您将需要创建一个新的View
(它的子类)并覆盖onDraw
方法。
此方法应仅根据动画开始后的elapsed time部分绘制图形。