I generate an ellipse and I try to reshape with respect to sweepAngle_speed that u can see below. This sweepAngle_speed come from MainActivity.java. In MainActivity.java, I create a seekbar and I use an algorithm between value of seekbar and sweepAngle_speed, therefore I expected a change in filled area in my ellipse. onDraw function is not called directly, so I use invalidate function in my getLog function which is created by me. However I cannot call onDraw function anyway. When I run the code, onDraw function is called directly by system 3 times, however when I change seekbar value, I do not call onDraw function anyway. My first question is that How onDraw function is called directly by system ? The second one is how I can call onDraw function during system is working. Thanks.
CustomView.java
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context);
m_Context = context;
getLog();
// create the Paint and set its color
}``
#Override
protected void onDraw(Canvas canvas) {
//c=canvas;
//super.onDraw(c);
Paint p1 = new Paint();
RectF rectF = new RectF(-750, 0, 750, 720);
//p1.setColor(Color.parseColor("#34ebe2"));
p1.setShader(new LinearGradient(0, -360, 0, getHeight(), Color.CYAN, Color.BLUE, Shader.TileMode.MIRROR));
Log.d(TAG, "CANVAS: onDraw içine girdi ve Speed angle: " + sweepAngle_speed);
canvas.drawArc(rectF, 90, -sweepAngle_speed, true, p1);
}
public void getLog () {
paint = new Paint();
paint.setColor(Color.BLUE);
Log.d(TAG, "Speed geldi buraya ve invalidate yaptı");
setWillNotDraw(false);
//this.invalidate();
this.invalidate();
}
}
You can't call onDraw directly. You can use the invalidate method which will redraw it
You can make a function inside CustomView class e.g:
public void setSpeed(int sweepAngle_speed){
this. sweepAngle_speed = sweepAngle_speed;
invalidate(); // This invalidate will call onDraw and draw your view again
}
If you extend ViewGroup so you need to call setWillNotDraw(false) in the constructor of your ViewGroup
Related
I need to draw some text on canvas, this text may single line or multi lines. I found StaticLayout can fill this require. But When I create an StaticLayout and after I want to draw it, I call getHeight(), I found it always return the line count. Shouldn't this function return the number of pixels?
This is my code:
m_staticLayout = new StaticLayout(m_message, textPaint, m_messageWidth,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false);
Any help will be appreciated.
Firstly, StaticLayout is deprecated.
The reason it probably doesn't return pixels is because we haven't drawn anything yet, we're just initializing the StaticLayout. Hence, it returns the line count which we could probably use in the future. If you are trying to draw some text on Canvas, I wouldn't recommend using StaticLayout.
Instead, use the Paint class, Canvas, and Bitmap. Think of paint as the ink of the Canvas(which hosts all the draw calls). Canvas will draw into your Bitmap.
We will have to create the Paint, set up it's attributes, and then host the draw call drawText to the canvas. The Canvas will then draw the text using the Paint we created.
All of this will be in an Activity which extends View, which we will then pass as the View in setContentView for our MainActivity
This is how we can implement this:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
OtherActivity otherActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
otherActivity = new OtherActivity(this);
otherActivity.setBackgroundColor(Color.GRAY);
setContentView(otherActivity);
}
}
OtherActivity.java:
public class OtherActivity extends View {
public OtherActivity(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(20);
canvas.drawText("Some Text", 10, 25, paint);
}
}
I have a LinearLayout whose background color is set to black. In this LinearLayout, I have a View in which I draw using Canvas. Because the onDraw() method will be called multiple times, I want to clear what I drew previously when I call onDraw() method, thus I use Canvas.drawColor(Color.BLACK) to clear the canvas.
But what I get is a black screen without anything even when I draw something new. I can already draw something before I add Canvas.drawColor(Color.BLACK) within onDraw() method.
EDIT: codes of my onDraw() method
String value = "";
static Bitmap bitmap;
static Canvas canvas;
public void init(){// this is called by constructor method
this.setWillNotDraw(false);
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas();
canvas.setBitmap(bitmap);
}
public void onDraw(Canvas canvas){
canvas.drawBitmap(bitmap, 0, 0, null);
drawGrid();
}
public void drawGrid(){
Paint paint = new Paint();
paint.setColor(Color.GRAY);
paint.setStrokeWidth(1);
canvas.drawText(value, somex, somey, paint);
}
public void changeData(String value){
this.value = value;
this.postInvalidate();
}
Another question, where is the right place I call Canvas.drawColor(Color.BLACK)?
I used the below code and it works for me. Clearing the draw on canvas.
public void resetBitmapCanvasAndPath() {
// TODO Auto-generated method stub
mDrawingUtilities.mBitmap = Bitmap.createBitmap(Constants.SCREEN_WIDTH,Constants.SCREEN_HEIGHT ,
Bitmap.Config.ARGB_8888);
mDrawingUtilities.mCanvas = new Canvas(mDrawingUtilities.mBitmap);
mDrawingUtilities.mPath = new Path();
}
Here's a link similar to your question and have a look at the accepted answer.
How to clear finger paint?
use Color.TRANSPARENT instead of using Color.BLACK
Okay, so I'm trying to draw to a canvas on Android from outside of the onDraw method.
It's just easiest to show my code:
public class TestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Paint p = new Paint();
p.setColor(Color.GREEN);
Panel a = new Panel(this,150,150,50,p);
a.drawThing();
setContentView(a);
}
class Panel extends View{
private float radius, x, y;
private Canvas CAN;
private Paint p;
public Panel(Context context, float x, float y, float radius, Paint p){
super(context);
this.x = x;
this.y = y;
this.radius = radius;
this.p = p;
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
CAN = canvas;
}
public void drawThing(){
CAN.drawCircle(x, y, radius, p);
}
}
}
Do you see what I'm trying to do? But for some reason it throws a NullPointerException
Many of the graphics resources are explicitly freed/released after they've been used. I'm not exactly sure why they do this, but whatever the reason, they don't you to do what you're trying.
Instead of drawing outside of the onDraw method, use some kind of flag to change what the onDraw method is doing. When you want to draw some specific thing, you can set the right flag, and call invalidate().
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
if (doThing) {
canvas.drawCircle(x, y, radius, p);
}
}
EDIT
Something else to consider is drawing to and "off-scrren" source. This means using some kind of graphics representation like a bitmap as a buffer that you can draw to in other code. This won't update your gui, but it will give you the chance to do some heavy duty drawing without locking up the user's device. Once you are done drawing to the bitmap (or whatever) you can invalidate your view and draw it to the screen in the onDraw(Canvas) method.
I'm pretty sure that the null pointer happens because you're calling drawSomething before onDraw ever gets called. So CAN is null.
You can draw onto canvas outside of the onDraw. See this Can we have two canvases in an activity ? (OR) Having a canvas outside the onDraw() is not working for more info.
so i created a view called "drawable view"
class DrawableView extends View{
Context mContext;
int touches=0,k,Xoffs,clicks=0;
double x_1 = 0,x_2=0;
private float mLastTouchX, mLastTouchY;
public DrawableView(Context context) {
super(context);
mContext = context;
}
....
#Override
protected void onDraw(Canvas canvas){
Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
canvas.drawColor(Color.BLUE);
myPaint.setColor(Color.WHITE);
canvas.drawCircle(200, 100, 20, myPaint);
}
..... more code....
}
and it can only be invalidated within the ondraw command! ie: calling "invalidate();" at the end of the ondraw command causes it to loop.
I have tried many times to call g_draw.invalidate(); or g_draw.postInvalidate(); (g_draw is the name of the created Drawable View)from other classes and even the main activity class and it doesnt work. why and how can i fix it?
thanks
If you want continious onDraw invoking try doing it in another thread. Create a thread, and from its run method try doing postInvalidate.
It always worked for me.
Another thing is that when you draw a circle once, next time wont make any difference - it will look the same.
You may want to call invalidate() somewhere in your DrawableView class. For example, if you want your view to redraw itself after any touch event, you would do something like this:
public boolean onTouchEvent( MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
invalidate();
}
}
This is how I draw the movable pieces in my puzzle game.
I'm creating a custom widget by extending LinearLayout:
public class MyWidget extends LinearLayout {
private static Paint PAINT = new Paint(Paint.ANTI_ALIAS_FLAG);
static {
PAINT.setColor(Color.RED);
}
public MyWidget(Context context) {
this(context, null);
}
public MyWidget(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight()/2, canvas.getWidth()/2, PAINT);
// never gets called :-(
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
// this gets called, but with a canvas sized after the padding.
}
}
I can add children just fine, but I'm never getting my custom onDraw() being called. dispatchDraw() gets called, but that seems to have a different canvas (the one that's within the padding. I need to draw on the whole layout area). Is there some flag that needs to get set to get onDraw() called for the layout?
You need to call setWillNotDraw(false) in your constructor.
Because by default a layout does not need to draw, so an optimization is to not call is draw method. By calling setWillNotDraw(false) you tell the UI toolkit that you want to draw.