drawText Canvas method not working - android

I am very new to Java and android. my 1st app using canvas and paint. for some reason I get a force close whenever I try using the drawText method.. Please help.
I am basically trying to display text in a specific x,y coordinate. which will need updates throughout game play, my code:
public class MyGame extends Main {
TextView timeDisplay;
public String clock;
int x_pos = 10;
int y_pos = 100;
int radius = 20;
float x = 10;
float y = 20;
android.graphics.Paint p;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// setup Drawing view
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
c.drawText("test", 30, 0,x,y, p); <-- if I comment this out, no force close...
Your help is appreciated.

Your Paint object "p" is never created. It contains the null pointer, hence the exception you are getting.

initialize p as follow
Paint p = new Paint();
p.setColor(Color.WHITE);
p.setStyle(Style.FILL);
and then use
c.drawText("test", 30, 0,x,y, p);

Related

draw Canvas multiple times - best practice

I'm still searching for the right way to draw on canvas multiple times.
Wished result: ImageView set to visible, show first text, then second instead of first, finally third instead of second. Each text is visible for half a second
Idea: paint canvas with setColor(Color.WHITE) after each text, use synchronized block for setting backgroundcolor and text, use invalidate() with custom draw() method
I tryed different ways, this is the current version of my code:
initializeStimulus() - called in onCreate() of my Service
private void initializeStimulus(String stimulus) {
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
stimulusOverlay = new CustomImageView(this);
stimulusOverlay.setBackgroundColor(getResources().getColor(R.color.background_stimulus));
stimulusOverlay.setVisibility(View.VISIBLE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
// Position of stimuli in relation to screen size / 2
Point displaySize = new Point();
windowManager.getDefaultDisplay().getRealSize(displaySize);
int width = displaySize.x;
int height = displaySize.y;
params.x = 0;
params.y = 0;
windowManager.addView(stimulusOverlay, params);
imageBitmap = Bitmap.createBitmap((width/3)*2, height/5, Bitmap.Config.ARGB_8888);
p = new Paint();
Canvas canvas = new Canvas(imageBitmap);
p.setColor(Color.BLACK);
Typeface non_proportional_font = Typeface.createFromAsset(getAssets(), "fonts/luximr.ttf");
p.setTypeface(non_proportional_font);
float scale = getResources().getDisplayMetrics().density;
p.setTextSize(40 * scale);
fillTextPathArray();
stimulusOverlay.setImageBitmap(imageBitmap);
stimulusOverlay.draw(canvas);
}
private void fillTextPathArray(){
mTextPaths = new ArrayList<Path>(VOC_COUNT);
String[] text = new String[VOC_COUNT];
String stimulus = getStimulusFromPref(positionStimulus);
int stimulusLength = stimulus.length();
String masking = String.format("%0" + stimulusLength + "d", 0).replace('0', 'X');
text[0] = masking;
text[1] = stimulus;
text[2] = masking;
for (int i = 0; i < text.length; i++) {
Path path = new Path();
p.getTextPath(text[i], 0, masking.length(), imageBitmap.getWidth()/4, (imageBitmap.getHeight()/3)*2, path);
path.close(); // not required on 2.2/2.3 devices
mTextPaths.add(path);
}
}
This function made an ArrayList of paths, which I need to be displayed in the right order. So at the end, the user will be able to see my canvas changing from first text to second text to third text.
I started with tips like "redraw entire view" or "draw box with backgroundcolor over old text" (Android Canvas Drawing Text and Change Text afterwards), because canvas drawing couldn't be revesed. Didn't work out for me.
The big problem remains: the code runs through and everything will be shown in one canvas, one above the other. AND: Time delays like while loop or Thread.sleep(500) didn't have any impact on the canvas. The result was the same: The code was running through - with the given time delay - and at the end everything was painted, not step by step (first, second, third).
I even tryed to draw each text in separate methods.
So I tryed to implement each given new Canvas, new Paint and even new View - nothing changed. At the end everything was drawn instead of step by step.
Currently I have my custom ImageView (CustomImageView), where I'm working with the invalidate() method while using a synchronized block.
private class CustomImageView extends AppCompatImageView {
private boolean stimulusVisible = false;
private int countStimuli = 0;
public CustomImageView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
if (!stimulusVisible) {
Object lock = new Object();
synchronized (lock) {
canvas.drawPath(mTextPaths.get(countStimuli), p);
stimulusVisible = true;
countStimuli++;
}
} else {
long startTime = System.currentTimeMillis();
while((System.currentTimeMillis()-startTime) < 500){}
canvas.drawColor(Color.CYAN);
stimulusVisible = false;
}
invalidate();
}
}
The while loop should stop everything for half a sec.
I really hope for your suppoert.
Is there a better way to implement this?
Am I missing something? I though invalidate() would redraw the canvas but it didn't have an impact. I'm trying for 2 days now, please help.

Animation at a specified rate using canvas / Ondraw

In my Android app, I am trying to show letters one by one with a short delay between each, while also playing a sound for each letter. I have everything working, and the sounds play with the correct delay, but the text always prints to the screen far too fast. The canvas seems to be updated even when i am not specifically invalidating the view.
Here is what I have so far - I also tried a variant of this based on the "snake" example and had the same results... any help would be appreciated!
public class SpellingView extends View {
private static final String WORD = "TRUCK";
int width;
int height;
String textToPrint;
float textspace;
int j=0;
private final Path arc;
private final Paint tPaint;
//constructor for SpellingView
public SpellingView(Context context) {
super(context);
arc = new Path();
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
displayLetterLoop();
}
public void displayLetterLoop(){
for (int i = 0; i < WORD.length(); i++){
final Runnable mUpdateUITimerTask = new Runnable() {
public void run() {
Spelling.mp.start();
}
};
final Handler mHandler = new Handler();
mHandler.postDelayed(mUpdateUITimerTask, i*1500);
}
}
#Override
protected void onDraw(Canvas canvas) {
int k;
// Drawing commands go here
width = canvas.getWidth();
height = canvas.getHeight();
arc.addArc(new RectF((width*.15f), (height*.15f), (width*.85f), (height*.4f)), 180,180);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.RED);
tPaint.setTextSize(height * 0.1f);
tPaint.setTextAlign(Paint.Align.LEFT);
setBackgroundColor(Color.BLACK);
for (k = 0; k < j; k++){
char c = WORD.charAt(k);
String cs = Character.toString(c);
textToPrint+= cs;
textspace =(float) (k*(width/WORD.length())*.9);
canvas.drawTextOnPath(cs, arc, textspace , 0, tPaint);
}
if(j<WORD.length()){
j++;
}
}
}
Custom view will invalidate itself when is a part of a layout which for some reason redraw itself. Therefore you could envelop your code in onDraw() with a condition and a flag so that it draws your stuff only when the timer sets the flag and calls invalidate. After one letter is drawn then the flag shoud be set on false like:
if (drawLetter){
drawLetter = false;
/code...
}
However this also may need to be a sychronized block.
OnDraw should happen 60 times a second and not only when you are invalidating.
So maybe you need to update some class variables (when you are invalidating) and use those for your draw logic # OnDraw.

