I code a mini game for Android where an animal is controlled by the player when the player clicks on the sides of the Drawable.
I wonder if it is better, and if yes, how to make the Drawable touchable so that the player can drag the character to either side instead of clicking by its sides? I'm interested in both UX/UI opinion and actual solution to the problem.
package dev.android.jamie;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
// An item was selected. You can retrieve the selected item using
Log.d("myTag", "This is my message" + parent.getItemAtPosition(pos));
String name = "Jamie";
String str = parent.getItemAtPosition(pos).toString();
if (str.equals("Rookie")) {
cg = new CatchGame(this, 3, name, onScoreListener);
// setContentView(cg);
mainLayout.addView(cg);
getSupportActionBar().hide();
setContentView(mainLayout);
Log.d("game", "Started Rookie game");
} else if (str.equals("Advanced")) {
mainLayout = new LinearLayout(this);
mainLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout menuLayout = new LinearLayout(this);
menuLayout.setBackgroundColor(Color.parseColor("#FFFFFF"));
textView = new TextView(this);
textView.setVisibility(View.VISIBLE);
str = "Score: 0";
textView.setText(str);
menuLayout.addView(textView);
Button button = new Button(this);
button.setText("Pause");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
togglePausePlay();
}
});
menuLayout.addView(button);
Spinner spinner2 = new Spinner(this);
spinner2.setOnItemSelectedListener(this);
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, spinnerValue);
spinner2.setAdapter(adapter);
menuLayout.addView(spinner2);
mainLayout.addView(menuLayout);
cg = new CatchGame(this, 5, "Jamie", onScoreListener);
cg.setBackground(getResources().getDrawable(R.drawable.bg_land_mdpi));
mainLayout.addView(cg);
// getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
Log.d("game", "Started Advanced game");
} else if (str.equals("Expert")) {
cg = new CatchGame(this, 7, name, onScoreListener);
//setContentView(cg);
mainLayout.addView(cg);
getSupportActionBar().hide();
setContentView(mainLayout);
}
}
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
}
CatchGame cg;
public TextView textView;
public LinearLayout mainLayout;
String[] spinnerValue = {"Difficulty", "Rookie", "Advanced", "Expert", "Master"};
// start app
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainLayout = new LinearLayout(this);
mainLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout menuLayout = new LinearLayout(this);
menuLayout.setBackgroundColor(Color.parseColor("#FFFFFF"));
textView = new TextView(this);
textView.setVisibility(View.VISIBLE);
String str = "Score: 0";
textView.setText(str);
menuLayout.addView(textView);
Button button = new Button(this);
button.setText("Pause");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
togglePausePlay();
}
});
menuLayout.addView(button);
Spinner spinner2 = new Spinner(this);
spinner2.setOnItemSelectedListener(this);
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, spinnerValue);
spinner2.setAdapter(adapter);
menuLayout.addView(spinner2);
mainLayout.addView(menuLayout);
cg = new CatchGame(this, 5, "Jamie", onScoreListener);
cg.setBackground(getResources().getDrawable(R.drawable.bg_land_mdpi));
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
}
private void togglePausePlay() {
if (cg.paused) {
// play
// getSupportActionBar().hide();
Toast.makeText(MainActivity.this, "Play", Toast.LENGTH_SHORT).show();
} else {
// pause
// getSupportActionBar().show();
Toast.makeText(MainActivity.this, "Pause", Toast.LENGTH_SHORT).show();
}
cg.paused = !cg.paused;
}
private OnScoreListener onScoreListener = new OnScoreListener() {
#Override
public void onScore(int score) {
textView.setText("Score: " + score);
}
};
interface OnScoreListener {
void onScore(int score);
}
class CatchGame extends View {
int NBRSTEPS; // number of discrete positions in the x-dimension; must be uneven
String heroName;
int screenW;
int screenH;
int[] x; // x-coordinates for falling objects
int[] y; // y-coordinates for falling objects
int[] hero_positions; // x-coordinates for hero
Random random = new Random();
int ballW; // width of each falling object
int ballH; // height of ditto
float dY; //vertical speed
Bitmap falling, hero, jamie2, jamieleft, jamieright, falling2;
int heroXCoord;
int heroYCoord;
int xsteps;
int score;
int offset;
boolean gameOver; // default value is false
boolean toastDisplayed;
boolean paused = false;
OnScoreListener onScoreListener;
// constructor, load images and get sizes
public CatchGame(Context context, int difficulty, String name, OnScoreListener onScoreListener) {
super(context);
NBRSTEPS = difficulty;
heroName = name;
this.onScoreListener = onScoreListener;
x = new int[NBRSTEPS];
y = new int[NBRSTEPS];
hero_positions = new int[NBRSTEPS];
int resourceIdFalling = 0;
int resourceIdFalling2 = 0;
int resourceIdHero = 0;
if (heroName.equals("Jamie")) {
resourceIdFalling = R.mipmap.falling_object2;
resourceIdFalling2 = R.drawable.coconut_hdpi;
resourceIdHero = R.drawable.left_side_hdpi;
setBackground(getResources().getDrawable(R.mipmap.background));
}
falling = BitmapFactory.decodeResource(getResources(), resourceIdFalling); //load a falling image
falling2 = BitmapFactory.decodeResource(getResources(), resourceIdFalling2); //load a falling image
hero = BitmapFactory.decodeResource(getResources(), resourceIdHero); //load a hero image
jamieleft = BitmapFactory.decodeResource(getResources(), R.drawable.left_side_hdpi); //load a hero image
jamieright = BitmapFactory.decodeResource(getResources(), R.drawable.right_side_hdpi); //load a hero image
ballW = falling.getWidth();
ballH = falling.getHeight();
}
// set coordinates, etc.
void initialize() {
if (!gameOver) { // run only once, when the game is first started
int maxOffset = (NBRSTEPS - 1) / 2;
for (int i = 0; i < x.length; i++) {
int origin = (screenW / 2) + xsteps * (i - maxOffset);
x[i] = origin - (ballW / 2);
hero_positions[i] = origin - hero.getWidth();
}
int heroWidth = hero.getWidth();
int heroHeight = hero.getHeight();
hero = Bitmap.createScaledBitmap(hero, heroWidth * 2, heroHeight * 2, true);
hero = Bitmap.createScaledBitmap(hero, heroWidth * 2, heroHeight * 2, true);
jamieleft = Bitmap.createScaledBitmap(jamieleft, jamieleft.getWidth() * 2, jamieright.getWidth() * 2, true);
jamieright = Bitmap.createScaledBitmap(jamieright, jamieright.getWidth() * 2, jamieright.getWidth() * 2, true);
heroYCoord = screenH - 2 * heroHeight; // bottom of screen
}
for (int i = 0; i < y.length; i++) {
y[i] = -random.nextInt(1000); // place items randomly in vertical direction
}
offset = (NBRSTEPS - 1) / 2; // place hero at centre of the screen
heroXCoord = hero_positions[offset];
// initialize or reset global attributes
dY = 2.0f;
score = 0;
gameOver = false;
toastDisplayed = false;
}
// method called when the screen opens
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenW = w;
screenH = h;
xsteps = w / NBRSTEPS;
initialize();
}
// method called when the "game over" toast has finished displaying
void restart(Canvas canvas) {
toastDisplayed = true;
initialize();
draw(canvas);
}
// update the canvas in order to display the game action
#Override
public void onDraw(Canvas canvas) {
if (toastDisplayed) {
restart(canvas);
return;
}
super.onDraw(canvas);
int heroHeight = hero.getHeight();
int heroWidth = hero.getWidth();
int heroCentre = heroXCoord + heroWidth / 2;
Context context = this.getContext();
// compute locations of falling objects
for (int i = 0; i < y.length; i++) {
if (!paused) {
y[i] += (int) dY;
}
// if falling object hits bottom of screen
if (y[i] > (screenH - ballH) && !gameOver) {
dY = 0;
gameOver = true;
paused = true;
int duration = Toast.LENGTH_SHORT;
final Toast toast = Toast.makeText(context, "GAME OVER!\nScore: " + score, duration);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
toastDisplayed = true;
}
}, 3000);
//Vibrator v = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
// Vibrate for 3000 milliseconds
//v.vibrate(3000);
}
// if the hero catches a falling object
if (x[i] < heroCentre && x[i] + ballW > heroCentre &&
y[i] > screenH - ballH - heroHeight) {
y[i] = -random.nextInt(1000); // reset to new vertical position
score += 1;
onScoreListener.onScore(score);
}
}
canvas.save(); //Save the position of the canvas.
for (int i = 0; i < y.length; i++) {
if (i % 2 == 0)
canvas.drawBitmap(falling2, x[i], y[i], null); //Draw the falling on the canvas.
else
canvas.drawBitmap(falling, x[i], y[i], null); //Draw the falling on the canvas.
}
canvas.drawBitmap(hero, heroXCoord, heroYCoord, null); //Draw the hero on the canvas.
canvas.restore();
//Call the next frame.
invalidate();
}
// event listener for when the user touches the screen
#Override
public boolean onTouchEvent(MotionEvent event) {
if (paused) {
paused = false;
}
int action = MotionEventCompat.getActionMasked(event);
if (action != MotionEvent.ACTION_DOWN || gameOver) { // non-touchdown event or gameover
return true; // do nothing
}
int coordX = (int) event.getX();
int xCentre = (screenW / 2) - (hero.getWidth() / 2);
int maxOffset = hero_positions.length - 1; // can't move outside right edge of screen
int minOffset = 0; // ditto left edge of screen
if (coordX < xCentre && offset > minOffset) { // touch event left of the centre of screen
offset--; // move hero to the left
if (coordX < heroXCoord)// + heroWidth / 2)
hero = Bitmap.createScaledBitmap(jamieleft, jamieleft.getWidth(), jamieleft.getHeight(), true);
}
if (coordX > xCentre && offset < maxOffset) { // touch event right of the centre of screen
offset++; // move hero to the right
if (coordX > heroXCoord)
hero = Bitmap.createScaledBitmap(jamieright, jamieright.getWidth(), jamieright.getHeight(), true);
}
heroXCoord = hero_positions[offset];
return true;
}
}
}
Related
I try to run a test for my android app but I get this trace. What does it mean?
java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:390)
at android.widget.Toast.<init>(Toast.java:114)
at android.widget.Toast.makeText(Toast.java:277)
at android.widget.Toast.makeText(Toast.java:267)
at dev.android.gamex.CatchGame.onDraw(MainActivity.java:317)
at dev.android.gamex.JamieTest.useAppContext(JamieTest.java:45)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:58)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:375)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2074)
Tests ran to completion.
My test class
package dev.android.gamex;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.test.InstrumentationRegistry;
import android.widget.TextView;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class JamieTest {
private static final String FAKE_STRING = "HELLO WORLD";
private OnScoreListener onScoreListener = new OnScoreListener() {
#Override
public void onScore(int score) {
}
};
#Mock
Canvas can;
#Test
public void useAppContext() throws Exception {
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("dev.android.gamex", appContext.getPackageName());
CatchGame cg = new CatchGame(appContext, 5, "Jamie", onScoreListener);
cg.initialize();
assertTrue(! cg.gameOver);
cg.onDraw(new Canvas());
assertTrue(! cg.paused);
}
}
The code I want to test is below.
package dev.android.gamex;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
CatchGame cg;
public TextView textView;
public LinearLayout mainLayout;
String[] spinnerValue = {"Rookie", "Advanced", "Expert", "Master"};
// start app
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainLayout = new LinearLayout(this);
mainLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout menuLayout = new LinearLayout(this);
menuLayout.setBackgroundColor(Color.parseColor("#FFFFFF"));
textView = new TextView(this);
textView.setVisibility(View.VISIBLE);
String str = "Score: 0";
textView.setText(str);
menuLayout.addView(textView);
Button button = new Button(this);
button.setText("Pause");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
togglePausePlay();
}
});
menuLayout.addView(button);
Spinner spinner2 =new Spinner(this);
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, spinnerValue);
spinner2.setAdapter(adapter);
menuLayout.addView(spinner2);
mainLayout.addView(menuLayout);
cg = new CatchGame(this, 5, "Jamie", onScoreListener);
cg.setBackground(getResources().getDrawable(R.drawable.bg_land_mdpi));
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
}
private void togglePausePlay() {
if (cg.paused) {
// play
// getSupportActionBar().hide();
Toast.makeText(MainActivity.this, "Play", Toast.LENGTH_SHORT).show();
} else {
// pause
// getSupportActionBar().show();
Toast.makeText(MainActivity.this, "Pause", Toast.LENGTH_SHORT).show();
}
cg.paused = !cg.paused;
}
private OnScoreListener onScoreListener = new OnScoreListener() {
#Override
public void onScore(int score) {
textView.setText("Score: " + score);
}
};
#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, menu);
return true;
}
// method called when top right menu is tapped
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
int difficulty = cg.NBRSTEPS;
String name = cg.heroName;
switch (item.getItemId()) {
case R.id.item11:
cg = new CatchGame(this, 3, name, onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item12:
cg = new CatchGame(this, 5, name, onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item13:
cg = new CatchGame(this, 7, name, onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item14:
cg = new CatchGame(this, 9, name, onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item15:
cg = new CatchGame(this, 11, name, onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item21:
cg = new CatchGame(this, difficulty, "Jamie", onScoreListener);
setContentView(cg);
mainLayout.addView(cg);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(mainLayout);
return true;
case R.id.item22:
cg = new CatchGame(this, difficulty, "Spaceship", onScoreListener);
setContentView(cg);
//mainLayout.addView(cg);
//getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
//setContentView(mainLayout);
return true;
default:
cg.paused = true;
return super.onOptionsItemSelected(item);
}
}
}
interface OnScoreListener {
void onScore(int score);
}
class CatchGame extends View {
int NBRSTEPS; // number of discrete positions in the x-dimension; must be uneven
String heroName;
int screenW;
int screenH;
int[] x; // x-coordinates for falling objects
int[] y; // y-coordinates for falling objects
int[] hero_positions; // x-coordinates for hero
Random random = new Random();
int ballW; // width of each falling object
int ballH; // height of ditto
float dY; //vertical speed
Bitmap falling, hero, jamie2, jamieleft, jamieright;
int heroXCoord;
int heroYCoord;
int xsteps;
int score;
int offset;
boolean gameOver; // default value is false
boolean toastDisplayed;
boolean paused = false;
OnScoreListener onScoreListener;
// constructor, load images and get sizes
public CatchGame(Context context, int difficulty, String name, OnScoreListener onScoreListener) {
super(context);
NBRSTEPS = difficulty;
heroName = name;
this.onScoreListener = onScoreListener;
x = new int[NBRSTEPS];
y = new int[NBRSTEPS];
hero_positions = new int[NBRSTEPS];
int resourceIdFalling = 0;
int resourceIdHero = 0;
if (heroName.equals("Jamie")) {
resourceIdFalling = R.mipmap.falling_object2;
resourceIdHero = R.drawable.left_side_hdpi;
setBackground(getResources().getDrawable(R.mipmap.background));
}
if (heroName.equals("Spaceship")) {
resourceIdFalling = R.mipmap.falling_object;
resourceIdHero = R.mipmap.ufo;
setBackground(getResources().getDrawable(R.mipmap.space));
}
falling = BitmapFactory.decodeResource(getResources(), resourceIdFalling); //load a falling image
hero = BitmapFactory.decodeResource(getResources(), resourceIdHero); //load a hero image
jamieleft = BitmapFactory.decodeResource(getResources(), R.drawable.left_side_hdpi); //load a hero image
jamieright = BitmapFactory.decodeResource(getResources(), R.drawable.right_side_hdpi); //load a hero image
ballW = falling.getWidth();
ballH = falling.getHeight();
}
public CatchGame(Context context, int difficulty, String name, OnScoreListener onScoreListener, Drawable background) {
this(context, difficulty, name, onScoreListener);
this.setBackground(background);
}
// set coordinates, etc.
void initialize() {
if (!gameOver) { // run only once, when the game is first started
int maxOffset = (NBRSTEPS - 1) / 2;
for (int i = 0; i < x.length; i++) {
int origin = (screenW / 2) + xsteps * (i - maxOffset);
x[i] = origin - (ballW / 2);
hero_positions[i] = origin - hero.getWidth();
}
int heroWidth = hero.getWidth();
int heroHeight = hero.getHeight();
hero = Bitmap.createScaledBitmap(hero, heroWidth * 2, heroHeight * 2, true);
hero = Bitmap.createScaledBitmap(hero, heroWidth * 2, heroHeight * 2, true);
jamieleft = Bitmap.createScaledBitmap(jamieleft, jamieleft.getWidth()* 2, jamieright.getWidth() * 2, true);
jamieright = Bitmap.createScaledBitmap(jamieright, jamieright.getWidth()* 2, jamieright.getWidth() * 2, true);
heroYCoord = screenH - 2 * heroHeight; // bottom of screen
}
for (int i = 0; i < y.length; i++) {
y[i] = -random.nextInt(1000); // place items randomly in vertical direction
}
offset = (NBRSTEPS - 1) / 2; // place hero at centre of the screen
heroXCoord = hero_positions[offset];
// initialize or reset global attributes
dY = 2.0f;
score = 0;
gameOver = false;
toastDisplayed = false;
}
// method called when the screen opens
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenW = w;
screenH = h;
xsteps = w / NBRSTEPS;
initialize();
}
// method called when the "game over" toast has finished displaying
void restart(Canvas canvas) {
toastDisplayed = true;
initialize();
draw(canvas);
}
// update the canvas in order to display the game action
#Override
public void onDraw(Canvas canvas) {
if (toastDisplayed) {
restart(canvas);
return;
}
super.onDraw(canvas);
int heroHeight = hero.getHeight();
int heroWidth = hero.getWidth();
int heroCentre = heroXCoord + heroWidth / 2;
Context context = this.getContext();
// compute locations of falling objects
for (int i = 0; i < y.length; i++) {
if (!paused) {
y[i] += (int) dY;
}
// if falling object hits bottom of screen
if (y[i] > (screenH - ballH) && !gameOver) {
dY = 0;
gameOver = true;
paused = true;
int duration = Toast.LENGTH_SHORT;
final Toast toast = Toast.makeText(context, "GAME OVER!\nScore: " + score, duration);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
toastDisplayed = true;
}
}, 3000);
//Vibrator v = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
// Vibrate for 3000 milliseconds
//v.vibrate(3000);
}
// if the hero catches a falling object
if (x[i] < heroCentre && x[i] + ballW > heroCentre &&
y[i] > screenH - ballH - heroHeight) {
y[i] = -random.nextInt(1000); // reset to new vertical position
score += 1;
onScoreListener.onScore(score);
}
}
canvas.save(); //Save the position of the canvas.
for (int i = 0; i < y.length; i++) {
canvas.drawBitmap(falling, x[i], y[i], null); //Draw the falling on the canvas.
}
canvas.drawBitmap(hero, heroXCoord, heroYCoord, null); //Draw the hero on the canvas.
canvas.restore();
//Call the next frame.
invalidate();
}
// event listener for when the user touches the screen
#Override
public boolean onTouchEvent(MotionEvent event) {
if (paused) {
paused = false;
}
int action = MotionEventCompat.getActionMasked(event);
if (action != MotionEvent.ACTION_DOWN || gameOver) { // non-touchdown event or gameover
return true; // do nothing
}
int coordX = (int) event.getX();
int xCentre = (screenW / 2) - (hero.getWidth() / 2);
int maxOffset = hero_positions.length - 1; // can't move outside right edge of screen
int minOffset = 0; // ditto left edge of screen
if (coordX < xCentre && offset > minOffset) { // touch event left of the centre of screen
offset--; // move hero to the left
if(coordX < heroXCoord)// + heroWidth / 2)
hero = Bitmap.createScaledBitmap(jamieleft, jamieleft.getWidth() , jamieleft.getHeight() , true);
}
if (coordX > xCentre && offset < maxOffset) { // touch event right of the centre of screen
offset++; // move hero to the right
if(coordX > heroXCoord)
hero = Bitmap.createScaledBitmap(jamieright, jamieright.getWidth() , jamieright.getHeight() , true);
}
heroXCoord = hero_positions[offset];
return true;
}
}
The repository is available online.
You CANNOT show a Toast on non-UI thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread.
You could use Activity#runOnUiThread():
runOnUiThread(new Runnable() {
public void run() {
final Toast toast = Toast.makeText(context, "GAME OVER!\nScore: " + score, duration);
toast.show();
}
});
If you want execute a instrumentation test on main thread, add #UiThreadTest annotation:
#Test
#UiThreadTest
public void useAppContext() {
// ...
}
P.s: There are also many other ways with explain (using Handler, Looper, Observable..) in these posts: Android: Toast in a thread and Can't create handler inside thread that has not called Looper.prepare()
One cannot show a Toast from a non UI Thread. So you can do the following from the worker thread and it doesn't require Activity or Context
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast toast = Toast.makeText(mContext, "Toast", Toast.LENGTH_SHORT);
toast.show();
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
Toast.makeText(mContext, "Toast", Toast.LENGTH_SHORT).show()
}
In kotlin put your code inside this:
runOnUiThread {
Log.i(TAG, "runOnUiThread")
Toast.makeText(MainActivity.this, "Play", Toast.LENGTH_SHORT).show()
}
Run Your UI component with runOnUiThread, this is what i did - KOTLIN
inner class yourThread : Thread() {
override fun run() {
// this is for fragment, you can use 'this' for Activity
requireActivity().runOnUiThread {
// Your Toast
Toast.makeText(requireContext(), "Toasted",Toast.LENGTH_LONG).show()
}
}
I'm trying to make small App. This App have Activity, Custom View Class, and service.
1) Activity ask service for new Data and redraw Custom view
2) Service is listning to Bluetooth device and parse data.
Everything was fine, but I noticed that App is slowing down after 40 mins working.
I made another project remove service and find that it slowing too! So problem is my Customview class, maybe i have memory leaks in service to... but i have problem with drawings 100%.
I found that i have some objects that i'm creating on onDraw() method.. i try to move all thise staff to onSizeChanged() - but get more lags.
And now i need help. I need some example with simple drawings that depends on device width and height (I think my method is wrong - i use proportions of my 'Design' to calculate demetions in px)
By the way i'm using animator which make animations more smooth))
public class Dynamics {
/**
* Used to compare floats, if the difference is smaller than this, they are
* considered equal
*/
private static final float TOLERANCE = 0.01f;
/** The position the dynamics should to be at */
private float targetPosition;
/** The current position of the dynamics */
private float position;
/** The current velocity of the dynamics */
private float velocity;
/** The time the last update happened */
private long lastTime;
/** The amount of springiness that the dynamics has */
private float springiness;
/** The damping that the dynamics has */
private double damping;
public Dynamics(float springiness, float dampingRatio) {
this.springiness = springiness;
this.damping = dampingRatio * 2 * Math.sqrt(springiness);
}
public void setPosition(float position, long now) {
this.position = position;
lastTime = now;
}
public void setVelocity(float velocity, long now) {
this.velocity = velocity;
lastTime = now;
}
public void setTargetPosition(float targetPosition, long now) {
this.targetPosition = targetPosition;
lastTime = now;
}
public void update(long now) {
float dt = Math.min(now - lastTime, 50) / 1000f;
float x = position - targetPosition;
double acceleration = -springiness * x - damping * velocity;
velocity += acceleration * dt;
position += velocity * dt;
lastTime = now;
}
public boolean isAtRest() {
final boolean standingStill = Math.abs(velocity) < TOLERANCE;
final boolean isAtTarget = (targetPosition - position) < TOLERANCE;
return standingStill && isAtTarget;
}
public float getPosition() {
return position;
}
public float getTargetPos() {
return targetPosition;
}
public float getVelocity() {
return velocity;
}
}
In my Custom view i have this to set new data:
public void SetData(int[] NewData2,float[]newDatapoints)
{
this.NewData=NewData2;
long now = AnimationUtils.currentAnimationTimeMillis();
if (datapoints == null || datapoints.length != newDatapoints.length) {
datapoints = new Dynamics[newDatapoints.length];
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i] = new Dynamics(70f, 0.50f);
datapoints[i].setPosition(newDatapoints[i], now);
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
invalidate();
} else {
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
removeCallbacks(animator);
post(animator);
}
LastData=NewData;
//redraw();
}
Thise is "code" of my custom view, after all changes it's look terible, so i cut 90% of it. And i make some test code insted:
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.AnimationUtils;
import java.io.IOException;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Random;
public class CustomDisplayView extends View {
//paint for drawing custom view
private Paint RectPaint = new Paint();
//Динамические данные float
private Dynamics[] datapoints;
//Динамические статические Int
private int[] NewData = new int[500];
//созадем новый объект квадрат
private RectF rectf= new RectF();
//Задаем массив динамических цветов
int[] CurColors= new int[100];
int[] TargetColors= new int[100];
public CustomDisplayView(Context context, AttributeSet attrs){
super(context, attrs);
//Установка парметров красок
RectPaint.setAntiAlias(true);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != 0 && h != 0) {
//create Bitmap here
}
}
/**
* Override the onDraw method to specify custom view appearance using canvas
*/
#Override
protected void onDraw(Canvas canvas) {
//Get Screen size
//int viewWidth=this.getMeasuredWidth();
// int viewHeight = this.getMeasuredHeight();
//Выводим код цвета
RectPaint.setColor(0xff000000);
RectPaint.setTextSize(40);
canvas.restore();
canvas.drawText("V: " + datapoints[1].getPosition(), 20, 60, RectPaint);
//int saveCount = canvas.save();
for(int a=0;a<1000;a++)
{
rectf.set(datapoints[a].getPosition(), datapoints[a + 1].getPosition(), datapoints[a].getPosition() + datapoints[a + 1].getPosition() / 10, datapoints[a + 1].getPosition() + datapoints[a + 1].getPosition() / 10);
RectPaint.setColor(0x88005020);
//RectPaint.setColor(CurColor[a]);
//canvas.rotate(datapoints[1].getPosition(), viewWidth/2, viewHeight/2);
canvas.drawRoundRect(rectf, 0, 0, RectPaint);
//canvas.restore();
}
//canvas.restoreToCount(saveCount);
/*
for(int a=0;a<999;a++)
{
CurColors[a]=progressiveColor(CurColors[a], TargetColors[a], 2);
if(CurColors[a]==TargetColors[a])
{
TargetColors[a]=randomColor();
}
}
*/
canvas.restore();
}
//Рандом колор
public static int randomColor(){
Random random = new Random();
int[] ColorParams= new int[4];
ColorParams[0]=random.nextInt(235)+20;
ColorParams[1]=random.nextInt(255);
ColorParams[2]=random.nextInt(255);
ColorParams[3]=random.nextInt(255);
return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);
}
//Интерполяция цвета
public static int progressiveColor(int CurColor,int TargetColor,int Step){
//Current color
int[] ColorParams= new int[4];
ColorParams[0]=(CurColor >> 24) & 0xFF;
ColorParams[1]=(CurColor >> 16) & 0xFF;
ColorParams[2]=(CurColor >> 8) & 0xFF;
ColorParams[3]=CurColor & 0xFF;
//TargetColor
int[] TargetColorParams= new int[4];
TargetColorParams[0]=(TargetColor >> 24) & 0xFF;
TargetColorParams[1]=(TargetColor >> 16) & 0xFF;
TargetColorParams[2]=(TargetColor >> 8) & 0xFF;
TargetColorParams[3]=TargetColor & 0xFF;
for(int i=0;i<4;i++)
{
if(ColorParams[i]<TargetColorParams[i])
{
ColorParams[i]+=Step;
if(ColorParams[i]>TargetColorParams[i])
{
ColorParams[i]=TargetColorParams[i];
}
}
else if(ColorParams[i]>TargetColorParams[i])
{
ColorParams[i]-=Step;
if(ColorParams[i]<TargetColorParams[i])
{
ColorParams[i]=TargetColorParams[i];
}
}
}
//int red = r - (int)((float)(r*255)/(float)all);
//int green = (int)((float)(g*255)/(float)all);
return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);
//return String.format("#%06X", (0xFFFFFF & Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3])));
//return " "+opacity+" "+red+" "+green+" "+blue;
}
//each custom attribute should have a get and set method
//this allows updating these properties in Java
//we call these in the main Activity class
/**
* Get the current text label color
* #return color as an int
*/
public int getLabelColor(){
return 1;
}
/**
* Set the label color
* #param newColor new color as an int
*/
public void setLabelColor(int newColor){
//update the instance variable
//labelCol=newColor;
//redraw the view
invalidate();
requestLayout();
}
public void redraw(){
//redraw the view
invalidate();
requestLayout();
}
public void SetData(int[] NewData2,float[]newDatapoints)
{
this.NewData=NewData2;
long now = AnimationUtils.currentAnimationTimeMillis();
if (datapoints == null || datapoints.length != newDatapoints.length) {
datapoints = new Dynamics[newDatapoints.length];
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i] = new Dynamics(70f, 0.50f);
datapoints[i].setPosition(newDatapoints[i], now);
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
invalidate();
} else {
for (int i = 0; i < newDatapoints.length; i++) {
datapoints[i].setTargetPosition(newDatapoints[i], now);
}
removeCallbacks(animator);
post(animator);
}
//redraw();
}
public int GetAction(float x,float y)
{
/*
if(x>(DicsCenterX-LineHalfSpeedZone) && x<(DicsCenterX+LineHalfSpeedZone) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
{
// private int SpeedZoneRadius2=0;
// private int PowerOutRadius=0;
//Смена режима
//начинаем смену размеру index / ms
ChangeVal(0,700);
return 1;
}
else if(x>(CofCantBGDrop*2) && x<(CofCantBGDrop*4) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
{
return 2;
}
else
{
return 0;
}
//return 0;
*/
return 1;
}
public static String fmt(double d)
{
double val = d/100;
String result;
if(val == (long) val)
result= String.format("%d",(long)d);
else
result= String.format("%s",d);
if(result.length()<2)
{
String result2=result;
result="0"+result2;
}
return result;
}
private Runnable animator = new Runnable() {
#Override
public void run() {
boolean needNewFrame = false;
long now = AnimationUtils.currentAnimationTimeMillis();
for (Dynamics dynamics : datapoints) {
dynamics.update(now);
if (!dynamics.isAtRest()) {
needNewFrame = true;
}
}
if (needNewFrame) {
postDelayed(this, 15);
}
invalidate();
}
};
}
I just want to understand where i need to declare scale values, where i need to calc real dimensions in px.. and et.c. to have no memory leaks..
If i remove color change and incrice number of Rects up to 1000 - i get lags.
All methods o any information how to debug memory leaks - you are wellcome!
You have to remove runnable for animation when view is detached.
if (needNewFrame) {
postDelayed(this, 15); <--- memory leak
}
Try like this.
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallback(your runnable);
}
Also refreshing every 15 milliseconds is very heavy.
I'm trying to create something like this. The problem is how to create vertical lines close to the seekbar. I tried the code given here, but the seekbar line disappears. Any help would be appreciated. Here is what I've done so far.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SeekBar sb = (SeekBar)findViewById(R.id.seekBar1);
//Get the width of the main view.
Display display = getWindowManager().getDefaultDisplay();
Point displaysize = new Point();
display.getSize(displaysize);
int width = displaysize.x;
//set the seekbar maximum (Must be a even number, having a remainder will cause undersirable results)
//this variable will also determine the number of points on the scale.
int seekbarmax = 10;
int seekbarpoints = (width/seekbarmax); //this will determine how many points on the scale there should be on the seekbar
//find the seekbar in the view, and set some behaviour properties
SeekBar seekbar = (SeekBar)findViewById(R.id.seekBar1);
//Set the seekbar to a max range of 10
seekbar.setMax(seekbarmax);
//Create a new bitmap that is the width of the screen
Bitmap bitmap = Bitmap.createBitmap(width, 100, Bitmap.Config.ARGB_8888);
//A new canvas to draw on.
Canvas canvas = new Canvas(bitmap);
//a new style of painting - colour and stoke thickness.
Paint paint = new Paint();
paint.setColor(Color.BLUE); //Set the colour to red
paint.setStyle(Paint.Style.STROKE); //set the style
paint.setStrokeWidth(1); //Stoke width
Paint textpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textpaint.setColor(Color.rgb(61, 61, 61));// text color RGB
textpaint.setTextSize(28);// text size
int point = 0; //initiate the point variable
//Start a for loop that will loop seekbarpoints number of times.
for (int i = 0; i < seekbarpoints; i++ ){
if ((i%2)==0) {
//short line
point = point + seekbarpoints;
canvas.drawLine(point, 30, point, 0, paint);
//drawLine(startx,startx,endy,endy)
}
//Create a new Drawable
Drawable d = new BitmapDrawable(getResources(),bitmap);
//Set the seekbar widgets background to the above drawable.
seekbar.setProgressDrawable(d);
}
}
}
I was searching for the this for long time and only got an answer to draw the numbers. Thus I decided to do it myself. I took the solution having only the steps and extended it by adding the logic for the intervals.
Please see the below image.
I then successfully created a seekbar with interval lables and vertical lines over seekbar. The above image is what I've achieved.
However there are few optimization in the padding which you can work on adjusting the dimensions.
Solution :
The xml file for the intervals:
seekbar_with_intervals_labels
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textViewInterval"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#707070"/>
XML for the Vertical deviders : seekbar_vertical_lines
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textViewVerticalLine"
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#drawable/lines" />
Then the custom Seekbar class :
package com.example.abc.myapplication;
import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import com.example.abc.myapplication.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekbarWithIntervals extends LinearLayout {
private RelativeLayout RelativeLayout = null;
private SeekBar Seekbar = null;
private RelativeLayout Divider = null;
private View verticalLine = null;
private int WidthMeasureSpec = 0;
private int HeightMeasureSpec = 0;
public SeekbarWithIntervals(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
getActivity().getLayoutInflater()
.inflate(R.layout.seekbar_with_intervals, this);
}
private Activity getActivity() {
return (Activity) getContext();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
verticalLine = new View(getActivity());
verticalLine.setLayoutParams(new LayoutParams(2, LayoutParams.MATCH_PARENT));
verticalLine.setBackgroundColor(Color.BLACK);
if (changed) {
alignIntervals();
// We've changed the intervals layout, we need to refresh.
RelativeLayout.measure(WidthMeasureSpec, HeightMeasureSpec);
RelativeLayout.layout(RelativeLayout.getLeft(), RelativeLayout.getTop(), RelativeLayout.getRight(), RelativeLayout.getBottom());
}
}
private void alignIntervals() {
int widthOfSeekbarThumb = getSeekbarThumbWidth();
int thumbOffset = widthOfSeekbarThumb / 2;
int widthOfSeekbar = getSeekbar().getWidth();
int firstIntervalWidth = getRelativeLayout().getChildAt(0).getWidth();
int remainingPaddableWidth = widthOfSeekbar - firstIntervalWidth - widthOfSeekbarThumb;
int numberOfIntervals = getSeekbar().getMax();
int maximumWidthOfEachInterval = remainingPaddableWidth / numberOfIntervals;
alignFirstInterval(thumbOffset);
alignIntervalsInBetween(maximumWidthOfEachInterval);
alignLastInterval(thumbOffset, maximumWidthOfEachInterval);
}
private int getSeekbarThumbWidth() {
return getResources().getDimensionPixelOffset(R.dimen.seekbar_thumb_width);
}
private void alignFirstInterval(int offset) {
TextView firstInterval = (TextView) getRelativeLayout().getChildAt(0);
firstInterval.setPadding(offset - 10, 0, 0, 0);
TextView firstLine = (TextView) getDivider().getChildAt(0);
firstLine.setPadding(offset + 10, 0, 0, 0);
}
private void alignIntervalsInBetween(int maximumWidthOfEachInterval) {
int widthOfPreviousIntervalsText = 0;
int widthOfPreviousLine = 0;
// Don't align the first or last interval.
for (int index = 1; index < (getRelativeLayout().getChildCount() - 1); index++) {
TextView textViewInterval = (TextView) getRelativeLayout().getChildAt(index);
int widthOfText = textViewInterval.getWidth();
// This works out how much left padding is needed to center the current interval.
//int leftPadding = Math.round(maximumWidthOfEachInterval - (widthOfText / 2) - (widthOfPreviousIntervalsText / 2) - (widthOfText / 2));
int leftPadding = Math.round(maximumWidthOfEachInterval - (widthOfText / 2) - (widthOfPreviousIntervalsText / 2) - (widthOfText / index ) + index + 5 * 5);
textViewInterval.setPadding(leftPadding, 0, 0, 0);
widthOfPreviousIntervalsText = widthOfText;
TextView textViewLine = (TextView) getDivider().getChildAt(index);
int widthOfLine = textViewLine.getWidth();
// This works out how much left padding is needed to center the current interval.
leftPadding = (maximumWidthOfEachInterval + (index + (maximumWidthOfEachInterval / 10)) - (index * 4)); //Math.round(maximumWidthOfEachInterval + (widthOfLine ) + (widthOfPreviousLine ));
//leftPadding = Math.round((maximumWidthOfEachInterval - (widthOfPreviousLine / index) - (widthOfPreviousLine / index) - (widthOfPreviousLine / index)) + 10);
textViewLine.setPadding(leftPadding , 0, 0, 0);
widthOfPreviousLine = widthOfLine;
}
}
private void alignLastInterval(int offset, int maximumWidthOfEachInterval) {
int lastIndex = getRelativeLayout().getChildCount() - 1;
TextView lastInterval = (TextView) getRelativeLayout().getChildAt(lastIndex);
int widthOfText = lastInterval.getWidth();
int leftPadding = Math.round(maximumWidthOfEachInterval - widthOfText - offset);
lastInterval.setPadding(leftPadding + 20, 0, 0, 0);
TextView lastLine = (TextView) getDivider().getChildAt(lastIndex);
leftPadding = Math.round(maximumWidthOfEachInterval - (widthOfText / 5) - (widthOfText / 5) - (widthOfText / 5 ) + 3 * 10);
lastLine.setPadding(leftPadding , 0, 0, 0);
}
protected synchronized void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
WidthMeasureSpec = widthMeasureSpec;
HeightMeasureSpec = heightMeasureSpec;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int getProgress() {
return getSeekbar().getProgress();
}
public void setProgress(int progress) {
getSeekbar().setProgress(progress);
}
public void setIntervals(List<String> intervals) {
displayIntervals(intervals);
getSeekbar().setMax(intervals.size() - 1);
}
private void displayIntervals(List<String> intervals) {
int idOfPreviousInterval = 0;
int idOfPreviousLine = 0;
if (getRelativeLayout().getChildCount() == 0) {
for (String interval : intervals) {
TextView textViewInterval = createInterval(interval);
alignTextViewToRightOfPreviousInterval(textViewInterval, idOfPreviousInterval);
TextView textViewVerticaLine = createVerticalLine();
alignTextViewToRightOfPreviousInterval(textViewVerticaLine, idOfPreviousLine);
idOfPreviousLine = textViewVerticaLine.getId();
idOfPreviousInterval = textViewInterval.getId();
getRelativeLayout().addView(textViewInterval);
getDivider().addView(textViewVerticaLine);
}
}
}
private TextView createInterval(String interval) {
View textBoxView = (View) LayoutInflater.from(getContext())
.inflate(R.layout.seekbar_with_intervals_labels, null);
TextView textView = (TextView) textBoxView
.findViewById(R.id.textViewInterval);
textView.setId(View.generateViewId());
textView.setText(interval);
return textView;
}
private TextView createVerticalLine() {
View textBoxView = (View) LayoutInflater.from(getContext())
.inflate(R.layout.seekbar_vertical_lines, null);
TextView textView = (TextView) textBoxView
.findViewById(R.id.textViewVerticalLine);
textView.setId(View.generateViewId());
return textView;
}
private void alignTextViewToRightOfPreviousInterval(TextView textView, int idOfPreviousInterval) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (idOfPreviousInterval > 0) {
params.addRule(RelativeLayout.RIGHT_OF, idOfPreviousInterval);
}
textView.setLayoutParams(params);
}
public void setOnSeekBarChangeListener(OnSeekBarChangeListener onSeekBarChangeListener) {
getSeekbar().setOnSeekBarChangeListener(onSeekBarChangeListener);
}
private RelativeLayout getRelativeLayout() {
if (RelativeLayout == null) {
RelativeLayout = (RelativeLayout) findViewById(R.id.intervals);
}
return RelativeLayout;
}
private SeekBar getSeekbar() {
if (Seekbar == null) {
Seekbar = (SeekBar) findViewById(R.id.seekbar);
}
return Seekbar;
}
private RelativeLayout getDivider() {
if (Divider == null) {
Divider = (RelativeLayout) findViewById(R.id.fl_divider);
}
return Divider;
}
}
Then the MainActivity where we dynamically add the intervals.
public class MainActivity extends AppCompatActivity {
private SeekbarWithIntervals SeekbarWithIntervals = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<String> seekbarIntervals = getIntervals();
getSeekbarWithIntervals().setIntervals(seekbarIntervals);
}
private List<String> getIntervals() {
return new ArrayList<String>() {{
add("45");
add("55");
add("65");
add("75");
add("85");
add("95");
}};
}
private SeekbarWithIntervals getSeekbarWithIntervals() {
if (SeekbarWithIntervals == null) {
SeekbarWithIntervals = (SeekbarWithIntervals) findViewById(R.id.seekbarWithIntervals);
}
return SeekbarWithIntervals;
}
}
You can put the padding bottom of the divider so as to push it upwards like in your image.
Note : You can also have a single layout defining the divider and the number layout.
You will need two PNG drawables one for background and one for progress.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#android:id/background"
android:drawable="#drawable/seekbar_drawable_frost" />
<item
android:id="#android:id/progress"
android:drawable="#drawable/seekbar_drawable_frost_progress" />
</layer-list>
I'm developing an android game, trying to store the character's coordinates. I'm using the onSaveInstanceState and onRestoreInstanceState methods. But when I tested the coordinates get's changed.
So it loads the correct value but after that it saves a bad number then it loads this bad value.
Class1
package hu.cig.vob;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import cug.hu.vob.R;
public class Level extends Activity {
private LevelView lv;
private LinearLayout linearL;
private Button left, right, jump, fire;
private mListener l = new mListener();
//Konstansok az activity allapotanak mentesehez
private String playerX = "PlayerX",playerY="PlayerY",playerH="PlayerH";
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.level_layout);
final ImageView healthBar = (ImageView) findViewById(R.id.life_view);
Drawable d = getResources().getDrawable(R.drawable.main_screen_bg);
linearL = (LinearLayout) findViewById(R.id.linear_layout);
linearL.setBackgroundDrawable(d);
lv = new LevelView(getApplicationContext(), getIntent().getIntExtra(
MainActivity.LEVEL_EXTRA, 0), getWindowManager());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT);
lv.setLayoutParams(params);
linearL.addView(lv, 0);
left = (Button) findViewById(R.id.left);
right = (Button) findViewById(R.id.right);
jump = (Button) findViewById(R.id.jump);
fire = (Button) findViewById(R.id.fire);
left.setOnTouchListener(l);
right.setOnTouchListener(l);
jump.setOnTouchListener(l);
fire.setOnTouchListener(l);
lv.setOnClickListener(new OnClickListener() {
// Game over screen esetén kilép
#Override
public void onClick(View v) {
if (lv.getGameState()) {
finish();
}
}
});
// Életcsik frissitése az életnek megfelelően
new Thread() {
#Override
public void run() {
while (true) {
if (lv.getRobot().getHealth() <= 0) {
runOnUiThread(new Runnable() {
#Override
public void run() {
healthBar.setImageResource(R.drawable.battery5);
}
});
} else if (lv.getRobot().getHealth() <= 25) {
runOnUiThread(new Runnable() {
#Override
public void run() {
healthBar.setImageResource(R.drawable.battery4);
}
});
} else if (lv.getRobot().getHealth() <= 50) {
runOnUiThread(new Runnable() {
#Override
public void run() {
healthBar.setImageResource(R.drawable.battery3);
}
});
} else if (lv.getRobot().getHealth() <= 75) {
runOnUiThread(new Runnable() {
#Override
public void run() {
healthBar.setImageResource(R.drawable.battery2);
}
});
}else if(lv.getRobot().getHealth() >= 75){
runOnUiThread(new Runnable() {
#Override
public void run() {
healthBar.setImageResource(R.drawable.battery);
}
});
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
#Override
protected void onPause() {
overridePendingTransition(0, 0);
super.onPause();
}
// TODO:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
lv.getRobot().setX(savedInstanceState.getInt(playerX));
lv.getRobot().setY(savedInstanceState.getInt(playerY));
Log.d("LoL","Loaded y:"+savedInstanceState.getInt(playerY));
lv.getRobot().setHealth(savedInstanceState.getInt(playerH));
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(playerX , lv.getRobot().getX());
outState.putInt(playerY, lv.getRobot().getY());
Log.d("LoL","Saved y:"+lv.getRobot().getY());
outState.putInt(playerH, lv.getRobot().getHealth() );
super.onSaveInstanceState(outState);
}
// iránygombok kezelése
private class mListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
switch (v.getId()) {
case R.id.left:
lv.getRobot().moveLeft();
break;
case R.id.right:
lv.getRobot().moveRight();
break;
case R.id.jump:
lv.getRobot().jump();
break;
case R.id.fire:
lv.getRobot().shot();
break;
}
break;
case MotionEvent.ACTION_UP:
switch (v.getId()) {
case R.id.left:
lv.getRobot().stopMovingLeft();
break;
case R.id.right:
lv.getRobot().stopMovingRight();
break;
case R.id.fire:
lv.getRobot()._shot();
break;
}
break;
}
return true;
}
}
}
class2
package hu.cig.vob;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import cug.hu.vob.R;
public class Robot {
private Bitmap icon, currIcon, iconShot;
private int x, y, speedX = 0, speedY = 0, health = 100;
private final int MOVESPEED = 3, JumpSpeed = 15;
private boolean isMovingLeft = false, isMovingRight = false,
isFalling = true, isJumping = false, canJump = true;
private Rect bottom, horizontal;
private Context context;
private List<Bullet> bullets = Collections
.synchronizedList(new ArrayList<Bullet>());
public Robot(int in_x, int in_y, Bitmap i, float sc, Context c) {
context = c;
icon = i;
currIcon = icon;
iconShot = BitmapFactory.decodeResource(c.getResources(),
R.drawable.shot_right);
x = in_x * (icon.getWidth()/2);
y = in_y * (icon.getHeight()/2);
y = (int) (sc - y);
// for colliding
horizontal = new Rect((int) (x + icon.getWidth() * (31.5 / 100)),
y + 5, (int) (x + icon.getWidth() - icon.getWidth()
* (31.5 / 100)), y + icon.getHeight() - 5);
bottom = new Rect((int) (x + icon.getWidth() * (31.5 / 100) + 5), y
+ icon.getHeight() - 10, (int) (x + icon.getWidth()
- icon.getWidth() * (31.5 / 100) - 5), y + icon.getHeight());
}
public void update(List<Block> blocks) {
int oldX = x, oldY = y;
if (!(x + speedX < 0 || x + speedX > LevelView.intScreenWidth)) {
x += speedX;
}
updateRect();
for (int i = 0; i < blocks.size(); i++) {
if (horizontal.intersect(blocks.get(i).getRect())) {
stopMovingRight();
stopMovingLeft();
x = oldX;
updateRect();
}
}
if (bullets.size() > 0) {
Iterator<Bullet> it = bullets.iterator();
while (it.hasNext()) {
Bullet b = it.next();
if (b.getCx() > LevelView.screenWidth) {
it.remove();
} else {
b.update();
}
Iterator<Block> itt = blocks.iterator();
while (itt.hasNext()) {
Block bb = itt.next();
if (bb.getRect().intersect(b.getRect())) {
it.remove();
}
}
}
}
// #graviti"
if (isJumping) {
y -= speedY;
speedY--;
if (speedY == 0) {
isFalling = true;
isJumping = false;
}
updateRect();
}
if (isFalling) {
y += JumpSpeed - 5;
canJump = false;
updateRect();
}
for (Block b : blocks) {
if (bottom.intersect(b.getRect())) {
y = oldY;
updateRect();
canJump = true;
}
}
}
private void updateRect() {
horizontal = new Rect((int) (x + icon.getWidth() * (31.5 / 100)),
y + 10, (int) (x + icon.getWidth() - icon.getWidth()
* (31.5 / 100)), y + icon.getHeight() - 10);
bottom = new Rect((int) (x + icon.getWidth() * (31.5 / 100) + 5), y
+ icon.getHeight() - 10, (int) (x + icon.getWidth()
- icon.getWidth() * (31.5 / 100) - 5), y + icon.getHeight() - 2);
}
public void moveLeft() {
speedX = -MOVESPEED;
isMovingLeft = true;
}
public void moveRight() {
speedX = MOVESPEED;
isMovingRight = true;
}
public void stopMovingLeft() {
isMovingLeft = false;
stop();
}
public void stopMovingRight() {
isMovingRight = false;
stop();
}
public void stop() {
if (isMovingRight == false && isMovingLeft == false) {
speedX = 0;
}
if (isMovingRight == true && isMovingLeft == false) {
moveRight();
}
if (isMovingRight == false && isMovingLeft == true) {
moveLeft();
}
}
public Bitmap getIcon() {
return currIcon;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getSpeed() {
return speedX;
}
public boolean isMovingLeft() {
return isMovingLeft;
}
public boolean isMovingRight() {
return isMovingRight;
}
public Rect getBottomRect() {
return bottom;
}
public Rect getHRect() {
return horizontal;
}
public int getHealth() {
return health;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setHealth(int health) {
this.health = health;
}
public void shot() {
currIcon = iconShot;
Bullet b = new Bullet((float) (x + iconShot.getWidth()),
(float) (y + ((26.31 * iconShot.getHeight()) / 100)),
Helper.convertPx_Dpi(10, context), 2);
bullets.add(b);
}
public void _shot() {
currIcon = icon;
}
public List<Bullet> getBullets() {
return bullets;
}
public void jump() {
if (!isJumping && canJump) {
isJumping = true;
isFalling = false;
speedY = JumpSpeed;
}
}
public void increaseHealth(int x){
health += x;
if(health > 100){
health = 100;
}
}
public void degreeseHealth(int a) {
health -= a;
}
}
Your app can resume while obscured by the lock screen. If you want to tell the difference between "resume is hidden by a lock screen" and "resume is actually displayed" you can check your window focus.
See Making Android Games that Play Nice for more details.
A different way to get a similar "wait until actually displayed" is to wait for the first Activity.onUserInteraction after a resume before restarting your game.
I am creating a floor map with n number of dynamic buttons with incremental value and added to a custom relative layout. Now i need to create onclicklistner for each buttons added to a view. How to get the id or some unique value to identify which button is clicked. Can somebody please help me on this i am breaking my head for the past 10 days. Thanks in advance.
This is my Custom Relative layout :
public class InteractiveView extends RelativeLayout implements OnClickListener{
Matrix matrix = new Matrix();
private float mPositionX = 0;
private float mPositionY = 0;
private float mScale = 0.1f;
private Context context;
private boolean canvasFlag = true;
public InteractiveView(Context context) {
super(context);
this.context = context;
this.setWillNotDraw(false);
// this.setOnTouchListener(mTouchListener);
this.setOnClickListener(this);
}
public void setPosition(float lPositionX, float lPositionY){
mPositionX = lPositionX;
mPositionY = lPositionY;
}
public void setMovingPosition(float lPositionX, float lPositionY){
mPositionX += lPositionX;
mPositionY += lPositionY;
}
public void setScale(float lScale){
mScale = lScale;
}
protected void dispatchDraw(Canvas canvas) {
canvas.save();
// canvas.setMatrix(matrix);
Log.e("Canvas Height ",canvas.getWidth()+" "+canvas.getHeight());
Log.e("Canvas Height ",getWidth() /14 +" "+getHeight()/12 );
Log.e("Canvas Density "," "+canvas.getDensity() );
canvas.translate(mPositionX*mScale, mPositionY*mScale);
canvas.translate(getWidth() / 14,getHeight() / 12);
if (mScale < 0.10)
mScale = 0.1f;
canvas.scale(mScale, mScale);
Log.e("Scale : ",mScale+" ");
super.dispatchDraw(canvas);
canvas.restore();
}
// touch events
private final int NONE = 0;
private final int DRAG = 1;
private final int ZOOM = 2;
private final int CLICK = 3;
// pinch to zoom
private float mOldDist;
private float mNewDist;
private float mScaleFactor = 0.01f;
// position
private float mPreviousX;
private float mPreviousY;
int mode = NONE;
#SuppressWarnings("deprecation")
public OnTouchListener mTouchListener = new OnTouchListener(){
public boolean onTouch(View v, MotionEvent e) {
/*Button button = (Button)v;
Log.e("Button Text : "," "+button.getText().toString());
*/
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: // one touch: drag
mode = CLICK;
break;
case MotionEvent.ACTION_POINTER_2_DOWN: // two touches: zoom
mOldDist = spacing(e);
mode = ZOOM; // zoom
break;
case MotionEvent.ACTION_UP: // no mode
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_2_UP: // no mode
mode = NONE;
break;
case MotionEvent.ACTION_MOVE: // rotation
if (e.getPointerCount() > 1 && mode == ZOOM) {
/*mNewDist = spacing(e) - mOldDist;
mScale += mNewDist*mScaleFactor;
invalidate();
mOldDist = spacing(e); */
} else if (mode == CLICK || mode == DRAG) {
float dx = (x - mPreviousX)/mScale;
float dy = (y - mPreviousY)/mScale;
setMovingPosition(dx, dy);
invalidate();
mode = DRAG;
}
break;
}
mPreviousX = x;
mPreviousY = y;
return true;
}
};
// finds spacing
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y)/4;
}
This is my fragment class where i create floor map :
public class FloorMapFragment extends Fragment implements OnClickListener {
ViewGroup root;
Button exhibitor;
ZoomControls zoom;
int id = 0;
float dx=0,dy=0,x=0,y=0;
InteractiveView mInteractiveView;
int startX, startY;
boolean isClicked = false;
int unit = 100;
int incremental = 100;
int new_X;
int i;
int new_Width = new_X + incremental;
int new_Y;
int new_Hight = new_Y + incremental;
int leftMargin, topMargin;
int orange = Color.parseColor("#C0680F");
int maroon = Color.parseColor("#5F0C0C");
int pink = Color.parseColor("#F45C91");
int moov = Color.parseColor("#6E4689");
int gray = Color.parseColor("#777777");
int red = Color.parseColor("#E31E26");
int blue = Color.parseColor("#3A53A4");
int green = Color.parseColor("#70BD59");
int cyan = Color.parseColor("#70CDDD");
RelativeLayout r;
// View mainView = null;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
PointF oldDistPoint = new PointF();
public static String TAG = "ZOOM";
int mScreenWidth = 0;
int mScreenHeight= 0;
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
enum Direction {
LEFT, RIGHT, UP, DOWN
};
FloorListner listner;
#SuppressWarnings("deprecation")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
root = (ViewGroup) inflater.inflate(R.layout.floor_main, null);
// mainView = (RelativeLayout)root.findViewById(R.id.zoom_layout);
r = (RelativeLayout) root.findViewById(R.id.my_relative_layout);
zoom = (ZoomControls)root. findViewById(R.id.zoomControls1);
mScreenWidth = r.getWidth();
/*MainActivity.activity.getResources()
.getDisplayMetrics().widthPixels;*/
mScreenHeight = r.getHeight();
/*MainActivity.activity.getResources()
.getDisplayMetrics().heightPixels; */
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
layoutParams.height = 75;
layoutParams.width = 57;
// layoutParams.bottomMargin = 100;
// layoutParams.setMargins(0, 0, 0, 100);
// layoutParams.setMargins(-220, 0, 0, 0);
/*ImageView lImageView = new ImageView(MainActivity.activity);
lImageView.setLayoutParams(new RelativeLayout.LayoutParams(-1,-1));
lImageView.setImageResource(R.drawable.transparentimage);;*/
mInteractiveView = new InteractiveView(MainActivity.activity);
// mInteractiveView.setOnClickListener(this);
// mInteractiveView.setOnTouchListener(mTouchListener);
// mInteractiveView.setLayoutParams(new RelativeLayout.LayoutParams(-5,-5 ));
// mInteractiveView.setLayoutParams(layoutParams);
// mInteractiveView.setPosition(-mScreenWidth/2, -mScreenHeight/2);
zoom.setOnZoomInClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = r.getScaleX();
float y = r.getScaleY();
Log.e("Zoon In Listener : ", "X Scale : "+ x );
Log.e("Zoon In Listener : ", "Y Scale : "+ y );
Log.e("Zoon In Width : ", "X Scale : "+ r.getWidth() );
Log.e("Zoon In Height : ", "Y Scale : "+ r.getHeight() );
if (x <= 6.0 && y <= 6.0){
r.setScaleX((float) (x + 0.5));
r.setScaleY((float) (y + 0.5));
}
}
});
zoom.setOnZoomOutClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = r.getScaleX();
float y = r.getScaleY();
Log.e("Zoon Out Listener : ", "X Scale : "+ x );
Log.e("Zoon Out Listener : ", "Y Scale : "+ y );
if (x > 1.0 && y > 1.0){
r.setScaleX((float) (x - 0.5));
r.setScaleY((float) (y - 0.5));
}
}
});
ProgressDialog d = new ProgressDialog(getActivity());
d.setMessage("Loading Map");
d.show();
draw();
d.dismiss();
/*
mInteractiveView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});*/
/*for( i=0; i<((ViewGroup)mInteractiveView).getChildCount(); ++i) {
View nextChild = ((ViewGroup)mInteractiveView).getChildAt(i);
try {
final Button b = (Button) nextChild;
Log.e("Button Text : ", " : "+b.getText().toString());
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int index = ((ViewGroup)b.getParent()).indexOfChild(b);
Log.e("Button get Id : ", ""+v.getTag().toString());
}
});
} catch (Exception e) {
}
}*/
//
// mInteractiveView.addView(lImageView);
// r.setLayoutParams(layoutParams);
r.addView(mInteractiveView);
/* ExhibitorDAO dao = new ExhibitorDAO(getActivity());
workAround(dao, "K19");*/
/* Fragment fragment = new NewsFragment();
FragmentTransaction trans = ;
trans.addToBackStack(null);
trans.replace(R.id.main, fragment);
trans.commit();*/
// r.setOnTouchListener(MyOnTouchListener);
// r.setLayoutParams(layoutParams);
Log.e("Width And Height : ", "Width : "+r.getLayoutParams().width+ " : Height :"+r.getLayoutParams().height);
return root;
}
private OnTouchListener mTouchListener = new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
isClicked = true;
x = event.getX();
y = event.getY();
dx = x-r.getX();
dy = y-r.getY();
break;
case MotionEvent.ACTION_UP:
if (isClicked){
isClicked = false;
/*Button b = (Button) v;
ExhibitorDAO dao = new ExhibitorDAO(getActivity());
workAround(dao,b.getText().toString());*/
}
break;
case MotionEvent.ACTION_POINTER_UP:
isClicked = false;
break;
case MotionEvent.ACTION_POINTER_DOWN:
isClicked = false;
break;
case MotionEvent.ACTION_MOVE:
r.setX(event.getX()-dx);
r.setY(event.getY()-dy);
isClicked = false;
break;
default:
break;
}
return false;
}
};
private void decreaseXBy(int i) {
new_X = new_X - (2 * i);
}
private void reset() {
new_X = 0;
new_Y += incremental;
;
}
private void drawingH(Direction direction, float width) {
if (direction == direction.RIGHT) {// means go to right direction{
new_X += (incremental * width);
} else if (direction == direction.LEFT) { // means go to left
new_X -= (incremental * width);
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Button b = (Button) v;
ExhibitorDAO dao = new ExhibitorDAO(getActivity());
try{
Exhibitor exhibitor = new Exhibitor();
Log.e("Button Text : ", " : "+b.getText());
if (!b.getText().equals("")) {
Logger.log("floor:");
exhibitor = dao.getExhibitorByBooth(b.getText().toString());
ExhibitorApplication ex = new ExhibitorApplication();
ex.exhibitor = exhibitor;
if (exhibitor != null){
listner.Onfloorclick();
ex.fav_exhibitor = 4 ;
Logger.log("floor:"+ex.exhibitor.Exhibitor_FileNumber);
}
else
{
Logger.log("floor:"+ex.exhibitor.Exhibitor_FileNumber);
}
}
{
Logger.log("floor:no data");
}
}
catch(Exception ex)
{
Toast.makeText(getActivity(), "No Information "+ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
public Button drawExhibitor(float width, int height, int color,
String label, String fileNumber, Direction d) {
exhibitor = new Button(getActivity());
// exhibitor.setOnClickListener(this);
// exhibitor.setOnTouchListener(MyOnTouchListener);
if (color == Color.BLUE)
exhibitor.setBackgroundColor(Color.parseColor("#56A5EC"));
if (color == Color.WHITE)
exhibitor.setAlpha(0);
else
exhibitor.setBackgroundColor(color);
// exhibitor.setId(id);
// id++;
exhibitor.setText(label);
exhibitor.setTextSize(8);
// exhibitor.setId(foo);
exhibitor.setTag(label);
exhibitor.setTypeface(Typeface.DEFAULT_BOLD);
exhibitor.setGravity(Gravity.CENTER);
exhibitor.setTextColor(Color.WHITE);
/*exhibitor.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Button get Id : ", ""+exhibitor.getId());
}
});*/
exhibitor.setOnTouchListener(mTouchListener);
leftMargin = new_X;
topMargin = new_Y;
drawingH(d, width);
InteractiveView.LayoutParams params = new InteractiveView.LayoutParams(
(int) (width * incremental), height * incremental);
params.leftMargin = leftMargin;
params.topMargin = topMargin;
mInteractiveView.addView(exhibitor, params);
params = null;
if (color != Color.WHITE) {
drawingHSpace();
}
return exhibitor;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FloorListner) {
listner = (FloorListner) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet MyListFragment.OnItemSelectedListener");
}
}
private void drawingHSpace() {
new_X += 2;
}
private void drawingHSpace(float t) {
new_X = (int) (new_X + (2 * t));
}
private void drawingVSpace() {
new_Y += 2;
}
private void removeDrawingVSpace() {
new_Y -= 2;
}
private void decreaseXBy(float i) {
new_X = (int) (new_X - (2 * i));
}
private void drawLabel(float width, int height, int color, int drawable, Direction d) {
// TODO Auto-generated method stub
TextView image = new TextView(getActivity());
//image.setText(label);
image.setBackgroundResource(drawable);
image.setGravity(Gravity.CENTER);
image.setTextSize(20);
image.setTypeface(Typeface.DEFAULT_BOLD);
//image.setTextColor(color);
// image.setOnTouchListener(MyOnTouchListener);
leftMargin = new_X;
topMargin = new_Y;
drawingH(d,width);
InteractiveView.LayoutParams params = new InteractiveView.LayoutParams(
(int)(width * incremental), height * incremental);
params.leftMargin = leftMargin;
params.topMargin = topMargin;
mInteractiveView.addView(image, params);
}
private void drawLabel(float width, int height, int color, String label, Direction d) {
// TODO Auto-generated method stub
TextView image = new TextView(getActivity());
image.setText(label);
image.setGravity(Gravity.CENTER);
image.setTextSize(20);
image.setTypeface(Typeface.DEFAULT_BOLD);
image.setTextColor(color);
// image.setOnTouchListener(mTouchListener);
leftMargin = new_X;
topMargin = new_Y;
drawingH(d,width);
InteractiveView.LayoutParams params = new InteractiveView.LayoutParams(
(int)(width * incremental), height * incremental);
params.leftMargin = leftMargin;
params.topMargin = topMargin;
mInteractiveView.addView(image, params);
}
private void draw() {
drawExhibitor(28.5F, 3, Color.WHITE, "", "", Direction.RIGHT);
drawLabel(2, 3, blue, R.drawable.al_mamzar, Direction.RIGHT);
reset();
reset();
drawExhibitor(16.5F, 1, Color.WHITE, "", "", Direction.RIGHT);
drawLabel(2, 1, blue, R.drawable.business_center, Direction.RIGHT);
drawExhibitor(4.65F, 1, Color.WHITE, "", "", Direction.RIGHT);
drawLabel(1, 1, blue, R.drawable.bath_f, Direction.RIGHT);
drawExhibitor(14F, 1, Color.WHITE, "", "", Direction.RIGHT);
drawLabel(1, 1, blue, R.drawable.bath_m, Direction.RIGHT);
//reset();
reset();
drawingVSpace();
drawingVSpace();
}
}
Finally i am adding the Interactive View to a relative layout.
As you will find it in the documentation that each view can have an id (using setId (int id) or from xml android:id ) or tag(using setTag (int key)) associated with it and later on you can get that id or tag via getId() or getTag().
Now before you actually retrieve any id for a view at first you have to set an id for that specific view either via programmatically or via xml.
If you don't specify any id for a view and you are trying get that view's id you will get NO_ID.
As per documentation: getId () returns this view's identifier.A positive integer used to identify the view or NO_ID if the view has no ID.
Now to address your problem, before you add a button to your viewgroup assign a unique id to that button.
To illustrate more here is an example:
public class MainActivity extends Activity {
private LinearLayout mRootLayout;
private OnClickListener mOnClickListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Log.e("mButton "," onClick");
Toast.makeText(MainActivity.this, " "+arg0.getId(), Toast.LENGTH_LONG).show();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRootLayout = (LinearLayout)findViewById(R.id.mRootLayout);
for(int i = 0;i<10;i++){
Button mButton = new Button(this);
mButton.setText("Button "+i);
mButton.setId(i);
if(i<9){
mButton.setOnClickListener(mOnClickListener);
}
mRootLayout.addView(mButton);
}
Button testFindButton = (Button)mRootLayout.findViewById(9);
testFindButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.e("testFindButton "," onClick");
Toast.makeText(MainActivity.this, " testFindButton "+v.getId(), Toast.LENGTH_LONG).show();
}
});
}
}
You can use the setTag method for each button, to set an id. Then in the onClick method, retrieve that value, and execute the code related to that button.
Some code (not tested):
private OnClickListener listener = new OnClickListener()
{
#Override
public void onClick(View v)
{
int id = (Integer)v.getTag();
switch (id)
{
case 1: break;
....
}
}
});
for (int i=0 ; i<N ; i++)
{
yourbutton.setTag(Integer.valueOf(i));
yourbutton.setOnClickListener(listener);
}