I've been struck hard with an issue with the path class that is used to draw smooth lines on canvas with the canvas.drawPath(path,paint) function . Path class is useful for smoothing out lines with the path.quadTo() and cubeTo() function . But they do not let you draw a smoothed out line with varying thickness . I want to draw a Path on the canvas with increasing thickness up to a certain threshold width and then slim out at the end . Also i tried using a number of paths at every touch point of user but that fails when the user moves his finger really fast , because at that time a single path of a long length is obtained . Please help me i am in big trouble with this . Is there any other way of smoothing out lines .
Thank You
I think you are asking how to vary the width of the Path that is drawn using the canvas.drawPath() method. The following code snippet should help you regarding that:
private Paint myPaint;
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeJoin(Paint.Join.ROUND);
myPaint.setStrokeCap(Paint.Cap.ROUND);
if(someFlag != thresholdValue)
myPaint.setStrokeWidth(20);
else
{
myPaint.setStrokeWidth(someReducedValue); // or have a counter updated in your thread to regularly decrement the value
}
//..
..//
canvas.drawPath(path, myPaint); // inside onDraw() where path corresponds to your Path variable
The correct way to do this is to use the PathMeausre class , where we can easily get subPaths from a prent path and manuplate them accordingly . When i ll be done with the code ,i ll post the snippet soon.
Related
is there any example, howto place any of charts in MPAndroidChart library to homescreen widget?
//i tried to use getChartbitmap(), but
1)bitmap is not created immediately after calling invalidate(), so it return null
2)i dont see way, howto initialize chart class without placing resources - which i cant do
for widget.
anybody have some successful example ?
The chart needs some milliseconds to draw the content onto the Bitmap. That is the reason why calling getChartBitmap() right after invalidate() will not return a valid Bitmap.
Try using a Handler and delay the time before retrieving the Bitmap by abound 100ms.
Try this code
BarData chartData =...
BarChart chart = new BarChart(mContext);
chart.setData(chartData);
chart.measure(View.MeasureSpec.makeMeasureSpec(300,View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(500,View.MeasureSpec.EXACTLY));
chart.layout(0, 0, chart.getMeasuredWidth(), chart.getMeasuredHeight());
Bitmap chartBitmap = chart.getChartBitmap();
In Activity with chart, function getChartBitmap() working fine! It's return bitmap without any errors. IMHO that's the problem, in widget we don't have an activity, placing created chart in layout is not take effect :( So, we can't have a widget with this chart at all, and it's very sad - this chart so really cool.
I've set global variables x,y in the Activity class.
I start a thread "t0" that continually update globals x and y.
I have onDraw pseudocode as follows (all on the UI thread):-
View.onDraw(){
if (x,y changed value) {
x0=x;
y0=y;
loop (x0-- until x0==0){
canvas.drawBitmap(bmp, x0, y0, bitmapPaint);
invalidate();
}
}
}
I was hoping that I'd see an animation of the bitmap moving across the screen on the x-axis, with each invalidate() re-drawing the new position. Instead I see it 'jump' to the last x position 0 (no intermediate stages).
I'm making the assumption that although x and y are updating via t0, I'm not too concerned since the loop is busy with the original x,y values (assigned to x0,y0).
I observe x,y updating and code is executed inside the 'if loop' (I see this via debug).
I tried adding a delay, but it didn't seem to make any difference. I can get it to re-draw directly to a new x,y position, but I need a smooth 'transition' via the loop to happen from one-x0-coord to another.
Any hints or tips would be appreciated.
Thanks in advance.
Steve
I think you can't cause an onDraw within an onDraw. calling invalidate() only causes that onDraw will be called after the current onDraw finishes. I am not sure how you really implemented it since it's pseudocode but i imagine you don't want the loop in the onDraw but do somethinglike this:
View.onDraw(){
if (x,y changed value) {
x0=x;
y0=y;
if (x0!=0){
x0--;
canvas.drawBitmap(bmp, x0, y0, bitmapPaint);
invalidate();
}
}
}
What is happening here I guess is, intermediates are getting drawn. But there is not enough time to show those. you have to set some thread.sleep inside it. It will work.
I want my sprite to move from one point to another point in a curve path, so i am using Bezierto in my code, but it doesnt seems to work out as it shows an error on bezier keyword
(The local variable bezier may not have been initialized). please help me.
my code is as follows
//initial point of sprite
sprite1pos=CGPoint.ccp((winSize.width/2+winSize.width/2),0);
//now the bezier config declaration
CCBezierConfig bezier;
bezier.controlPoint_1=CGPoint.ccp(sprite1pos.x,sprite1pos.y);
bezier.controlPoint_2=CGPoint.ccp(winSize.width/2,winSize.height/2);
bezier.endPosition=CGPoint.ccp(0,0);
CCBezierTo action = CCBezierTo.action(3, bezier);
sprite1.runAction(action);
You need to initialize your bezier variable.
The line :
CCBezierConfig bezier;
Does not initialize the bezier variable.
It should be :
CCBezierConfig bezier = new CCBezierConfig(<arguments if any>);
My project is based on surfaceView and up until now I've had all of my rendering in onDraw which I am overriding. All seemed to be OK.
However, I've just updated my SDK and now it gives me an error telling me:
Suspicious method call; should probably call "draw" rather than "onDraw"
Could someone please explain the difference between these two?
I've read some similar questions around the net but I've not found an explanation that I understand.
Thanks
I tried cleaning my project and it did solve the problem. Try it.
SurfaceView.draw() basically calls View.draw(); If you want to implement your drawing, you should do it in View.onDraw() which is for you to implement which even says in the source code comments.
This method is called by ViewGroup.drawChild() to have each child view
draw itself. This draw() method is an implementation detail and is not
intended to be overridden or to be called from anywhere else other
than ViewGroup.drawChild().
As for difference between them:
draw():
13416 /*
13417 * Draw traversal performs several drawing steps which must be executed
13418 * in the appropriate order:
13419 *
13420 * 1. Draw the background
13421 * 2. If necessary, save the canvas' layers to prepare for fading
13422 * 3. Draw view's content
13423 * 4. Draw children
13424 * 5. If necessary, draw the fading edges and restore layers
13425 * 6. Draw decorations (scrollbars for instance)
13426 */
onDraw() is empty. Its for you to implement.
I have the problem since ever.
I handle it like this:
1) Declare a method like the following.
#SuppressLint("WrongCall")
public void drawTheView() {
theCanvas = null;
try{
theCanvas = getHolder().lockCanvas();
if(theCanvas != null) {
onDraw(theCanvas);
}
} finally {
getHolder().unlockCanvasAndPost(theCanvas);
}
}
2) Now you can modify the onDraw() Method:
#Override
public void onDraw(Canvas canvas) {
//Do some drawing
}
You can call the drawTheView() method from everywhere you want and call the onDraw() method this way without getting the error...
I think this is a practical way.
Note that in the case of drawing, overriding draw() and calling super.draw is often used when a ViewGroup wants to draw content over its child views. Content drawn in onDraw will appear under children.
As friiky said, #SuppressLint("WrongCall") fixed my problem. However it must be in front of the method name, not the above.
What I did is put mouse over the error code, right click and select Add #SuppressLint("WrongCall")
onDraw gives you a canvas to draw to the screen.
draw() allows you to manually draw a canvas to the screen (you have to make the canvas yourself).
I am going crazy trying to figure this out. I am trying to make an array or arraylist of Rect (rectangles) that I can update the coordinates and draw on the screen(to make them move).
Right now I have a separate class called Fire in which I make a new rectangle each iteration with the new coordinates in its own onDraw() method. In the View's onDraw() method's first iteration I add a new Fire to an arraylist.
In the Fire class I have:
public void onDraw(Canvas canvas){
moveF();
Rect r = new Rect(_l,_t,_r,_b);
canvas.drawRect(r, paint);
}
In the View class I have:
protected void onDraw(Canvas canvas) {
int i = 0;
canvas.drawColor(Color.WHITE);
if(i==0){
fires.add(new Fire(20,100,40,120));
i++;
}
for(Fire fire : fires){
fire.onDraw(canvas);
}
}
I got rid of pointless parts of code, but this is the important stuff. The Rectangle prints, however it prints all the previous locations as well and I don't understand why. I have been trying to fix this forever and any help you guys could give would be greatly appreciated. I was able to implement this in java easy, but android is giving me problems.
Thanks in advance!!!
From the code, you are adding new rectangles to the list, and then drawing each rectangle. But from the description, it seems that you just want to draw a single rectangle, with updated coordinates.
Instead of creating a new Rect each time, reuse a rectangle and update its coordinates with set(...).
A second problem is that you set i=0 and then immediately check for i==0, which would be always true. Try something like this instead:
static final Rect rect = new Rect();
// your code here
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
moveF();
rect.set(_l,_t,_r,_b);
canvas.drawRect(rect, paint);
}
With each call to View.onDraw you create a new fire and add it to your list.
Then you iterate over all fires and draw them.
So you get more and more fires.
Do all fires move the same way or is there some random component?
It might be that you don't see the previous locations of one fire, but that there are many fires moving on the same path.
Do you want to have 1 fire moving around or more and more fires moving around independently?