How shift graph in Android's Canvas

I draw a graph with canvas in android, but I want to shift it to left or right side. I don't want to scroll it, I just want to shift it in one page by which you can see the graph is shifting lively.
I would be appreciated if any body help me.
I am looking for a an answer to this question as well. I have a solution but it is to slow and uses a lot of CPU time. I am drawing two graphs with a width of 200 pixels and have the values stored in an array. I just shift the values in the array and moves them into a path.
I would be nice to have a solution where the canvas gets shifted by 1 pixel to the left and the 200th column gets drawn with the new value. With both paths are empty it takes about 2ms (Droid Incredible) to draw the paths. When the 2 paths are filled up it can take more than 40ms. This would give still 25fps but I would like to run other threads at the same time and don't want to waste CPU time.
Here is the source.
public class OSCI extends View
{
Integer[] codebuffer = new Integer[200];
Integer[] codebuffer1 = new Integer[200];
private static final String TAG = "MyActivity";
long start;
int code=0;
// private static final String TAG = "MyActivity";
public OSCI(Context context)
{
super(context);
Arrays.fill(codebuffer, 1);
Arrays.fill(codebuffer1, 1);
}
public OSCI(Context context, AttributeSet attrs)
{
super(context, attrs);;
Arrays.fill(codebuffer, 1);
Arrays.fill(codebuffer1, 1);
}
#Override
protected void onDraw(Canvas canvas)
{
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.YELLOW);
Path path = new Path();
path.moveTo(0, 70);
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeWidth(2);
paint1.setColor(Color.GREEN);
Path path1 = new Path();
path1.moveTo(0, 70);
int max = Collections.max(Arrays.asList(codebuffer));
if(max==0)max=1;
for (int a = 0; a < codebuffer.length; a++)
{
if (codebuffer[a] < 0)code=0;
code = 70 * codebuffer[a] / max;
path.lineTo(a * 2 + 2, 70 - code);
path1.lineTo(a * 2+ 2, 70 - (codebuffer1[a]));
}
start=(SystemClock.elapsedRealtime());
canvas.drawPath(path1, paint);
canvas.drawPath(path, paint1);
Log.v(TAG, " "+(SystemClock.elapsedRealtime()-start));
}
public void newValue(int value, int valuew)
{
System.arraycopy(codebuffer, 1, codebuffer, 0, 199);
codebuffer[199] = value;
System.arraycopy(codebuffer1, 1, codebuffer1, 0, 199);
codebuffer1[199] = valuew;
invalidate();
}
}

