Hello I've set up an onTouchListener within my application for an ImageView, my aim was to have an ImageView that the user would be able to drag around and place where ever they want within the app. I've written some code using sample code found on the web for an onTouchListener that I thought would work but I'm having some problems with it, rather than allowing me to drag the image around, the image resizes and gets bigger or smaller when you drag your finger over it.
Does anyone have any ideas why? Here's my code:
ImageView t1img;
t1img = (ImageView) findViewById(R.id.imgT1);
windowWidth = getWindowManager().getDefaultDisplay().getWidth();
windowHeight = getWindowManager().getDefaultDisplay().getHeight();
t1img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
layoutParams = (LayoutParams) t1img.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int xCoord = (int) event.getRawX();
int yCoord = (int) event.getRawY();
if (xCoord > windowWidth) {
xCoord = windowWidth;
}
if (yCoord > windowHeight) {
yCoord = windowHeight;
}
layoutParams.leftMargin = xCoord - 25;
layoutParams.topMargin = yCoord - 75;
t1img.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
If you need to support gingerbread you can take a look at my example here
https://github.com/NAYOSO/android-dragview
if you only need to support jelly bean above you can use the Drag and Drop from android library you can see it from this article
http://developer.android.com/guide/topics/ui/drag-drop.html
For some explanation about the Drag and Drop view
at first you need t create the touch listener and then call startDrag to start draging. As simple as that.
private final class dragTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
return true;
} else {
return false;
}
}
}
To monitor the target of dropping place you can use onDragListener
private class dropListener implements OnDragListener {
View draggedView;
CustomTextView dropped;
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
draggedView = (View) event.getLocalState();
dropped = (CustomTextView) draggedView;
draggedView.setVisibility(View.INVISIBLE);
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
CustomTextView dropTarget = (CustomTextView) v;
dropTarget.setText(dropped.getText().toString());
break;
case DragEvent.ACTION_DRAG_ENDED:
break;
default:
break;
}
return true;
}
}
As you can see from my code there is many event but the main one is when the view is start being dragged, dropped and ended.
Don't forget to set the listener to view
tvDrag.setOnTouchListener(new dragTouchListener());
tvDrop.setOnDragListener(new dropListener())
I hope my explanation is clear enough!
If you have further question I will try to answer it tonight or tomorrow :)
I have done an example using thread. You can try this example for a smooth drag and drop bitmap image using touch Event listener
Download Demo or Code
I have created three classes
MainActivity.Java
Instatiates our BallView class and Adds setContentView to the BallView Class as shown below
package com.whatsonline.dragobject;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
public class MainActivity extends Activity {
private Bitmap bitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int w=getWindowManager().getDefaultDisplay().getWidth()-25;
int h=getWindowManager().getDefaultDisplay().getHeight()-25;
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.p1);
BallView ballView=new BallView(this, bitmap, w, h);
setContentView(ballView);
}
}
Our BallView extends the surfaceView class and implements the surface holder as shown below. Also, contains the draw method to draw the canvas and touchEvent listener to get the position of the Bitmap image to be moved and move along the drawn image Bitmap path.
package com.whatsonline.dragobject;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BallView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap bitmap;
private MyThread thread;
private int x=25,y=25;
int width,height;
public BallView(Context context, Bitmap bmp, int w,int h) {
super(context);
width=w;
height=h;
bitmap=bmp;
thread=new MyThread(getHolder(),this);
getHolder().addCallback(this);
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// bitmap = BitmapFactory.decodeResource(getResources(), bmp);
canvas.drawColor(Color.BLUE);//To make background
canvas.drawBitmap(bitmap, x-(bitmap.getWidth()/2),y-(bitmap.getHeight()/2), null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x=(int)event.getX();
y=(int)event.getY();
if(x<25)
x=25;
if(x> width)
x=width;
if(y <25)
y=25;
if(y > height)
y=height;
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.startrun(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
thread.startrun(false);
thread.stop();
}
}
and finally
MainThread class
call the onDraw method if it is running as shown below
package com.whatsonline.dragobject;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MyThread extends Thread {
private SurfaceHolder msurfaceHolder;
private BallView mballView;
private boolean mrun =false;
public MyThread(SurfaceHolder holder, BallView ballView) {
msurfaceHolder = holder;
mballView=ballView;
}
public void startrun(boolean run) {
mrun=run;
}
#Override
public void run() {
super.run();
Canvas canvas;
while (mrun) {
canvas=null;
try {
canvas = msurfaceHolder.lockCanvas(null);
synchronized (msurfaceHolder) {
mballView.onDraw(canvas);
}
} finally {
if (canvas != null) {
msurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Download code here
Related
So I have followed this tutorial and the code works perfectly. However I have some trouble understanding how OnTouchListener and OnTouch work together. I have spent a long time trauling this forum, websites and documentation to understand but still, I do not.
In this code, a OnTouchListener is set for ourSurfaceView, and then the onTouch is called for the activity?!
Can someone please explain the relationship of OnTouchListener and OnTouch across different activities and views. Many Thanks!
package com.games.michael.waterproofme;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class MainActivity extends Activity implements OnTouchListener{
MySurface ourSurfaceView;
float x,y,sX, sY, fX, fY;
Bitmap test, plus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ourSurfaceView = new MySurface(this);
ourSurfaceView.setOnTouchListener(this);
x = 0;
y = 0;
sX = 0;
sY = 0;
fX = 0;
fY = 0;
test = BitmapFactory.decodeResource(getResources(), R.drawable.sportsball);//draw ball
plus = BitmapFactory.decodeResource(getResources(), R.drawable.plus);
setContentView(ourSurfaceView);
}
#Override
protected void onPause() {
super.onPause();
ourSurfaceView.pause();
}
#Override
protected void onResume() {
super.onResume();
ourSurfaceView.resume();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
x = event.getX();
y = event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
sX = event.getX();
sY = event.getY();
break;
case MotionEvent.ACTION_UP:
fX = event.getX();
fY = event.getY();
break;
}
return true;//false = finished dont loop through. true = loop through
}
public class MySurface extends SurfaceView implements Runnable{
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = false;
public MySurface(Context context){
super(context);
ourHolder = getHolder();
ourThread = new Thread(this);
ourThread.start();
}
public void pause(){
isRunning = false;
while(true){
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume(){
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
public void run() {
while(isRunning){
if(!ourHolder.getSurface().isValid()) {/
continue;}
Canvas canvas = ourHolder.lockCanvas();
canvas.drawRGB(02, 02, 150);
if (x != 0 && y != 0){
canvas.drawBitmap(test, x-(test.getWidth()/2), y-(test.getHeight()/2), null);//bitmap, left, top, paint
}
if (sX != 0 && sY != 0){
canvas.drawBitmap(plus, sX-(plus.getWidth()/2), sY-(plus.getHeight()/2), null);//bitmap, left, top, paint
}
if (fX != 0 && fY != 0){
canvas.drawBitmap(plus, fX-(plus.getWidth()/2), fY-(plus.getHeight()/2), null);//bitmap, left, top, paint
}
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
}
OnTouchListener is interface - class that implements it must override its methods. For android.view.View.OnTouchListener this is one method: boolean onTouch(View v, MotionEvent event)
When touch event occurs in your SurfaceView there is check if onTouchListener is set and if so its onTouch method is called
Can someone please explain the relationship of OnTouchListener and OnTouch across different activities and views.
Touch events on views are invoked if you register any callback to them. SurfaceView extends the View class.
ourSurfaceView.setOnTouchListener(this);
setContentView(ourSurfaceView);
So you just set the ourSurfaceView to the activity as their content view and registered the View.OnTouchListener. That means the abstract method onTouch is invoked on the ourSurfaceView instance and not the activity.
In this code, a OnTouchListener is set for ourSurfaceView, and then the onTouch is called for the activity?!
No, it delegates any touch event from ourSurfaceView instance as their content view to your MainActivity class because you registered the View.OnTouchListener
Just a simple Java example:
public class Main {
public static void main(String[] args){
SurfaceClass surfaceClass = new SurfaceClass();
ActivityClass activityClass = new ActivityClass();
surfaceClass.setOnFartListener(activityClass);
//Touch event :D
surfaceClass.fart();
}
public static class ActivityClass implements SurfaceClass.OnFartListener{
#Override
public void onFart(String kindOfFart) {
System.out.println(kindOfFart);
}
}
public static class SurfaceClass{
private SurfaceClass.OnFartListener onFartListener;
public void fart(){
if(onFartListener != null){
onFartListener.onFart("Huge One!!");
}
}
public void setOnFartListener(SurfaceClass.OnFartListener onFartListener){
this.onFartListener = onFartListener;
}
public interface OnFartListener{
void onFart(String kindOfFart);
}
}}
See touch event below :D
javac Main.java && java Main
I am new to Android so I am making a coloring book app just to get myself acquainted to android programming. I have looked up my problem extensively and implemented the solutions but still no progress.
I have an activity 'ColoringActivity' which calls a class 'PaintView' which extends surfaceview. I am trying to update the canvas in a separate thread. I also have a button in the layout which takes the user to another activity for picking colors. The problem is that when the user returns after choosing the color, the canvas becomes empty and I cant draw on the canvas anymore. I think i somehow loose the thread in between activities and although the thread is running in the background, I have no access to it.
I read on this forum that I must implement pause() and resume() methods in the thread class and basically kill the thread when I go to another activity and restart it when I return. Also I read I have to override onPause() and onResume() method in activity class and construct the surfaceview in onResume() so that it is constructed every time user returns to this activity.
I am sorry if it doesnt make much sense because I am lost as well.
My 'ColoringActivity':
package com.ali.coloryourself;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class ColoringActivity extends Activity {
private static final int COLOR_REQUEST_CODE = 100;
public static String file;
public static Bitmap bitmap;
BitmapFactory.Options options;
PaintView paintView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
Intent intent = getIntent();
file = intent.getStringExtra("fileName");
// paintView = (PaintView) findViewById(R.id.drawingSurface);
}
#Override
protected void onResume() {
paintView = (PaintView) findViewById(R.id.drawingSurface);
paintView.getThread().resume();
super.onResume();
}
#Override
protected void onPause() {
paintView.getThread().pause();
super.onPause();
}
public void pickColor(View v) {
paintView.getThread().pause();
Intent colorIntent = new Intent(this, ColorPickerActivity.class);
startActivityForResult(colorIntent, COLOR_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_CANCELED) {
if (requestCode == COLOR_REQUEST_CODE) {
int color = data.getIntExtra("Color", -1);
// paintView.getPaint().setColor(color);
}
}
}
}
My 'PaintView' class:
package com.ali.coloryourself;
import android.R.color;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class PaintView extends SurfaceView implements SurfaceHolder.Callback {
private Paint paint = new Paint();
private Canvas canvas;
private PaintThread thread;
private Path path = new Path();
private Bitmap bitmap;
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(3);
setThread(new PaintThread(holder));
}
class PaintThread extends Thread {
private boolean mRun;
private SurfaceHolder mSurfaceHolder;
private int mMode;
public static final int STATE_PAUSE = 2;
public static final int STATE_RUNNING = 4;
public PaintThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
}
#Override
public void run() {
while (mRun) {
try {
canvas = mSurfaceHolder.lockCanvas(null);
if (mMode == STATE_RUNNING) {
if (bitmap == null) {
bitmap = Bitmap.createBitmap(1, 1,
Bitmap.Config.ARGB_8888);
}
}
doDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private void doDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
public void setRunning(boolean b) {
mRun = b;
}
public void pause() {
if (mMode == STATE_RUNNING)
setState(STATE_PAUSE);
}
public void resume() {
setState(STATE_RUNNING);
}
public void setState(int mode) {
synchronized (mSurfaceHolder) {
mMode = mode;
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Log.d("Touch", "I am touching");
float eventX = event.getX();
float eventY = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
return true;
}
public void surfaceCreated(SurfaceHolder holder) {
if (getThread().getState() == Thread.State.NEW) {
getThread().setRunning(true);
getThread().start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
getThread().setRunning(false);
getThread().resume();
while (retry) {
try {
getThread().join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public Paint getPaint() {
return paint;
}
public void setPaint(int color) {
this.paint.setColor(color);
}
public PaintThread getThread() {
return thread;
}
public void setThread(PaintThread thread) {
this.thread = thread;
}
}
my 'activity_draw.xml'
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:onClick="pickColor"
android:text="Pick Color" />
<com.ali.coloryourself.PaintView
android:id="#+id/drawingSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/button1"
android:layout_marginTop="10dp"/>
</RelativeLayout>
I know I am missing some very basic thread concept. I need to allow the user to pick color and return and be able to continue drawing. I will be extremely grateful for your help.
I think I have found an answer although I am not sure if it is a good programming practice. I found out that my surface view and thread were created once 'ColoringActivity' was created and destroyed every time 'ColoringActivity' went to background. But once 'ColoringActivity' was restarted and resumed, surface view and thread were not recreated. So i moved the following line
setContentView(R.layout.activity_draw);
to onResume() method and now I can draw on the canvas every time. Now I just need to save the canvas and re load it when the activity comes back on to start off the coloring where the user left it.
This is my updated code. It doesn't detect movement at all now. Maybe I shouldn't be making each Image an instance? Basically I want to user to be able to swipe through all the images to make them dissapear.
Thanks for all the help.
package com.picomputing.mythirdapplication;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
/**
* Created by Paul on 8/13/13.
*/
public class Pin extends ImageView implements View.OnTouchListener {
boolean isPinDown;
public Pin(Context context) {
super(context);
this.isPinDown = false;
}
public Pin(Context context, AttributeSet attrs) {
super(context, attrs);
this.isPinDown = false;
}
public Pin(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.isPinDown = false;
}
public boolean pinDown() {
return this.isPinDown;
}
public void setPinDown() {
this.isPinDown = true;
}
public void setPinUp() {
this.isPinDown = false;
}
public void togglePin() {
if (isPinDown == false)
{
isPinDown = true;
this.setImageResource(Color.TRANSPARENT);
}
else
{
isPinDown = false;
this.setImageResource(R.drawable.pin);
}
}
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
int x = (int) event.getX(); //--relative to mLayout--
int y = (int) event.getY(); //--relative to mLayout--
Rect r = new Rect();
view.getHitRect(r);
if(r.contains(x,y) && view instanceof ImageView){
togglePin();
}
}
return true;
}
}
You need to listen and consume ACTION_MOVE events, for the parent view of whatever you are trying to change.
Here's an example with a couple of ImageViews in a LinerLayout as a parent:
public class test extends Activity {
LinearLayout mLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLayout = new LinearLayout(this);
mLayout.setOrientation(LinearLayout.VERTICAL);
for(int i = 0 ; i < 5; i++){
ImageView iv = new ImageView(this);
iv.setImageResource(android.R.drawable.ic_dialog_info);
mLayout.addView(iv);
}
setContentView(mLayout);
mLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
int x = (int) event.getX(); //--relative to mLayout--
int y = (int) event.getY(); //--relative to mLayout--
Rect r = new Rect();
for(int i = 0 ; i < mLayout.getChildCount(); i++){
View v = mLayout.getChildAt(i);
v.getHitRect(r);
if(r.contains(x,y) && v instanceof ImageView){
((ImageView) v).setImageResource(android.R.drawable.ic_dialog_alert);
}
}
}
return true; //-- this means that view is interested in more events of all kinds--
}
});
}
}
I hope I didn't misunderstand your question
but if what you want to do is to prevent multitoch on the image you can add this attribute
android:splitMotionEvents="false"
in the xml in the parent view of the imageview. for example :
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:splitMotionEvents="false"
>
// YOUR IMAGE VIEW HERE
</LinearLayout>
if you have any question feel free to ask in the comment :)
there are mainly three events on OnTouch action_down,Action_move and Action_up. do your coding on action down event i.e when user has touched your view. see the example here:
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction()==MotionEvent.ACTION_DOWN) {
//write your code here
}
else {
if (arg1.getAction()==MotionEvent.ACTION_MOVE){
do things
}
else {
if (arg1.getAction()==MotionEvent.ACTION_UP){
do things
}
}
}
I'm developing a 2d Game using Canvas/Surfaceview and have a problem with scrolling my background image.
Check out the game - http://youtu.be/4Gi5rRqzZ3M
In the NinJump game, the character Ninja is just jumping in X coordinates and Background image is scrolling at a very high speed, making Ninja look like it is actually running.
I have created the basic setup, created the Ninja, added jump functionality, added background. Now I want to repeat the same background over and over again. How can I accomplish that?
Below are my source files - Main Activity Class
package com.abc.apps;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class LadderActivity extends Activity {
private static final String TAG = LadderActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// requesting to turn the title OFF
requestWindowFeature(Window.FEATURE_NO_TITLE);
// making it full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// set our MainGamePanel as the View
setContentView(new MainGameBoard(this));
Log.d(TAG, "View added");
}
#Override
protected void onDestroy() {
Log.d(TAG, "Destroying...");
super.onDestroy();
}
#Override
protected void onStop() {
Log.d(TAG, "Stopping...");
super.onStop();
}
}
Game Board extends SurfaceView
package com.abc.apps;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainGameBoard extends SurfaceView implements SurfaceHolder.Callback{
private MainGameLoop thread;
private Monkey monkey;
private static final String TAG = MainGameLoop.class.getSimpleName();
int currentX, currentY;
public MainGameBoard(Context context) {
super(context);
// TODO Auto-generated constructor stub
// adding the callback (this) to the surface holder to intercept events
//This line sets the current class (MainGamePanel) as the handler for the events happening on the actual surface
getHolder().addCallback(this);
// create monkey and load bitmap INITIALIZE AT LEFT
monkey = new Monkey(BitmapFactory.decodeResource(getResources(), R.drawable.actor),60, 340);
// create the game loop thread
thread = new MainGameLoop(getHolder(), this);
// make the GamePanel focusable so it can handle events.
setFocusable(true);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//For jumping Left
if (event.getX() < (getWidth()/2 - 32)) {
// Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
//Log.d(TAG, "Jump Left");
// Sleep so that the main thread doesn't get flooded with UI events.
try {
Thread.sleep(32);
monkey.setX((getWidth()/2 - 60));
monkey.setY(monkey.getY()-70);
} catch (InterruptedException e) {
// No big deal if this sleep is interrupted.
}
}
//For Jumping Right
if (event.getX() > (getWidth()/2 + 32)) {
//Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
//Log.d(TAG, "Jump Right");
// Sleep so that the main thread doesn't get flooded with UI events.
try {
Thread.sleep(32);
monkey.setX((getWidth()/2 + 60));
monkey.setY(monkey.getY()-70);
} catch (InterruptedException e) {
// No big deal if this sleep is interrupted.
}
}
/* //Middle Portion
if (event.getX() > (getWidth()/2 - 32) && event.getX() < (getWidth()/2 +32)) {
//thread.setRunning(false);
//((Activity)getContext()).finish();
}*/
}
return true;
}
public void render(Canvas canvas) {
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, 0,null);
monkey.draw(canvas);
}
/* #Override
protected void onDraw(Canvas canvas){
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_scene), 0, 0,null);
monkey.draw(canvas);
}*/
}
Main Game Loop
package com.abc.apps;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainGameLoop extends Thread {
private SurfaceHolder surfaceHolder;
private MainGameBoard gameBoard;
private Monkey monkey;
private static final String TAG = MainGameLoop.class.getSimpleName();
// flag to hold game state
private boolean running = true;
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing on the surface
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// update game state
// render state to the screen
// draws the canvas on the panel
gameBoard.render(canvas);
}
}
finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
public MainGameLoop(SurfaceHolder surfaceHolder, MainGameBoard gameBoard) {
super();
this.surfaceHolder = surfaceHolder;
this.gameBoard = gameBoard;
}
}//MainThread
Monkey Class
package com.abc.apps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
public class Monkey {
private Bitmap bitmap; // the actual bitmap
private int x; // the X coordinate
private int y; // the Y coordinate
private boolean touched; // if monkey is touched
public Monkey(Bitmap bitmap, int x, int y) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isTouched() {
return touched;
}
public void setTouched(boolean touched) {
this.touched = touched;
}
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y, paint);
}
}
It looks like you are drawing your background in your MainGameBoard class in the render method.
public void render(Canvas canvas) {
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, 0,null);
monkey.draw(canvas);
}
You should just need 2 drawBitmap calls instead of 1 there.
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, y_offset1,null);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.monkey_sc), 0, y_offset2,null);
I'm making an assumption that each background image has the same height or greater than the screen height; if it is less than the screen height you would need more than 2 instances.
Then you start 1 image at y_offset1 = 0 and the other at y_offset2 = -image_height.
Each draw you would increase y_offset1 and y_offset2 by the same amount. You would then need to do a check for both offsets to see if either has an amount greater than the screen height. If it does then the y_offset that is now "below screen" should be reset to the other y_offset minus the image_height. This will create a scroll image that loops indefinitely.
When using this type of technique it is important to think about your image edges; the image should be designed such that they tile seamlessly, otherwise at the looping point there is a noticeable visual artifact along the edge.
I have to achieve that the Touch Scroll on the ViewFlipper. For Example. I have two Images. At First, ViewFlipper shows an First Image. Now I Flung the view from right to left. The First Image view Slide out left and the Second Slide in from Left. I can achieve it By this Post. But I want to Scroll the image. That is, on the Action_Move Event I want to do Touch Scroll. For Example, when I move the touch from right to left it will flung how much the touch moves. on that time the output should show both images partly.
How to do that? What I have to measure the Screen levels(height & width). Example codes are more helpful.
If you need to detect scroll on only viewflipper which is not occupying entire screen, then try the below
gestureDetector = new GestureDetector(new MyGestureDetector());
viewFlipper.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return false;
}
return true;
}
});
and MyGestureDetector will be same as in http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/
package com.appaapps.flipper;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ViewFlipper;
//------------------------------------------------------------------------------
// Flipper - Philip R Brenan at gmail.com
//------------------------------------------------------------------------------
public class FlipperActivity extends Activity {
ViewFlipper f;
DrawView a, b, c;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
f = new ViewFlipper(this);
a = new DrawView(this, "aaaaa");
b = new DrawView(this, "BBBBB");
c = new DrawView(this, "ccccc");
f.addView(a);
f.addView(b);
f.addView(c);
setContentView(f);
}
//------------------------------------------------------------------------------
// Draw
//------------------------------------------------------------------------------
class DrawView extends View implements View.OnTouchListener {
final String text;
DrawView(Context Context, String Text) {
super(Context);
text = Text;
setOnTouchListener(this);
}
public void onDraw(Canvas Canvas) {
super.onDraw(Canvas);
Paint p = new Paint();
p.setColor(0xffffffff);
p.setTextSize(20);
Canvas.drawText(text, 0, 20, p);
}
public boolean onTouch(View v, MotionEvent event) {
final int a = event.getAction();
if (a == MotionEvent.ACTION_DOWN) {
final int i = f.getDisplayedChild(), n = f.getChildCount();
f.setDisplayedChild((i + 1) % n);
}
return true;
}
}
}