generating random circles in android - java

Im trying to make a simple app that draws random circles when one button is pushed, and clears them all from the screen when another is pushed. Currently When i start the app on an emulator for some reason it starts with an automatically generated circle, then If I attempt to push the button to generate another circle the app crashes and I get a NullPointerException at my
c.drawcircle(b.getX(), b.getY(), b.getR(), p)
method.
Heres what I currently have:
Main:
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class Bubbles extends Activity implements OnClickListener
{
Button b1,b2;
drawView dv;
LinearLayout frame;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bubbles);
dv = new drawView(getApplicationContext());
frame = (LinearLayout)findViewById(R.id.LinearLayout2);
b1 = (Button)findViewById(R.id.BubbleButton);
b1.setOnClickListener(this);
b2 = (Button)findViewById(R.id.ClearButton);
b2.setOnClickListener(this);
frame.addView(dv);
}
#Override
public void onClick(View v)
{
if(v==b1)
{
dv.onDraw(null);
}
if(v==b2)
{
dv.clear();
}
v.postInvalidate();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.bubbles, menu);
return true;
}
}
drawView:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class drawView extends View
{
ArrayList<Bubble> bList = new ArrayList<Bubble>();
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
public drawView(Context con)
{
super(con);
}
public void onDraw(Canvas c)
{
Bubble b = new Bubble();
p.setColor(b.getColor());
p.setStyle(Paint.Style.FILL);
bList.add(b);
c.drawCircle(b.getX(), b.getY(), b.getR(), p);
}
public void clear()
{
bList.clear();
}
}
Im using an arrayList in this class to store all the bubbles I make and then clear the arrayList using the clear button.
Here is the Bubble class I made that goes with it:
Bubble:
import android.graphics.Color;
public class Bubble
{
int color;
int y;
int x;
int r;
public Bubble ()
{
color = Color.rgb(rand(0,255), rand(0,255), rand(0,255));
r = rand(0,255);
x =rand(0,255);
y = rand(0,255);
}
public int getColor() {
return color;
}
public int getY() {
return y;
}
public int getX() {
return x;
}
public int getR() {
return r;
}
/******************************rand()*****************************/
public int rand(int a, int b)
{
return((int)((b-a+1)*Math.random() + a));
}
}
Thanks for any input, This is my first time messing with graphics so Im not 100% sure why this is happening.

you pass null to your method onDraw here:
dv.onDraw(null);
I guess you would want to pass a Canvas there.
In this method then your Canvas will point to null since you passed null as the param:
public void onDraw(Canvas c) {
Bubble b = new Bubble();
p.setColor(b.getColor());
p.setStyle(Paint.Style.FILL);
bList.add(b);
c.drawCircle(b.getX(), b.getY(), b.getR(), p); // c == null here!
}
==> NPE