Drawing random circles

I am trying to draw a cupola circles at random positions in an Android application.
I draw them on a bitmap and then draw that bitmap on the canvas. This is the function where a draw the circles:
private void drawRandomCircles(int numOfCircles) {
Canvas c = new Canvas(b);
Paint cPaint = new Paint;
cPaitn.setColor(Color.RED);
for(int i = 0; i < numOfCircles; i++) {
int x = Math.Random % 100;
int y = Math.Random % 100;
c.drawCircle(x, y, 20, cPaint)
}
}
The Bitmap b is global.
And after calling this function I just draw the bitmap in the onDraw method.
Now the problem is that I only get one circle drawn on the screen, no matter the size of numOfCircles.
Any clue what is happening here?
That code doesn't even compile. What is new Paint; for instance?
I suggest you log your arguments to drawCircle to make sure you draw them on different locations. If Math.Random for instance is a field, it would change in between reads, which would put the circles on top of each other.
If you intended to write Math.random() the error is that Math.random() returns a value between 0 and 1. You may want to use
Random r = new Random();
// your loop
int x = r.nextInt(100);
int y = r.nextInt(100);

How to retrieve drawable (picture) from a view?

I wrote code to draw on a view. After it is done, how can I get the resulting image from the view. For example, in the code below, I want to get the the drawable (Image) from mCustomDrawableView. How can I do that? Thanks.
public class HelloTestGraph extends Activity {
/** Called when the activity is first created. */
// #Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout lo = (LinearLayout) findViewById(R.id.top_view);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
CustomDrawableView mCustomDrawableView = new CustomDrawableView(this);
mCustomDrawableView.setLayoutParams(param);
lo.addView(mCustomDrawableView);
}
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
private Drawable mPic;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
mPic = getResources().getDrawable(R.drawable.example_picture);
mPic.setBounds(x, y + 100, x + width, y + height+100);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
mPic.draw(canvas);
}
}
}
This is a little convoluted, but should get you there.
Step 1: Create a Muteable Bitmap of the size you want and stash it aside. It could be the size of the device's screen or the size of your largest view (depending on what you want to do with it later) Save that bitmap pointer aside as something like myBitmap
Step 2: Create a canvas with the aforementioned bitmap. "Canvas myCanvas = new Canvas(myBitmap);"
Step 3: In your onDraw() method, draw your views both to the passed in "canvas" object, and to your own custom one.
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
mPic.draw(canvas);
mDrawable.draw(myCanvas);
mPic.draw(myCanvas);
}
Step 4: Your original bitmap should now contain the fully rendered version of ONLY your view.
I'm not sure if this is exactly what you're looking for, but it will give you a bitmap (which you can convert into an image) of the contents of your view.
From inside your custom class, you'd specify getters and setters if you wanted to access them from outside the class.
public Drawable getDrawable() { return mDrawable; }
Then from outside the class (as in your activity), you can call the getDrawable() method on the view once it's instantiated.
Drawable drawable = mCustomDrawableView.getDrawable();

Categories

Resources