Hi i draw a canvas for my application
here is the code my canvas
public class Canvas1 extends View{
int i;
int k;
float l,m;
public Canvas1(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public Canvas1 (Context context, AttributeSet attrs) {
super(context, attrs);
}
public Canvas1 (Context context, AttributeSet ats, int ds) {
super(context, ats, ds);
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
Paint paint1=new Paint(Color.BLACK);
Paint paint=new Paint(200);
paint.setStrokeWidth((float)0.5);
canvas.drawLine(0,0,0,getMeasuredHeight(), paint1);
canvas.drawLine(0,0, getMeasuredWidth(), 0, paint1);
canvas.drawLine(0,getMeasuredHeight(), getMeasuredWidth(),getMeasuredHeight(), paint1);
canvas.drawLine(getMeasuredWidth(),getMeasuredHeight(), getMeasuredWidth(), 0, paint1);
//canvas.drawLine(0, 0, ((float)getMeasuredWidth()), ((float)getMeasuredHeight()), paint);
if(l!=0||m!=0)
{
canvas.drawLine(getMeasuredWidth()/2,getMeasuredHeight()/2,getMeasuredWidth()/2,getMeasuredHeight(),paint);
canvas.drawLine(0,0,getMeasuredWidth()/2,getMeasuredHeight()/2,paint);
}
for(int i=1;i<5;i++)
canvas.drawLine(((float)getMeasuredWidth())/5*i, 0, ((float)getMeasuredWidth()/5*i),getMeasuredHeight(), paint);
for(int i=0;i<5;i++)
canvas.drawLine(0, getMeasuredHeight()/5*i, getMeasuredWidth(), getMeasuredHeight()/5*i, paint);
canvas.save();
}
public Boolean setline(float d,float e){
l=d;
m=e;
Log.i("Hello Canvas",l+" "+m+" ");
return true;
}
}
now i am trying to call the function setline() from my main activity in this activity there is an array of canvas . here is the code of my activity
public class HelloCanvasActivity extends Activity {
/** Called when the activity is first created. */
Integer[] in={R.id.can1,R.id.can2,R.id.can3,R.id.can4,R.id.can5,R.id.can6,R.id.can7,R.id.can8};
float x,y;
int j=0;
Canvas1[] can=new Canvas1[8];
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
for(int i=0;i<8;i++)
{
can[i]=(Canvas1)findViewById(in[i]);
}
can[0].setline((float)0.5,(float) 0.5);
new Thread(new Runnable(){
public void run(){
for(int i=0;i<8;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
can[i].setline((float)0.5,(float)0.5);
}
}
}).start();
}
}
when i omit Thread.sleep(1000) from my code lines are drawing but when i put Thread.sleep(1000) setline is calling after 1 second i am getting log in my log table of Hello World,but no line is drawing on canvas please help me in finding where i am wrong.
In your setline method, call invalidate()
Related
i need to by clicking on the button redraw the picture, but after method invalidate onDraw method is not called. But the call onDraw only happens after running the application.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Draw draw = new Draw(this);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
draw.setA(40);
draw.setB(300);
draw.invalidate();
}
});
}
}
Here is the code Draw.java
public class Draw extends View {
private Paint mPaint;
private int a;
private int b;
public Draw(Context context) {
super(context);
init();
}
public Draw(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Draw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(5);
setWillNotDraw(false);
a = 0;
b = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.WHITE);
canvas.drawPaint(mPaint);
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true);
canvas.drawLine(80, 50, 80, 500, mPaint);
canvas.drawLine(80, 50, 70, 85, mPaint);
canvas.drawLine(80, 50, 90, 85, mPaint);
canvas.drawLine(80, 500, 500, 500, mPaint);
canvas.drawLine(500, 500, 465, 510, mPaint);
canvas.drawLine(500, 500, 465, 490, mPaint);
mPaint.setTextSize(35);
mPaint.setStrokeWidth(2);
canvas.drawText("X", 480, 540, mPaint);
canvas.drawText("Y", 45, 80, mPaint);
canvas.drawText("0", 70, 540, mPaint);
drawFunction(canvas, a, b);
}
public void drawFunction(Canvas canvas, int a, int b) {
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true);
canvas.drawLine(80, 500, a, b, mPaint);
}
public void setA(int a) {
this.a = a;
}
public void setB(int b) {
this.b = b;
}
}
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<labs.example.function.Draw
android:layout_width="match_parent"
android:layout_height="wrap_content">
</labs.example.function.Draw>
</RelativeLayout>
Thanks in advance.
Add an id
<labs.example.function.Draw
android:id="#id/draw"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</labs.example.function.Draw>
Replace
final Draw draw = new Draw(this);
by
final Draw draw = (Draw) findViewById(R.id.draw); // need to refer to the view in xml.
If you use final Draw draw = new Draw(this); you need to add that view to your view hierachy.
Did you try to call setWillNotDraw(false). In this post you can see that by default all ViewGroup sub-classes do not call their onDraw method.
I am trying to override ondraw in EditText,use canvas to write words on EditText.
But when I setInputType in EditText,it can't display any words.
I don't know how it works.
public class Input extends EditText{
private static int paddingHintText = 30;
private static int paddingInput = 200;
private static int hintTextSize = 40;
private String textString = "test";
Paint paint;
public Input(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
setBackgroundResource(R.drawable.editseletor);
setPadding(paddingInput, 0, 0, 0);
setGravity(Gravity.CENTER);
//if I use it,it can't display any words
//setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_PASSWORD);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
paint.setColor(Color.rgb(50, 50, 50));
paint.setTextSize(hintTextSize);
canvas.drawText(textString, paddingHintText, this.getHeight()/2+hintTextSize/2-5, paint);
canvas.drawLine(0, 50, 200, 50, paint);
super.onDraw(canvas);
}
public void setLeftText(String textString){
this.textString = textString;
}
}
I just get green Pixels at the border of my drawn bitmap if I set the alpha of the paint to 200.
The problem does not appear if I set the alpha to 100 or 255.
How can I fix this?
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private DrawThread drawThread;
private boolean surfaceCreated;
Paint paint = new Paint();
private Bitmap bitmap;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.circleyellow);
paint.setAlpha(200);
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bitmap, 200, 200, paint);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
setSurfaceCreated(true);
createDrawThread();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
setSurfaceCreated(false);
}
public void setSurfaceCreated(boolean surfaceCreated) {
this.surfaceCreated = surfaceCreated;
}
public boolean getSurfaceCreated() {
return surfaceCreated;
}
public void createDrawThread(){
if (drawThread != null) {
drawThread.destroy();
}
drawThread = new DrawThread(getHolder(), this);
drawThread.setRunning(true);
drawThread.start();
}
public DrawThread getDrawThread(){
return drawThread;
}
I think I have solved the problem. A friend has told me this solution:
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
bitmap = BitmapFactory.decodeResource(
getResources(),
R.drawable.circleyellow
);
paint.setAlpha(200);
}
I'm making an Android app and I've got a tricky thing to do.
I need to draw a path on a canvas but the drawing should be animated (ie. drawing point after point with a slight delay).
Is it possible to make something like this using Android SDK?
If not, how could I produce this effect?
Try this code, I used it to draw a heartbeat using Path & Canvas:
public class TestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new HeartbeatView(this));
}
public static class HeartbeatView extends View {
private static Paint paint;
private int screenW, screenH;
private float X, Y;
private Path path;
private float initialScreenW;
private float initialX, plusX;
private float TX;
private boolean translate;
private int flash;
private Context context;
public HeartbeatView(Context context) {
super(context);
this.context=context;
paint = new Paint();
paint.setColor(Color.argb(0xff, 0x99, 0x00, 0x00));
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStyle(Paint.Style.STROKE);
paint.setShadowLayer(7, 0, 0, Color.RED);
path= new Path();
TX=0;
translate=false;
flash=0;
}
#Override
public void onSizeChanged (int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenW = w;
screenH = h;
X = 0;
Y = (screenH/2)+(screenH/4)+(screenH/10);
initialScreenW=screenW;
initialX=((screenW/2)+(screenW/4));
plusX=(screenW/24);
path.moveTo(X, Y);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.save();
flash+=1;
if(flash<10 || (flash>20 && flash<30))
{
paint.setStrokeWidth(16);
paint.setColor(Color.RED);
paint.setShadowLayer(12, 0, 0, Color.RED);
}
else
{
paint.setStrokeWidth(10);
paint.setColor(Color.argb(0xff, 0x99, 0x00, 0x00));
paint.setShadowLayer(7, 0, 0, Color.RED);
}
if(flash==100)
{
flash=0;
}
path.lineTo(X,Y);
canvas.translate(-TX, 0);
if(translate==true)
{
TX+=4;
}
if(X<initialX)
{
X+=8;
}
else
{
if(X<initialX+plusX)
{
X+=2;
Y-=8;
}
else
{
if(X<initialX+(plusX*2))
{
X+=2;
Y+=14;
}
else
{
if(X<initialX+(plusX*3))
{
X+=2;
Y-=12;
}
else
{
if(X<initialX+(plusX*4))
{
X+=2;
Y+=6;
}
else
{
if(X<initialScreenW)
{
X+=8;
}
else
{
translate=true;
initialX=initialX+initialScreenW;
}
}
}
}
}
}
canvas.drawPath(path, paint);
//canvas.restore();
invalidate();
}
}
}
It uses drawing a Path point by point with couple of effects using counters. You can take what you need and transfer it to SurfaceView which is more efficient.
I hope this is what you are looking for. It draws the path on user touch, you could simply tweek it to achieve what you desire.
public class MyCanvas extends Activity implements OnTouchListener{
DrawPanel dp;
private ArrayList<Path> pointsToDraw = new ArrayList<Path>();
private Paint mPaint;
Path path;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
dp = new DrawPanel(this);
dp.setOnTouchListener(this);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(30);
FrameLayout fl = new FrameLayout(this);
fl.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
fl.addView(dp);
setContentView(fl);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
dp.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
dp.resume();
}
public class DrawPanel extends SurfaceView implements Runnable{
Thread t = null;
SurfaceHolder holder;
boolean isItOk = false ;
public DrawPanel(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
}
#Override
public void run() {
// TODO Auto-generated method stub
while( isItOk == true){
if(!holder.getSurface().isValid()){
continue;
}
Canvas c = holder.lockCanvas();
c.drawARGB(255, 0, 0, 0);
onDraw(c);
holder.unlockCanvasAndPost(c);
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
synchronized(pointsToDraw)
{
for (Path path : pointsToDraw) {
canvas.drawPath(path, mPaint);
}
}
}
public void pause(){
isItOk = false;
while(true){
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
break;
}
t = null;
}
public void resume(){
isItOk = true;
t = new Thread(this);
t.start();
}
}
#Override
public boolean onTouch(View v, MotionEvent me) {
// TODO Auto-generated method stub
synchronized(pointsToDraw)
{
if(me.getAction() == MotionEvent.ACTION_DOWN){
path = new Path();
path.moveTo(me.getX(), me.getY());
//path.lineTo(me.getX(), me.getY());
pointsToDraw.add(path);
}else if(me.getAction() == MotionEvent.ACTION_MOVE){
path.lineTo(me.getX(), me.getY());
}else if(me.getAction() == MotionEvent.ACTION_UP){
//path.lineTo(me.getX(), me.getY());
}
}
return true;
}
}
I have made it with ObjectAnimator.
We have any Path and our CustomView (in wich we'll draw our path)
private CustomView view;
private Path path;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(R.id.custom_view);
path = new Path();
path.moveTo(0f, 0f);
path.lineTo(getResources().getDimension(R.dimen.point_250), 0f);
path.lineTo(getResources().getDimension(R.dimen.point_250), getResources().getDimension(R.dimen.point_150));
findViewById(R.id.btnStart).setOnClickListener(v -> {
test();
});
}
private void test() {
ValueAnimator pathAnimator = ObjectAnimator.ofFloat(view, "xCoord", "yCoord", path);
pathAnimator.setDuration(5000);
pathAnimator.start();
}
And just pass our "xCoord" and "yCoord" to CustomView
public class CustomView extends View {
private Paint paint;
private float xCoord;
private float yCoord;
private Path path = new Path();
public void setXCoord(float xCoord) {
this.xCoord = xCoord;
}
public void setYCoord(float yCoord) {
this.yCoord = yCoord;
path.lineTo(xCoord, yCoord);
invalidate();
}
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(20);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, paint);
}
}
This might help... It draws adjacent circles instead of a path to simulate an animatable path.
public class PathAnimatable {
private final float CIRCLE_SIZE = 2.5f;
public float SPPED_SCALE = 1f;
private float steps = 0;
private float pathLength;
private PathMeasure pathMeasure;
private float totalStepsNeeded;
private float[] point = new float[]{0f, 0f};
private float stride;
public PathAnimatable() {
this(null);
}
public PathAnimatable(Path path) {
super(path);
init();
}
private void init() {
pathMeasure = new PathMeasure(path, false);
pathLength = pathMeasure.getLength();
stride = CIRCLE_SIZE * 0.5f;
totalStepsNeeded = pathLength / stride;
steps = 0;
}
#Override
public void setPath(Path path) {
super.setPath(path);
init();
}
// Called this from your locked canvas loop function
public void drawShape(Canvas canvas, Paint paint) {
if (steps <= pathLength) {
for (float i = 0; i < steps ; i += stride) {
pathMeasure.getPosTan(i, point, null);
canvas.drawCircle(point[0], point[1], CIRCLE_SIZE, paint);
}
steps += stride * SPPED_SCALE;
} else {
steps = 0;
}
}
}
I am trying an example having SurfaceView. I have inherited my class from SurfaceView and using as follows:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
Context context;
MySurfaceViewThread mThread;
SurfaceHolder holder;
Paint paint;
int x = 20, y = 20, r = 10;
public void init() {
holder = getHolder();
holder.addCallback(this);
mThread = new MySurfaceViewThread(getHolder(), this);
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeCap(Cap.ROUND);
paint.setStrokeWidth(1);
paint.setColor(Color.rgb(255, 255, 255));
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context = context;
init();
}
public MySurfaceView(Context context, AttributeSet attr) {
super(context,attr);
this.context = context;
init();
}
public MySurfaceView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
this.context = context;
init();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mThread.isRunning = false;
while (true) {
try {
mThread.join();
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// canvas.drawColor(0, Mode.CLEAR);
x += 2;
y += 2;
r += 3;
canvas.drawColor(Color.rgb(x%255, y%255, (x+y)%255));
canvas.drawCircle(x, y, r, paint);
canvas.drawText("x:"+x, 100, 100, paint);
Log.d("onDraw","onDraw()"+"x:"+x + ",y:"+y+",r:"+r);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.d("surfaceCreated", "surfaceCreated()");
mThread.isRunning = true;
mThread.start();
}
}
I am updating my Canvas from a Thread which is:
public class MySurfaceViewThread extends Thread {
SurfaceHolder holder;
MySurfaceView surfaceView;
boolean isRunning = false;
public MySurfaceViewThread(SurfaceHolder holder, MySurfaceView surfaceView) {
Log.d("thread","thread constructor");
this.holder = holder;
this.surfaceView = surfaceView;
}
#Override
public void run() {
Log.d("run","run()");
while(isRunning) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized(holder) {
surfaceView.onDraw(canvas);
}
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
holder.unlockCanvasAndPost(canvas);
Log.d("canvas status", "canvas unlocaked...");
}
}
}
}
When application starts and its onDraw() is called, it draws circle and text as well but on further calls to onDraw() it draws nothing. Means nothing changed on screen after first update. Any idea where I am getting wrong? I am new to android and slow learner as well.
I got the answer. Its very strange. I don't know why this worked.
I commented the following line from my activity and it runs.
surfaceView.setBackgroundColor(Color.rgb(0, 255, 0));
the activity code is:
public class SurfaceViewTutorialActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MySurfaceView surfaceView = new MySurfaceView(this);
// surfaceView.setBackgroundColor(Color.rgb(0, 255, 0));
surfaceView.setBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
setContentView(surfaceView);
}
}
If any one knows about this, kindly guide me to the right direction.