I'm porting a game from JME to Android and I found an annoying problem. The next activity must draw a grid, and in fact it does. But the grid appear OK just in landscaping mode. When you put the phone vertical (in portrait mode) it appears strangely compressed.
The main code is the method used to draw a cells row, (getSquareRow)
Thanks in advance for any help.
Here is the code:
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class TraxActivity extends Activity {
InternalView myView;
private float shift, di;
private float n, minim, redux, side;
boolean first = true;
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
myView = new InternalView(this);
setContentView(myView);
}
private class InternalView extends View{
public InternalView(Context context){
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
n=5;
di=12;
int ancho = getWidth();
int alto = getHeight();
minim = Math.min(getWidth(), getHeight());
redux = minim*9/10;
shift = (getWidth() - redux)/2;
side = redux/n;
//background
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
canvas.drawPaint(paint);
//grid
for(int j=0; j < n; j++){
getSquareRow( canvas, j, paint);
}
}
public void getSquareRow(Canvas g, int row, Paint p){
p.setColor(Color.BLACK);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(10);
for(int i=0; i < n; i++){
g.drawRect(shift+i*side, shift+row*side, side, side, p );
}
}
}
}
Thanks guys, I'll be targeting the game just for landascaping mode. Althought I agree with alextsc but in this case looks like Android platform doesn't redraw accurately in portrait mode.
I can't to publish an image because I'm newbie posting here, but running this code you can check the anomaly and seems be related with the method drawRect.
Related
I'm having a problem drawing text on a canvas that has been scaled. I want to scale the canvas so that drawing dimensions and co-ordinates are always in the range 0.0 to 1.0 i.e. independent of Canvas width and height. (If this is poor practice please feel free to comment giving a reason why this is so.) While I can draw lines and arcs on a scaled canvas correctly, I'm having great difficulty painting text and this problem only seems to occur on Android 4.2
As an example, I have created some code based upon this page here. Not however I have stripped out a lot of the code for clarity.
First, this code works correctly and is as on the above link (albeit stripped down):
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
public class DrawDemo extends Activity {
DemoView demoview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
demoview = new DemoView(this);
setContentView(demoview);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class DemoView extends View{
private int width = 0;
private int height = 0;
public DemoView(Context context){
super(context);
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh){
width = w;
height = h;
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// custom drawing code here
// remember: y increases from top to bottom
// x increases from left to right
int x = 0;
int y = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// make the entire canvas white
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// draw some text using STROKE style
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(Color.MAGENTA);
paint.setTextSize(30);
canvas.drawText("Style.STROKE", 75, 75, paint);
}
}
}
Next I replaced the absolute pixel sizes with normalised ( 0 to 1.0) values and scaled the canvas:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
public class DrawDemo extends Activity {
DemoView demoview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
demoview = new DemoView(this);
setContentView(demoview);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class DemoView extends View{
private int width = 0;
private int height = 0;
public DemoView(Context context){
super(context);
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh){
width = w;
height = h;
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// custom drawing code here
// remember: y increases from top to bottom
// x increases from left to right
int x = 0;
int y = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// make the entire canvas white
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// draw some text using STROKE style
canvas.scale(width, height);
paint.setStyle(Paint.Style.STROKE);
//paint.setStrokeWidth(1);
paint.setColor(Color.MAGENTA);
paint.setTextSize(0.2f);
canvas.drawText("Style.STROKE", 0.5f, 0.5f, paint);
}
}
}
The result is nothing appears on the screen. Could someone suggest what I'm doing wrong? Bear in mind that drawing text in the latter has worked for me on Android < 4.2. Apologies for the formatting of the code sample,s I still cannot get to grips with Stackoverflows code formatting.
When hardware acceleration is on, text is rendered into a texture at the font size you specify on the paint. This means that in your case, text is rasterized at 0.2f pixels. That texture is then scaled up at drawing time, which is why you're not seeing anything.
While this issue has been addressed in a future version of Android, I would strongly recommend you didn't use 0..1 values. You might not only run into precision issues but you will also force the rendering pipelines (software and hardware) to bypass very useful optimizations. For instance, text rendered with a scale transform in software is rendered using paths instead of bitmaps blits.
I'm still learning Android, and I decided to download an example paint application to fiddle with that and learn a bit about how Android handles graphics/drawables/painting. The code I have shows a green and red 'V' in the upper left corner, and a red dot that follows where you touch.
However, I found that the screen is being redrawn each time, so I can't use it as a painting tool. It's almost as if I'm dumping a bucket of white paint over the surface and then redrawing the circle. How can I make it so that the red dot that follows your finger leaves a trail? Here's the code.
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
public class MainActivity extends Activity implements OnTouchListener {
private float x;
private float y;
private int moveX;
Paint paint = new Paint();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomPanel view = new MyCustomPanel(this);
ViewGroup.LayoutParams params =
new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
addContentView(view, params);
view.setOnTouchListener(this);
}
private class MyCustomPanel extends View {
public MyCustomPanel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.GREEN);
paint.setStrokeWidth(6);
canvas.drawLine(moveX,10,50,50,paint);
paint.setColor(Color.RED);
canvas.drawLine(50, 50, 90, 10, paint);
canvas.drawCircle(50, 50, 3, paint);
moveX++;
canvas.drawCircle(x,y,3,paint);
}
}
public boolean onTouch(View v, MotionEvent event) {
x = event.getX();
y = event.getY();
v.invalidate();
return true;
}
}
For example, save the circles in an ArrayList. Make an ArrayList and save every xy coordinates from touch as a point.The following code is just from scratch, could not test it at the moment, so if anything is not working let me know and I will give a an example when I am at home.
private ArrayList<Point> pointList = new ArrayList<Point>
Then in On Touch:
Point xyPoint = new Point();
xyPoint.x = event.getX();
xyPoint.y = event.getY();
pointList.add(xyPoint);
invalidate();
and in onDraw, do a for-loop to get all points and draw each one:
for(int i=0;i<pointList.size();i++){
Point p = pointList.get(i);
canvas.drawCircle(p.x, p.y, 2, paint);
}
This draws circles with 2px diameter where Your finger touches. But this is just an simple example, there is a lot of more You can do and that look better. You should learn about draw on path and how to draw rects and ovales etc. Here is a good example of how to draw on path:
http://android-er.blogspot.de/2011/08/drawpath-on-canvas.html
I'm trying to draw different random values from an array, but linking them with lines, so it looks likes the values of a continue function. I have done it quite good with this app:
package android.nacho.Graphic2D;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import java.util.Random;//included random
public class Graphic2D extends Activity{
DrawView drawView;
//private Button btnAsyncTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int randomInt;
//note a single Random object is reused here
Random randomGenerator = new Random();
int Maxsize=800;
int[] randomNumbers= new int[Maxsize];
for (int idx = 1; idx < Maxsize-1; ++idx){
randomInt = randomGenerator.nextInt(100);
randomNumbers[idx]=randomInt;
System.out.println("Random number: "+randomInt);
}
drawView = new DrawView(Graphic2D.this, randomNumbers, Maxsize);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
}
}
package android.nacho.Graphic2D;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawView extends View {
Paint paint = new Paint();
int[] values;
int Size, Offset;
public DrawView(Context context, int[] datainBytes, int size) {
super(context);
values=datainBytes;
Size=size;
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
int cont2;
for(int cont=0; cont<Size-(1); cont++)
{
cont2=cont+1;
canvas.drawLine(cont, 500-(values[cont]) , cont+1, 500-(values[cont2]), paint);
}
}
}
The thing is, now I want to dram much more points, but in a dinamicall way so the new value is the one most at the right, the rest of the values move one pixel to the left and the one most of the left just don't appear. I was planning to this with a loop in the main Activity, so in each iteration the random values are all the same but the last one, and the others have move one position to the left in the array. The final effect should be something like a video.
But there is a problem, do App don't draw this dinamically, it just draw the last iteration of the loop. ¿Could anyone help me to solve this?
I was thinking in using AsyncTask for that, doing the points generation in the backgroun and sending the result to the update so draw in, but the script was a mess that didn't work, so I prefer to don't upload it.
Thank you very much for any suggestion.
I have one activity in my Android App for now which is a RelativeLayout with a background color and onCreate I create a number of random colored circles and addViews on to the relativelayout based on the device screen width and height. Here are the code snippets.
MyActivity.java
package com.myapp.android;
import java.util.Random;
import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.widget.RelativeLayout;
public class MyActivity extends Activity {
/** Called when the activity is first created. */
Random randomGenerator = new Random();
String[] colors = { "#84B62C", "#6A28F2","#F3FA0A", "#DF1FE4", "#0000A0", "#28C9DB", "#E05323"};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
RelativeLayout main = (RelativeLayout) findViewById(R.id.main_myapp);
// Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
int number_side = width / 100;
int number_down = height / 100;
for(int i = 0; i < (number_side * number_down) * 3; i++) {
main.addView(new Ball(this,randomGenerator.nextInt(width), randomGenerator.nextInt(height), 40 * (randomGenerator.nextInt(3)), colors[randomGenerator.nextInt(colors.length)], "BALL" + Integer.toString(i)));
}
}
}
This works great draws all the colored circles in random throughout the screen as I want it. Looks good. Here is the code for the Ball.java where the circles are drawn.
Ball.java
package com.myapp.android;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class Ball extends View {
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public Ball(Context context, float x, float y, int r, String color, String tag) {
super(context);
mPaint.setColor(Color.parseColor(color));
this.x = x;
this.y = y;
this.r = r;
this.setTag(tag);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, mPaint);
}
}
What I am trying to do is let the user touch any one of the colored circle and drag it on the screen wherever they want to but I cannot get them to move. I have not posted any trial code here.
What would be the best way to detect the user touch (this can be onTouch or onLongClick) on any of the circles drawn on screen (one circle at a time especially the one that is touched by the user) and thereafter make the circle (which is essentially a view added to the main Relative Layout View group at run time) to follow the users touch drag action (ACTION_MOVE - my guess) until they release the drag (ACTION_UP - my guess).
I have read some tutorials on this topic but none has been really helpful or applicable to my use case. Also I wanted to ask you knowledgeable guys should I use the 2D Graphics Canvas or OpenGL API in my case so that the drag operation on the circles are very smooth and instantaneous. Feel free to run my simple code, it works fine until the balls are drawn on the screen.
In your implementation, you consider Ball as a View and there are many balls thus there are many Views.
If I were you, I'll consider the whole screen is ONE View and the balls are only sprites inside that View.
Say, I'll extend the View class or SurfaceView class and have a Collection as attribute to store all coordinates and sizes of balls. Inside onDraw(), it should loop through the collection and draw the balls on correct location with correct size.
I am trying to get a panel which has a canvas containing an image which i will place over another image and when i touch the screen the top(overlaying) image will be erased by means of a PoerterDuffXfermode(PorterDuff.Mode) etc ,, anyway I have the functionality done and dusted thanks to the help of a guy on this forum who provided some code which basically carried out exactly what I needed, but I'm having one slight problem,, the guys implementation of the code, will not allow me to reference the Panel class properly in XML to place the Panel on a pre defined XML (main.xml) file. its giving me an error stating
Custom view Panel is not using the 2- or 3-argument View constructors; XML attributes will not work
This is what my xml looks like on a basic scale (just the view in place within the outer linearlayout).
<com.easyscratch.full.Panel
xmlns:android="http://schemas.android.com/apk/res/android"
android:id ="#+id/easyCustView"
android:layout_width="300dp"
android:layout_height="300dp"
android:visibility="visible"
android:focusableInTouchMode="true"/>
The java is as followed .( PANEL CLASS)
package com.easyscratch.full;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
class Panel extends View
{
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
Bitmap bitmap;
Canvas pcanvas ;
int x = 0;
int y =0;
int r =0;
public Panel(Context context) {
super(context);
Log.v("Panel", ">>>>>>");
setFocusable(true);
setBackgroundColor(Color.GREEN);
// setting paint
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAntiAlias(true);
// getting image from resources
Resources r = this.getContext().getResources();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.foreground_image);
// converting image bitmap into mutable bitmap
bitmap = Bitmap.createBitmap(295, 260, Config.ARGB_8888);
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bm, 0, 0, null);
}
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
pcanvas.drawCircle(x, y, r, mPaint);
canvas.drawBitmap(bitmap, 0, 0,null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// set paramete to draw circle on touch event
x = (int) event.getX();
y = (int) event.getY();
r =20;
// Atlast invalidate canvas
invalidate();
return true;
}
}
BASIC MAIN CLASS CALLING MAIN.XML
package com.easyscratch.full;
import android.app.Activity;
import android.os.Bundle;
public class easyscratch extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
,, If only Someone cud tell me what im doing wrong , or maybe an alternative implementation of the
public Panel(Context context) {
super(context);
anyway thanks alot in advanced really would appriciate some help as soon as possible :)
CHEERS GUYS!
Your constructor for Panel must also, at least, have an AttributeSet field.
public Panel(Context context, AttributeSet attr){
super.(context, attr);