as for your random method try this
Random rng = new Random();
in your field declarations.
then use. rng.nextInt(255);
color = Color.rgb(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255));
as for your circles: firstly you need an update method(if you want any movement)
secondly you should be using a surfaceView to draw, and thirdly you should use a
copyOnWriteArrayList, because your button may be modifying the list while its iterating over it, and copyonwritearraylist is perfect for that. here: my gift to you.
CLASS 1
import java.util.Random;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
public class GrowCircle {
float x, y;int radius;
Paint myp = new Paint();
int colr,colg,colb;
int redvar=1;
int bluevar=5;
int greenvar=2;
int tripper=10;
int change=2;
Random rand = new Random();
public GrowCircle(float x, float y){
this.x=x;
this.y=y;
this.radius=2;
this.colr=rand.nextInt(254)+1;
this.colg=rand.nextInt(254)+1;
this.colb=rand.nextInt(254)+1;
}
public void update(){
radius+=4;
tripper+=change;
if(tripper<=1||tripper>=15){
change=-change;
}
Random col = new Random();
myp.setColor(Color.argb(255,colr,colg,colb));
colr+=redvar;
colg+=greenvar;
colb+=bluevar;
if(colr<=5||colr>=250){
redvar=-redvar;
}
if(colg<=5||colg>=250){
greenvar=-greenvar;
}
if(colb<=5||colb>=250){
bluevar=-bluevar;
}
}
public void drawThis(Canvas canvas){
myp.setStrokeWidth(tripper);
myp.setStyle(Style.STROKE);
canvas.drawCircle(x, y, radius, myp);
}
}
CLASS2
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import com.gmaninc.acidrain2.R;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.service.wallpaper.WallpaperService.Engine;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnTouchListener;
public class LiveWallpaperService extends WallpaperService {
CopyOnWriteArrayList<GrowCircle> gc = new CopyOnWriteArrayList<GrowCircle>();
private final Handler mHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public Engine onCreateEngine() {
return new CubeEngine();
}
class CubeEngine extends Engine {
private final Paint mPaint = new Paint();
private float mOffset;
private float mTouchX = -1;
private float mTouchY = -1;
private long mStartTime;
private float mCenterX;
private float mCenterY;
private final Runnable mDrawCube = new Runnable() {
public void run() {
drawFrame();
}
};
private boolean mVisible;
CubeEngine() {
// Create a Paint to draw the lines for our cube
final Paint paint = mPaint;
paint.setColor(0xffffffff);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
mStartTime = SystemClock.elapsedRealtime();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// By default we don't get touch events, so enable them.
setTouchEventsEnabled(true);
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawCube);
}
#Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawCube);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
// store the center of the surface, so we can draw the cube in the right spot
mCenterX = width/2.0f;
mCenterY = height/2.0f;
for(GrowCircle circ:gc){
circ.update();
}
drawFrame();
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawCube);
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xStep, float yStep, int xPixels, int yPixels) {
mOffset = xOffset;
drawFrame();
}
/*
* Store the position of the touch event so we can use it for drawing later
*/
#Override
public void onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mTouchX = event.getX();
mTouchY = event.getY();
} else {
mTouchX = -1;
mTouchY = -1;
}
float tx = event.getX();
float ty= event.getY();
gc.add(new GrowCircle(tx,ty));
super.onTouchEvent(event);
}
/*
* Draw one frame of the animation. This method gets called repeatedly
* by posting a delayed Runnable. You can do any drawing you want in
* here. This example draws a wireframe cube.
*/
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// draw something
drawCircs(c);
for(GrowCircle circ:gc){
if(circ.radius>350){
gc.remove(circ);
}
circ.update();
circ.drawThis(c);
}
drawTouchPoint(c);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawCube);
if (mVisible) {
mHandler.postDelayed(mDrawCube, 1000 / 25);
}
}
/*
* Draw a wireframe cube by drawing 12 3 dimensional lines between
* adjacent corners of the cube
*/
void drawCircs(Canvas c) {
c.save();
c.translate(mCenterX, mCenterY);
c.drawColor(0xff000000);
c.restore();
}
/*
* Draw a circle around the current touch point, if any.
*/
void drawTouchPoint(Canvas c) {
if (mTouchX >=0 && mTouchY >= 0) {
c.drawCircle(mTouchX, mTouchY, 80, mPaint);
}
}
}
}
MANIFEST
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gmaninc.acidrain2"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<service
android:name="LiveWallpaperService"
android:enabled="true"
android:label="Acid Rain 2"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" >
</action>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="#xml/mywallpaper" >
</meta-data>
</service>
</application>
</manifest>
this is a livewallpaper that creates circles onTouch... feel free to play around with it, you should find what you need in here....
NOTE: you may need to change the package name in the manifest to get it to run!

Related

I am making an app and I require to use the interface Parcelable but facing issues and not sure how to implement it

I am new to coding and to java and android. I am making an app that has multiple canvas views (where a person can draw lines with their finger) in multiple fragments (requested to be like this). I have managed to get the fragments to work and to draw lines on each canvas. Next, I want to be able to save the lines drawn by the user when the user goes to a different fragment or closes the app and when the user comes back to a fragment, the drawing for that fragment will still be there, and can continue editing it by adding more lines or clear it by hitting Clear, the same should happen for other fragments that should have their respective drawings.
I was previously told about the interface Parcelable and have made some steps to implement it but I am finding it hard to understand what I am doing and having trouble reading in an ArrayList. The error is stating that it is expecting ClassLoader but being provided with an ArrayList (I hope in the right place), and that's if I make the getter static but that creates an error: Non-static field 'paths' cannot be referenced from a static context in the getter in the PaintView class (this controls the drawing). I get a similar static context message for the readArrayList method in the FingerPath class. Once this is figured out, I will need to find out how to bring the relevant, saved drawing back to the canvas when the fragment is opened which I am not sure how, I think when the Bundle isn't equal to null but not sure.
I'll show the code below (right now it is on a test app)
FingerPath class
import android.graphics.Path;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
public class FingerPath implements Parcelable {
public int color;
public boolean emboss;
public boolean blur;
public int strokeWidth;
public Path path;
public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path) {
this.color = color;
this.emboss = emboss;
this.blur = blur;
this.strokeWidth = strokeWidth;
this.path = path;
}
protected FingerPath(Parcel in) {
color = in.readInt();
emboss = in.readByte() != 0;
blur = in.readByte() != 0;
strokeWidth = in.readInt();
//line below causing me issues
path = in.readArrayList(PaintView.getPaths());
}
public static final Creator<FingerPath> CREATOR = new Creator<FingerPath>() {
#Override
public FingerPath createFromParcel(Parcel in) {
return new FingerPath(in);
}
#Override
public FingerPath[] newArray(int size) {
return new FingerPath[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(color);
parcel.writeByte((byte) (emboss ? 1 : 0));
parcel.writeByte((byte) (blur ? 1 : 0));
parcel.writeInt(strokeWidth);
//parcel.writeParcelableArray(PaintView.getPaths(), 0);
}
}
PaintView
Controls what happens when the user starts drawing
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class PaintView extends View {
public static int BRUSH_SIZE = 10;
public static final int DEFAULT_COLOR = Color.WHITE;
public static int DEFAULT_BG_COLOR = Color.GRAY;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
//the getter in question
public ArrayList getPaths() {
return paths;
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp: paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
touchUp();
invalidate();
break;
}
return true;
}
}
Here's an example of a fragment
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class LineLHwFragment extends Fragment {
private PaintView paintView;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_line_l_hw, container, false);
paintView = v.findViewById(R.id.lineLPaintView);
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
setHasOptionsMenu(true);
return v;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.normal:
paintView.normal();
return true;
case R.id.clear:
paintView.clear();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("line test", paintView.getPaths());
}
}

Why isn't my player falling (gravity) in Eclipse and LibGDX?

I am trying to make my player fall/go down, but he is not. He is just stuck on the map. He can't move. Can you please help?
Here is the code for the Screen. This is where I have all the methods like show, render, resize, pause, resume, hide, etc
package net.hasanbilal.prisonrevelations.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import net.hasanbilal.prisonrevelations.entities.Player;
public class Play implements Screen {
private TiledMap map;
private OrthogonalTiledMapRenderer otmr;
private OrthographicCamera camera;
private Player porter;
#Override
public void show() {
map = new TmxMapLoader().load("maps/level1.tmx");
otmr = new OrthogonalTiledMapRenderer(map);
camera = new OrthographicCamera();
porter = new Player(new Sprite(new Texture("img/porter.png")));
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
otmr.setView(camera);
otmr.render();
otmr.getBatch().begin();
porter.draw(otmr.getBatch());
otmr.getBatch().end();
}
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
map.dispose();
otmr.dispose();
}
}
Here is the code for the player
package net.hasanbilal.prisonrevelations.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
public class Player extends Sprite {
/**
* x and y velocity
*/
private Vector2 velocity = new Vector2();
//change 120 to 60*2 if it doesn't work
private float speed = 60 * 2, gravity = 60 * 1.8f;
public Player(Sprite s) {
super(s);
}
public void draw(SpriteBatch sb) {
update(Gdx.graphics.getDeltaTime());
super.draw(sb);
}
private void update(float deltaTime) {
velocity.y -= gravity * deltaTime; //gravity to player
if(velocity.y>speed)
velocity.y = speed;
else if(velocity.y < speed)
velocity.y = -speed;
setX(getX() + velocity.x * deltaTime);
setY(getY() + velocity.y * deltaTime);
}
}
This assignment is due soon! Please help!
Nevermind guys, I fixed it. All I had to do is add porter.update(1);between porter.draw(otmr.getBatch()); and otmr.getBatch().end();

Android Wear Watch Face Development Colors

I am trying to develop watch faces, and I was able to add the time, date, and other information and position the text. I had trouble with style, mostly color. I have one red text, and another white text. After going to Ambient Mode and turning back to interactive mode, the color is either white or gray depending on the code below. I can only get it to return to one color.
SimpleWatchFaceService.java
package com.me.me.androidwearweather;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.support.wearable.watchface.CanvasWatchFaceService;
import android.support.wearable.watchface.WatchFaceStyle;
import android.view.SurfaceHolder;
import java.util.concurrent.TimeUnit;
public class SimpleWatchFaceService extends CanvasWatchFaceService {
#Override
public Engine onCreateEngine() {
return new SimpleEngine();
}
private class SimpleEngine extends CanvasWatchFaceService.Engine {
private final long TICK_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(1);
private Handler timeTick;
private SimpleWatchFace watchFace;
#Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
setWatchFaceStyle(new WatchFaceStyle.Builder(SimpleWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setAmbientPeekMode(WatchFaceStyle.AMBIENT_PEEK_MODE_HIDDEN)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
timeTick = new Handler(Looper.myLooper());
startTimerIfNecessary();
watchFace = SimpleWatchFace.newInstance(SimpleWatchFaceService.this);
}
private void startTimerIfNecessary() {
timeTick.removeCallbacks(timeRunnable);
if (isVisible() && !isInAmbientMode()) {
timeTick.post(timeRunnable);
}
}
private final Runnable timeRunnable = new Runnable() {
#Override
public void run() {
onSecondTick();
if (isVisible() && !isInAmbientMode()) {
timeTick.postDelayed(this, TICK_PERIOD_MILLIS);
}
}
};
private void onSecondTick() {
invalidateIfNecessary();
}
private void invalidateIfNecessary() {
if (isVisible() && !isInAmbientMode()) {
invalidate();
}
}
#Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
startTimerIfNecessary();
}
#Override
public void onDraw(Canvas canvas, Rect bounds) {
super.onDraw(canvas, bounds);
watchFace.draw(canvas, bounds);
}
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
watchFace.setAntiAlias(!inAmbientMode);
watchFace.setColor(inAmbientMode ? Color.GRAY : Color.WHITE);
// THIS IS WERE I THINK THE PROBLEM IS I tried the method on top and bottom of this comment
// if(inAmbientMode){
// watchFace.setColor(Color.GRAY);
// }
invalidate();
}
#Override
public void onTimeTick() {
super.onTimeTick();
invalidate();
}
#Override
public void onDestroy() {
timeTick.removeCallbacks(timeRunnable);
super.onDestroy();
}
}
}
SimpleWatchFace.java
package com.me.me.androidwearweather;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.format.Time;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class SimpleWatchFace {
private final Paint timePaint;
private final Paint datePaint;
private final Time time;
public static SimpleWatchFace newInstance(Context context) {
Paint timePaint = new Paint();
timePaint.setColor(Color.RED);
timePaint.setTextSize(context.getResources().getDimension(R.dimen.time_size));
timePaint.setAntiAlias(true);
Paint datePaint = new Paint();
datePaint.setColor(Color.WHITE);
datePaint.setTextSize(context.getResources().getDimension(R.dimen.date_size));
datePaint.setAntiAlias(true);
return new SimpleWatchFace(timePaint, datePaint, new Time());
}
SimpleWatchFace(Paint timePaint, Paint datePaint, Time time) {
this.timePaint = timePaint;
this.datePaint = datePaint;
this.time = time;
}
public void draw(Canvas canvas, Rect bounds) {
time.setToNow();
canvas.drawColor(Color.BLACK);
Calendar cal = Calendar.getInstance();
SimpleDateFormat twelvehour = new SimpleDateFormat("h");
SimpleDateFormat ampm = new SimpleDateFormat("a");
String TimeAmPmNoSec = String.format("%2s:%02d %2s", twelvehour.format(cal.getTime()), time.minute, ampm.format(cal.getTime()));
float timeXOffset = computeXOffset(TimeAmPmNoSec, timePaint, bounds);
float timeYOffset = computeTimeYOffset(TimeAmPmNoSec, timePaint, bounds);
canvas.drawText(TimeAmPmNoSec, timeXOffset, timeYOffset, timePaint);
SimpleDateFormat month_date = new SimpleDateFormat("MMM");
SimpleDateFormat day_text = new SimpleDateFormat("E");
String DateNew = String.format("%s | %s %02d", day_text.format(cal.getTime()), month_date.format(cal.getTime()), time.monthDay);
float dateXOffset = computeXOffset(DateNew, datePaint, bounds);
float dateYOffset = computeDateYOffset(DateNew, datePaint);
canvas.drawText(DateNew, dateXOffset, timeYOffset + dateYOffset, datePaint);
}
private float computeXOffset(String text, Paint paint, Rect watchBounds) {
float centerX = watchBounds.exactCenterX();
float timeLength = paint.measureText(text);
return centerX - (timeLength / 2.0f);
}
private float computeTimeYOffset(String timeText, Paint timePaint, Rect watchBounds) {
float centerY = watchBounds.exactCenterY();
Rect textBounds = new Rect();
timePaint.getTextBounds(timeText, 0, timeText.length(), textBounds);
int textHeight = textBounds.height();
return centerY + (textHeight / 2.0f) - 50f;
}
private float computeDateYOffset(String dateText, Paint datePaint) {
Rect textBounds = new Rect();
datePaint.getTextBounds(dateText, 0, dateText.length(), textBounds);
return textBounds.height() + 25f;
}
public void setAntiAlias(boolean antiAlias) {
timePaint.setAntiAlias(antiAlias);
datePaint.setAntiAlias(antiAlias);
}
public void setColor(int color) {
timePaint.setColor(color);
datePaint.setColor(color);
}
}
I was also wondering if it is possible to style a text with more than one font and color.
EDIT 2: Alright, you could just instantiate a new watch face each time the mode is changed (Java will automatically garbage collect the old one, so no worries on memory) OR, I personally would do this.
Add two new functions in your SimpleWatchFace class to replace your setColor function
public void setTimeColor(int color) {
timePaint.setColor(color);
}
public void setDateColor(int color) {
datePaint.setColor(color);
}
then change your function to be this
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
watchFace.setAntiAlias(!inAmbientMode);
if(inAmbientMode)
{
watchFace.setTimeColor(Color.BLACK);
watchFace.setDateColor(Color.GREY);
}
else
{
watchFace.setTimeColor(Color.RED);
watchFace.setDateColor(Color.WHITE);
}
}
When the watch is put into Ambient Mode the screen turns itself black and white (or black and grey as you're experiencing)
Note: In low-bit ambient mode, the system does not reliably render the
colors in the image
from The Android Webpage

Handling TouchEvents concurrentModificationException android

I was trying to draw some balloons on screeen using canvas in SurfaceView class, I was successfully able to draw Multiple balloons on canvas and animate them by swapping different images. The problem is When I try touching on Oneballoon I need to remove it from screen .Here I get this exception and I am stuck
Code:
MainActivity:
package com.pradhul.game.touchball;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GameView(this));
/*TODO Hide the bottom navigation bar */
}
}
GameView.java
package com.pradhul.game.touchball;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GameView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener {
private static final int NUM_OF_BALLOONS = 5; //TODO for more than one balloons animations dont work(?)
/*use SurfaceView because we want complete control over the screen.
* unlike extending View class the oDraw() Method will not be called automatically
* from the method onSurfaceCreated() we have to call it Manually and pass a canvas object into it
* */
private final SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Balloon> balloons = new ArrayList<>();
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(this);
createBalloons(NUM_OF_BALLOONS);
this.setOnTouchListener(this);
}
private void createBalloons(int count) {
for(int i=0 ; i< count ;i++){
balloons.add(createBalloon());
}
}
#Override
protected void onDraw(Canvas canvas) {
if(canvas != null) {
canvas.drawColor(Color.WHITE);
for(Balloon balloon : balloons){
try {
gameLoopThread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
balloon.onDraw(canvas);
}
}
}
#SuppressLint("WrongCall")
#Override
public void surfaceCreated(SurfaceHolder holder) {
/*this is called when the view is created*/
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
/*pausing game Thread*/
gameLoopThread.setRunning(false);
while (true){
try {
gameLoopThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Balloon createBalloon(){
return new Balloon(this);
}
#Override
public synchronized boolean onTouch(View v, MotionEvent event) {
Log.d("OnTouch real -", "x: " + event.getX() + ", Y: " + event.getY());
/* for (int i = balloons.size()-1; i >= 0; i--) {
Balloon balloon = balloons.get(i);
Log.d("OnTouch collision -", !balloon.isCollision(event.getX(), event.getY())+"");
if (!balloon.isCollision(event.getX(), event.getY())) {
balloons.remove(0);
break;
}
}*/
Iterator<Balloon> balloonIterator = balloons.iterator();
while(balloonIterator.hasNext()){
Balloon balloon = balloonIterator.next();
balloons.remove(0);
}
return true;
}
}
GameLoopThread.java
package com.pradhul.game.touchball;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
public class GameLoopThread extends Thread {
private GameView view;
private boolean running = false;
public GameLoopThread(GameView view){
this.view = view;
}
public void setRunning(boolean run){
running = run;
}
#SuppressLint("WrongCall")
public void run(){
while (running){
Canvas canvas = null;
try{
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder()){
view.onDraw(canvas);
}
}finally{
if(canvas != null) {
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
Balloon.java
package com.pradhul.game.touchball;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import java.util.Random;
public class Balloon {
private static final int BALLOON_SPEED = 10;
private int y = 0;
private int x = 0;
private int speed = 1;
private GameView gameView;
private Bitmap balloon;
public Bitmap[] normalBalloons;
private int balloonIndex = 0;
private int normalImages[] = {R.drawable.normal_01,R.drawable.normal_02,R.drawable.normal_03,
R.drawable.normal_04,R.drawable.normal_05,R.drawable.normal_06,R.drawable.normal_07,
R.drawable.normal_08,
};
private int crackingImages[] = {R.drawable.crack_01,R.drawable.crack_02,R.drawable.crack_03,
R.drawable.crack_04, R.drawable.crack_05,R.drawable.crack_04,R.drawable.crack_03,
R.drawable.crack_02
};
private boolean reverseSwap = false;
public Balloon(GameView gameView){
this.gameView = gameView;
normalBalloons = new Bitmap[8];
setUpImages();
}
public void onDraw(Canvas canvas){
/*draws the balloon in canvas */
animateBalloon();
update(canvas.getWidth());
canvas.drawBitmap(balloon, x, y, null);
}
public boolean isCollision(float x2, float y2) {
return x2 > x && x2 < x + balloon.getWidth() && y2 > y && y2 < y + balloon.getHeight();
}
private int getRandomX(int maxVal) {
Random rand = new Random();
return rand.nextInt(maxVal);
}
private void animateBalloon() {
/*Animates the balloon by swapping resource image at each call*/
this.balloon = getBalloons();
Log.d("Balloon",balloonIndex % normalBalloons.length + "");
}
private void update(int canvasWidth) {
/*updates the y position for moving the balloon*/
if (y <= 0){
/*so that the balloon starts from bottom
* gameView will return a height only after the View is ready
* getting 0 in constructor of this class*/
y = gameView.getHeight();
/*x is assigned a random between the width od the canvas
* so that the balloons will appear random positions from below*/
x = getRandomX(canvasWidth - balloon.getWidth());
}
if (y > gameView.getHeight() - balloon.getHeight() - speed) {
speed = -BALLOON_SPEED;
}
y = y + speed;
Log.d("Balloon","Positions:"+x+","+y);
}
private Bitmap getBalloons() {
if(balloonIndex == normalBalloons.length-1) {
reverseSwap = true;
}
if(balloonIndex == 0){
reverseSwap = false;
}
balloonIndex = reverseSwap?balloonIndex-1:balloonIndex+1;
return normalBalloons[balloonIndex];
}
private void setUpImages() {
/*setting up resources array*/
for(int count =0; count < normalImages.length; count++){
Bitmap balloon = BitmapFactory.decodeResource(gameView.getResources(), normalImages[count]);
normalBalloons[count] = balloon;
}
}
}
I am confused that why it causes an error like this , Can anybody can take look at it and suggest me a solution, is this the right way to remove ?
please share any suggestion
Thanks
It's the wrong way to remove.
If you iterate over a Collection / List, and want to remove the current element, you must use Iterator.remove() method.
In your case, simply call balloonIterator.remove() instead of balloons.remove(0)
Even simpler, since you want to remove all elements from the list - you should simply call balloons.clear() and remove the loop completely.
This exception is due to concurrent modification of list balloons.
As soon as you touch surface view onDraw() gets invoked with onTouch(), in which you are working on list balloons.
I think you should add touch listener to balloon instead of GameView.
okay ,
I need to wrap all my code inside a synchronized holder inorder this to work
(don't know much about it)
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("OnTouch","x:"+event.getX()+"Y:"+event.getY());
synchronized (getHolder()){
for (int i=0 ;i<balloons.size();i++){
balloons.remove(0);
break;
}
}
return true;
}

How do I update the position of an Android bitmap drawn to canvas with an onTouch event?

I am trying to update the position of a bitmap with an onTouch event. The image displays in the initial spot correctly. The logs show that the onTouch event is updating the coordinate and also show that onDraw is being called.
My Activity:
package com.miker.haminvaders;
import android.app.Activity;
import android.os.Bundle;
public class HamInvadersActivity extends Activity
{
private DrawView drawView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
drawView = (DrawView) findViewById(R.id.drawView);
}
#Override
public void onPause()
{
super.onPause();
drawView.stopGame();
}
#Override
protected void onDestroy()
{
super.onDestroy();
drawView.releaseResources();
}
}
My Thread Class:
package com.miker.haminvaders;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread
{
private boolean running;
SurfaceHolder surfaceHolder;
DrawView drawView;
public void setRunning(boolean r)
{
this.running = r;
}
#Override
public void run()
{
Canvas canvas = null;
while(running)
{
//Log.v("HAM", "tick!");
try
{
canvas = surfaceHolder.lockCanvas();
synchronized(surfaceHolder)
{
drawView.onDraw(canvas);
drawView.updatePositions();
}
}
finally
{
if(canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
public MainThread(SurfaceHolder surface, DrawView draw)
{
super();
surfaceHolder = surface;
drawView = draw;
}
}
My SurfaceView class:
package com.miker.haminvaders;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.graphics.BitmapFactory;
import android.util.Log;
public class DrawView extends SurfaceView implements SurfaceHolder.Callback
{
private MainThread myThread;
private int screenWidth;
private int screenHeight;
private Paint textPaint;
private Paint backPaint;
private float x, y;
private Bitmap bmpHam;
public DrawView(Context context, AttributeSet attrs)
{
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
textPaint = new Paint();
backPaint = new Paint();
myThread = new MainThread(holder, this);
bmpHam = BitmapFactory.decodeResource(getResources(), R.drawable.lilhamstrich);
}
#Override
protected void onSizeChanged( int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
screenWidth = w;
screenHeight = h;
textPaint.setTextSize(w/20);
backPaint.setColor(Color.WHITE);
newGame();
}
public void newGame()
{
x = screenWidth/2;
y = screenHeight/2;
}
public void updatePositions()
{
}
public void onDraw(Canvas canvas)
{
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bmpHam, x, y, null);
Log.v("HAM", "Draw! " + x + " " + y);
}
public void stopGame()
{
if(myThread != null)
myThread.setRunning(false);
}
public void releaseResources()
{
//soundPool stuff
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
myThread.setRunning(true);
myThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
myThread.setRunning(false);
while(retry)
{
try
{
myThread.join();
retry = false;
}
catch(InterruptedException e)
{
}
}
}
#Override
public boolean onTouchEvent (MotionEvent event)
{
int action = event.getAction();
if( action == MotionEvent.ACTION_DOWN)
{
x = event.getX();
y = event.getY();
Log.v("HAM","Down! " + x + " " + y);
}
return true;
}
}
Is there anything else that I need to include?
Call invalidate() in the onTouchEvent(), it should cause a redraw.

Categories