Related
I'm programming a pacman, the game is drawed in a SurfaceView, but I have problem to pause it and getting the atributes while it's running (no when I set them)
For example, I set a Semaphore that should be referenced in the Activity and in the Game view, and it is set it correct, but when the thread of the game view is running, and try to release the semaphore it indicates a NullPointerException.
On the other hand, when I try to pause the game, the game used to keep running in the background, and now when I resume it don't run
I'm sure the problem is with the references in memory, when I set and atribute as static i can access from both (view and surfaceview are the same object). I don't know why this happen.
Brief resume: An AppCompatActivity (which is PlayActivity) has a SurfaView (which is GameView), and this SurfaceView has the GameManager(which has all the things of the pacman in a moment). The references when the AppCompatActivity try to get something of the SurfaceView (for example the gameManager) are lost in execution.
Here the code
PlayActivity
public class PlayActivity extends AppCompatActivity {
private TextView playerNickname;
private TextView scoreTv;
private TextView maxScore;
private SurfaceView gameSurfaceView;
private GameView gameView;
private static Semaphore CHANGE_LIFES_MUTEX=new Semaphore(0,true);
private static Semaphore CHANGE_SCORE_MUTEX=new Semaphore(0,true);
private static Semaphore CHANGE_DIRECTION_MUTEX=new Semaphore(0,true);
private Thread changeScoreThread, changeDirectionThread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Modified code
setContentView(R.layout.activity_game);
//we get text view that we will use
playerNickname=(TextView) this.findViewById(R.id.tv_player);
scoreTv=(TextView) this.findViewById(R.id.tv_current_score);
maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
//set text view initial values
playerNickname.setText(getIntent().getExtras().getString("playerNickname"));
scoreTv.setText("0");
maxScore.setText("To modify");
this.gameView=new GameView(gameSurfaceView.getContext());
this.gameView.setSemaphores(CHANGE_SCORE_MUTEX,CHANGE_DIRECTION_MUTEX);
this.gameSurfaceView.getHolder().addCallback(this.gameView);
}
protected void onResume(){
super.onResume();
this.gameView.resume();
this.initChangerThreads();
}
public void updateScoreTv(int score){
this.scoreTv.setText(""+score);
}
protected void onPause(){
super.onPause();
this.gameView.pause();
//in order to stop the threads
CHANGE_SCORE_MUTEX.release();
CHANGE_DIRECTION_MUTEX.release();
}
public void onLose(int score){
//We try to save the score, if there is a previous register we write only if this score
//is better that the one before
DBManager manager;
long raw;
Score scoreToSave;
manager=new DBManager(this);
scoreToSave=new Score(this.playerNickname.toString(), score);
if(manager.saveScore(scoreToSave)==-1){
//if i couldn't save the score
if(manager.updateScore(scoreToSave)!=-1){
//if my new score is better than the one previous
}else{
//if my new score is worse or equal than the one previous
}
}
}
private void initChangerThreads() {
this.changeScoreThread = new Thread(new Runnable() {
public void run() {
while (gameView.isDrawing()) {
//Log.i("Score ",""+gameManager.getScore());
try {
CHANGE_SCORE_MUTEX.acquire();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateScoreTv(gameView.getGameManager().getScore());
}
});
}catch (Exception e){}
}
Log.i("Score Thread","ended");
}
});
this.changeScoreThread.start();
}
}
GameView
public class GameView extends SurfaceView implements Runnable, SurfaceHolder.Callback, GestureDetector.OnGestureListener {
private static final float SWIPE_THRESHOLD = 2;
private static final float SWIPE_VELOCITY = 2;
private static boolean CAN_DRAW = false;
private boolean GHOST_INICIALIZED=false;
private GestureDetector gestureDetector;
private GameManager gameManager;
private Thread thread; //game thread
private SurfaceHolder holder;
private int blockSize; // Ancho de la pantalla, ancho del bloque
private static int movementFluencyLevel=8; //this movement should be a multiple of the blocksize and multiple of 4, if note the pacman will pass walls
private int totalFrame = 4; // Cantidad total de animation frames por direccion
private int currentArrowFrame = 0; // animation frame de arrow actual
private long frameTicker; // tiempo desde que el ultimo frame fue dibujado
//----------------------------------------------------------------------------------------------
//Constructors
public GameView(Context context) {
super(context);
this.constructorHelper(context);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
this.constructorHelper(context);
}
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.constructorHelper(context);
}
private void constructorHelper(Context context) {
this.gestureDetector = new GestureDetector(this);
setFocusable(true);
this.holder = getHolder();
this.holder.addCallback(this);
this.frameTicker = (long) (1000.0f / totalFrame);
this.gameManager=new GameManager();
int screenWidth=getResources().getDisplayMetrics().widthPixels;
this.blockSize = ((((screenWidth/this.gameManager.getGameMap().getMapWidth())/movementFluencyLevel)*movementFluencyLevel)/4)*4;
this.holder.setFixedSize(blockSize*this.gameManager.getGameMap().getMapWidth(),blockSize*this.gameManager.getGameMap().getMapHeight());
this.gameManager.getGameMap().loadBonusBitmaps(this.getBlockSize(),this.getResources(),this.getContext().getPackageName());
this.gameManager.setPacman(new Pacman("pacman","",this.movementFluencyLevel,this.gameManager.getGameMap().getPacmanSpawnPosition(),this.blockSize,this.getResources(),this.getContext().getPackageName()));
Ghost.loadCommonBitmaps(this.blockSize,this.getResources(),this.getContext().getPackageName());
}
//----------------------------------------------------------------------------------------------
//Getters and setters
public int getBlockSize() {
return blockSize;
}
public GameManager getGameManager() {
return gameManager;
}
public boolean isDrawing(){
return CAN_DRAW;
}
//----------------------------------------------------------------------------------------------
private synchronized void initGhost(){
if(!GHOST_INICIALIZED){
GHOST_INICIALIZED=true;
this.gameManager.initGhosts(this.blockSize,this.getResources(),this.getContext().getPackageName(),movementFluencyLevel);
}
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void run() {
long gameTime;
Canvas canvas;
while (!holder.getSurface().isValid()) {
}
this.initGhost();
this.setFocusable(true);
while (CAN_DRAW) {
gameTime=System.currentTimeMillis();
if(gameTime > frameTicker + (totalFrame * 15)){
canvas = holder.lockCanvas();
if(canvas!=null){
if(this.updateFrame(gameTime,canvas)){
try {
Thread.sleep(3000);
}catch (Exception e){}
}
holder.unlockCanvasAndPost(canvas);
if(this.gameManager.checkWinLevel()){
CAN_DRAW=false;
this.gameManager.cancelThreads();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
//animation
Log.i("Game","You win");
}else if(!this.gameManager.getPacman().hasLifes()){
//we lost
CAN_DRAW=false;
this.gameManager.cancelThreads();
//animation
Log.i("Game","You lose");
}
}
}
}
}
// Method to capture touchEvents
#Override
public boolean onTouchEvent(MotionEvent event) {
//To swipe
//https://www.youtube.com/watch?v=32rSs4tE-mc
this.gestureDetector.onTouchEvent(event);
super.onTouchEvent(event);
return true;
}
//Chequea si se deberia actualizar el frame actual basado en el
// tiempo que a transcurrido asi la animacion
//no se ve muy rapida y mala
#RequiresApi(api = Build.VERSION_CODES.N)
private boolean updateFrame(long gameTime, Canvas canvas) {
Pacman pacman;
Ghost[] ghosts;
boolean pacmanIsDeath;
pacman=this.gameManager.getPacman();
ghosts=this.gameManager.getGhosts();
// Si el tiempo suficiente a transcurrido, pasar al siguiente frame
frameTicker = gameTime;
canvas.drawColor(Color.BLACK);
this.gameManager.getGameMap().draw(canvas, Color.BLUE,this.blockSize,this.gameManager.getLevel());
this.gameManager.moveGhosts(canvas,this.blockSize);
pacmanIsDeath=pacman.move(this.gameManager,canvas);
if(!pacmanIsDeath){
// incrementar el frame
pacman.changeFrame();
for(int i=0; i<ghosts.length;i++){
ghosts[i].changeFrame();
}
currentArrowFrame++;
currentArrowFrame%=7;
}else{
pacman.setNextDirection(' ');
for(int i=0; i<ghosts.length;i++){
ghosts[i].respawn();
}
}
return pacmanIsDeath;
}
public int getScore(){
return this.getGameManager().getScore();
}
public void setSemaphores(Semaphore changeScoreSemaphore, Semaphore changeDirectionSemaphore){
this.gameManager.setChangeScoreSemaphore(changeScoreSemaphore);
this.gameManager.getPacman().setChangeDirectionSemaphore(changeDirectionSemaphore);
Log.i("Semaphore", "setted");
}
//----------------------------------------------------------------------------------------------
//Callback methods
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void surfaceCreated(SurfaceHolder holder) {
CAN_DRAW = true;
this.thread= new Thread(this);
this.thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("Surface","destroyed");
}
//----------------------------------------------------------------------------------------------
public void resume() {
CAN_DRAW = true;
thread = new Thread(this);
thread.start();
}
public void pause() {
CAN_DRAW = false;
while (true) {
try {
thread.join();
} catch (InterruptedException e) {
// retry
}
break;
}
this.thread=null;
}
#Override
public boolean onDown(MotionEvent e) {
return false;
}
#Override
public void onShowPress(MotionEvent e) {
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
#Override
public void onLongPress(MotionEvent e) {
}
#Override
public boolean onFling(MotionEvent downEvent, MotionEvent moveEvent, float velocityX, float velocityY) {
//To swipe
//https://www.youtube.com/watch?v=32rSs4tE-mc
boolean result;
float diffX, diffY;
Pacman pacman;
Log.i("Fling", "detected");
result=false;
diffX = moveEvent.getX() - downEvent.getX();
diffY = moveEvent.getY() - downEvent.getY();
pacman=this.gameManager.getPacman();
if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY){
if (Math.abs(diffX) > Math.abs(diffY)) {
if (diffX > 0) {
//right
pacman.setNextDirection('r');
} else {
//left
pacman.setNextDirection('l');
}
}else{
if (diffY > 0) {
//down
pacman.setNextDirection('d');
} else {
//up
pacman.setNextDirection('u');
}
}
result=true;
}
return result;
}
}
GameManager
public class GameManager {
private static final int TOTAL_LEVELS=256;
private static int SCORE=0;
private GameMap gameMap;
private int level,bonusResetTime;//,score;
private CountDownScareGhosts scareCountDown;
private Pacman pacman;
private Ghost[] ghosts;
private boolean fruitHasBeenInTheLevel;
private static Semaphore CHANGE_SCORE_MUTEX;
public GameManager(){
this.fruitHasBeenInTheLevel=false;
//this.score=0;
this.gameMap=new GameMap();
this.gameMap.loadMap1();
this.level=1;
this.ghosts=new Ghost[4];
this.bonusResetTime = 5000;
this.scareCountDown=null;
}
public void setChangeScoreSemaphore(Semaphore changeScoreSemaphore) {
CHANGE_SCORE_MUTEX = changeScoreSemaphore;
//if(this.changeScoreSemaphore==null){
// Log.i("Change Score Semaphore","I'm null");
//}else{
// Log.i("Change Score Semaphore","I'm not null");
//}
}
public void addScore(int s){
//this.score+=s;
SCORE+=s;
CHANGE_SCORE_MUTEX.release();
/*if(this.changeScoreSemaphore==null){
Log.i("Change Score Semaphore","I'm null");
}else{
Log.i("Change Score Semaphore","I'm not null");
}*/
//this.changeScoreSemaphore.release();
}
public int getScore() {
return SCORE;
//return this.score;
}
public int getLevel() {
return this.level;
}
public GameMap getGameMap() {
return this.gameMap;
}
public Ghost[] getGhosts(){
return this.ghosts;
}
public Pacman getPacman(){
return this.pacman;
}
public void setPacman(Pacman pacman){
this.pacman=pacman;
}
public void eatPallet(int posXMap, int posYMap){
SCORE+=10;
CHANGE_SCORE_MUTEX.release();
//this.score+=10;
Log.i("Score GM", ""+SCORE);
//Log.i("Score GM", ""+this.score);
this.gameMap.getMap()[posYMap][posXMap]=0;
//this.changeScoreSemaphore.release();
//if(this.changeScoreSemaphore==null){
// Log.i("Change Score Semaphore","I'm null");
//}else{
// Log.i("Change Score Semaphore","I'm not null");
//}
}
public void eatBonus(int posXMap,int posYMap){
SCORE+=500;
CHANGE_SCORE_MUTEX.release();
//this.score+=500;
//Log.i("Score", Double.toString(this.score).substring(0,Double.toString(this.score).indexOf('.')));
this.gameMap.getMap()[posYMap][posXMap]=0;
//this.changeScoreSemaphore.release();
}
public void eatSuperPallet(int posXMap,int posYMap){
SCORE+=50;
CHANGE_SCORE_MUTEX.release();
//this.score+=50;
this.gameMap.getMap()[posYMap][posXMap]=0;
//Si hay un timer andando lo cancelo y ejecuto otro
if (this.scareCountDown != null){
this.scareCountDown.cancel();
}
this.scareCountDown = new CountDownScareGhosts(this.ghosts,this.gameMap.getMap());
this.scareCountDown.start();
//this.changeScoreSemaphore.release();
}
public void tryCreateBonus(){
//only if pacman has eaten 20 pallets we should allow the fruit appear
if(!this.fruitHasBeenInTheLevel && this.gameMap.getEatenPallets()>=20){
//to not allow the fruit be again in the level
this.fruitHasBeenInTheLevel=true;
new CountdownBonusThread(this.gameMap,this.bonusResetTime).start();
}
}
#RequiresApi(api = Build.VERSION_CODES.N)
public void moveGhosts(Canvas canvas,int blocksize) {
for (int i = 0; i < ghosts.length; i++) {
ghosts[i].move(this.gameMap.getMap(),this.pacman);
ghosts[i].draw(canvas);
}
}
public synchronized void initGhosts(int blocksize, Resources res, String packageName,int movementFluency) {
int[][]spawnPositions,cornersPositions, notUpDownPositions,defaultTargets;
defaultTargets=this.gameMap.getDefaultGhostTarget();
notUpDownPositions=this.gameMap.getNotUpDownDecisionPositions();
spawnPositions=this.gameMap.getGhostsSpawnPositions();
cornersPositions=this.gameMap.getGhostsScatterTarget();
//start position
// 5 blinky spawn [13, 11]
// 6 pinky spawn [15,11]
// 7 inky spawn [13,16]
// 8 clyde spawn [15,16]
this.ghosts=new Ghost[4];
ghosts[0] = new Ghost("blinky",spawnPositions[0], cornersPositions[0] ,new BehaviorChaseAgressive(notUpDownPositions,movementFluency,defaultTargets[0]),movementFluency,notUpDownPositions,'l',defaultTargets[0],blocksize,res,packageName);
ghosts[1] = new Ghost("pinky",spawnPositions[1],cornersPositions[1],new BehaviorChaseAmbush(notUpDownPositions,movementFluency,defaultTargets[1]),movementFluency,notUpDownPositions,'r',defaultTargets[1],blocksize,res,packageName);
ghosts[2] = new Ghost("inky",spawnPositions[2],cornersPositions[2],new BehaviorChasePatrol(notUpDownPositions,this.ghosts[0],movementFluency,defaultTargets[0]),movementFluency,notUpDownPositions,'l',defaultTargets[0],blocksize,res,packageName);
ghosts[3] = new Ghost("clyde",spawnPositions[3],cornersPositions[3],new BehaviorChaseRandom(notUpDownPositions,cornersPositions[3],movementFluency,defaultTargets[1]),movementFluency,notUpDownPositions,'r',defaultTargets[1],blocksize,res,packageName);
try{
Thread.sleep(200);
}catch(Exception e){}
for (int i=0;i<ghosts.length;i++){
ghosts[i].onLevelStart(1);
}
}
public boolean checkWinLevel() {
//player win the level if he has eaten all the pallet
return this.gameMap.countPallets()==0;
}
public void onResume(){
for (int i=0 ; i<this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null && !this.scareCountDown.hasEnded()){
this.scareCountDown.start();
}
}
public void onPause(){
for (int i=0 ; i<this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null && !this.scareCountDown.hasEnded()){
this.scareCountDown=this.scareCountDown.onPause();
}
}
public void cancelThreads(){
for (int i=0 ; i<this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null){
this.scareCountDown.cancel();
}
}
}
I am a beginner working with graphics. Right now I have an image displayed in random places on the screen. What I would like to do that if the image is touched, it should be replaced by another image. How can I do that?
Another thing I currently am using a class within a class.Thanks
public class MainActivity extends ActionBarActivity implements OnTouchListener{
MyGameGraphics myGraphics;
TextView tvScore, tvPlayerScore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tvScore = (TextView)findViewById(R.id.showScore);
tvPlayerScore = (TextView)findViewById(R.id.playerScore);
myGraphics = new GraphicsMain(this);
myGraphics.setOnTouchListener(this);
setContentView(myGraphics);
}
#Override
protected void onPause(){
super.onPause();
myGraphics.pause();
}
#Override
protected void onResume(){
super.onResume();
myGraphics.resume();
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
// TODO Auto-generated method stub
// How to change image using touch event here?
return false;
}
public class MyGameGraphics extends SurfaceView implements Runnable {
SurfaceHolder ourHolder;
Thread ourThread = null;
Boolean isRunning = false;
int[] images = new int[]{R.drawable.image1, R.drawable.image2};
public MyGameGraphics(Context context) {
super(context);
ourHolder = getHolder();
}
public void pause(){
isRunning = false;
while(true){
try {
ourThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume(){
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while(isRunning){
if(!ourHolder.getSurface().isValid())
continue;
Canvas ourCanvas = ourHolder.lockCanvas();
ourCanvas.drawRGB(0, 0, 0);
Random rn = new Random();
int location = rn.nextInt(12);
for(int i = 0; i < 500; i++){
try {
Random rn2 = new Random();
int generateWidthLocation = rn2.nextInt(420);
int generateHeightLocation = rn2.nextInt(600);
Bitmap btmp = BitmapFactory.decodeResource(getResources(), images[location]);
ourCanvas.drawBitmap(btmp, generateWidthLocation, generateHeightLocation, null);
ourThread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
ourHolder.unlockCanvasAndPost(ourCanvas);
}
}
}
}
In the OnTouch method, the event parameter has two functions : event.getX() and event.getY().
Then you just need to keep the generateWidthLocation and generateHeightLocation for the current position and you can easily determine if the image is touched or not (you also need to keep the height/width of the image).
You might need to check if the OnTouch method is called when the user touches the screens, moves his finger or stops to touch it : event.getAction() which is either MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE or MotionEvent.ACTION_UP.
EDIT : In your MyGameGraphics add the following properties :
int[] images = new int[] { R.drawable.image1, R.drawable.image2 };
int currentXImageLocation = 0;
int currentYImageLocation = 0;
int currentImageWidth = 0;
int currentImageHeight = 0;
And after ourCanvas.drawBitmap(btmp, generateWidthLocation, generateHeightLocation, null); add :
currentXImageLocation = generateWidthLocation;
currentYImageLocation = generateHeightLocation;
currentImageHeight = btmp.getHeight();
currentImageWidth = btmp.getWidth();
Then add this function in your MyGameGraphics class :
public boolean isImageTouched(float x, float y)
{
boolean result = false;
if(x > currentXImageLocation && x < currentXImageLocation + currentImageWidth
&& y > currentYImageLocation && y < currentYImageLocation + currentImageHeight)
{
result = true;
}
return result;
}
And finally in the OnTouch method :
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
if(myGraphics.isImageTouched(event.getX(), event.getY()))
{
//Image was touched, do something...
}
}
return true;
}
I am using touch listener for an imageview in the listview item .It is working fine when I just do that like an sample application(I mean I have that Listview item as an sample one). But when I put this in a listview it is really becoming very slow.
I just wants to drag the image only horizantally,for that purpose I used ConstrainedDragandDrop View class which I got from the Github.
In my sample application:
public class HorizontalScroll extends Activity {
ImageView full_left,heart;
RelativeLayout rlMainLayout,rlImages,Cartoon_image,half_left,play_btn,centre,centre_leftanimate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inflated_bloops);
half_left=(RelativeLayout)findViewById(R.id.half_left);
Cartoon_image=(RelativeLayout)findViewById(R.id.cartoon_image);
play_btn=(RelativeLayout)findViewById(R.id.play_btn);
heart=(ImageView)findViewById(R.id.ivheart);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) findViewById(R.id.dndView);
dndView.setDragHandle(findViewById(R.id.cartoon_image),findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,HorizontalScroll.this);
}
}
When I used in my Listview:
public class Cars extends BaseAdapter
{
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
LayoutInflater inflator = getLayoutInflater();
v= inflator.inflate(R.layout.inflated_bloops, null);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) v.findViewById(R.id.dndView);
dndView.setDragHandle(v.findViewById(R.id.cartoon_image),v.findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,FeedModeActivity.this);
RelativeLayout Cartoon_image=(RelativeLayout)v.findViewById(R.id.cartoon_image);
ImageView ivDummy =(ImageView)v.findViewById(R.id.dummy);
try{
loader.DisplayImageRelative( al_new.get(position).replace(" ", "%20"),ivDummy, Cartoon_image);
}
catch(Exception e){
e.printStackTrace();
}
return v;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return al_new.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
Here is my custom dragDrop view:
public class ConstrainedDragAndDropView extends LinearLayout {
Activity main;
protected View dragHandle,half,heart;
protected List<View> dropTargets = new ArrayList<View>();
protected boolean dragging = false;
protected int pointerId;
protected int selectedDropTargetIndex = -1;
protected int lastSelectedDropTargetIndex = -1;
protected int lastDroppedIndex = -1;
protected boolean allowHorizontalDrag = true;
protected boolean allowVerticalDrag = true;
protected DropListener dropListener;
public interface DropListener {
public void onDrop(final int dropIndex, final View dropTarget);
}
public ConstrainedDragAndDropView(Context context) {
super(context);
}
public ConstrainedDragAndDropView(Context context, AttributeSet attrs) {
super(context, attrs);
applyAttrs(context, attrs);
}
#SuppressLint("NewApi")
public ConstrainedDragAndDropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyAttrs(context, attrs);
}
public DropListener getDropListener() {
return dropListener;
}
public void setDropListener(DropListener dropListener) {
this.dropListener = dropListener;
}
public View getDragHandle() {
return dragHandle;
}
public void setDragHandle(View dragHandle,View half_left,View heart) {
this.dragHandle = dragHandle;
this.half=half_left;
this.heart=heart;
setupDragHandle();
}
public List<View> getDropTargets() {
return dropTargets;
}
public void setDropTargets(List<View> dropTargets) {
this.dropTargets = dropTargets;
}
public void addDropTarget(View target) {
if (dropTargets == null) {
dropTargets = new ArrayList<View>();
}
dropTargets.add(target);
}
public boolean isAllowHorizontalDrag() {
return allowHorizontalDrag;
}
public void setAllowHorizontalDrag(boolean allowHorizontalDrag) {
this.allowHorizontalDrag = allowHorizontalDrag;
}
public boolean isAllowVerticalDrag() {
return allowVerticalDrag;
}
public void setAllowVerticalDrag(boolean allowVerticalDrag,Activity c) {
this.allowVerticalDrag = allowVerticalDrag;
this.main=c;
}
protected void applyAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ConstrainedDragAndDropView, 0, 0);
try {
/*
layoutId = a.getResourceId(R.styleable.ConstrainedDragAndDropView_layoutId, 0);
if (layoutId > 0) {
LayoutInflater.from(context).inflate(layoutId, this, true);
}
*/
} finally {
a.recycle();
}
}
protected void setupDragHandle() {
this.setOnTouchListener(new DragAreaTouchListener());
}
protected class DragAreaTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("Action down", "action down in listener");
onActionDown(view, motionEvent);
break;
case MotionEvent.ACTION_UP:
Log.d("Action up", "action up in listener");
onActionUp(view, motionEvent);
break;
case MotionEvent.ACTION_MOVE:
Log.d("Action move", "action move in listener");
onActionMove(view, motionEvent);
break;
default:
break;
}
return true;
}
}
public static int param;
protected void onActionDown(View view, MotionEvent motionEvent) {
// if we're not already dragging, and the touch position is on the drag handle,
// then start dragging
if(!dragging && isDragHandleTouch(motionEvent)) {
pointerId = motionEvent.getPointerId(0);
Float s1= dragHandle.getX();
param=Integer.valueOf(s1.intValue());
Log.e("param",""+param);
// updateDragPosition(motionEvent);
dragging = true;
Log.d("drag", "drag start");
}
}
protected void onActionUp(View view, MotionEvent motionEvent) {
Log.d("Action up", "action up");
// if we're dragging, then stop dragging
if (dragging && motionEvent.getPointerId(0) == pointerId) {
Log.e("condition","satisfied");
Log.e("x val"+(int)motionEvent.getX(),"y val"+(int)motionEvent.getY());
Log.e("x1"+half.getLeft(),"y1"+half.getTop());
Log.e("x4"+half.getRight(),"y4"+half.getBottom());
Float s1=motionEvent.getX();
Float s2=motionEvent.getY();
int x=Integer.valueOf(s1.intValue());
dragging = false;
int y=Integer.valueOf(s2.intValue());
if((half.getLeft()<x)&&(x<half.getRight())&&((half.getTop()<y)&&(y<half.getBottom())))
{
Log.e("drop","on target");
try {
Thread.sleep(1000);
dragHandle.setX(param);
heart.setVisibility(View.VISIBLE);
Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
heart.startAnimation(pulse);
// heart.setVisibility(View.GONE);
pulse.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","start");
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","end");
heart.setVisibility(View.GONE);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// class SimpleThread extends Thread {
//
// public void run() {
//
// try {
// sleep(1000);
// runOnUiThread(new Runnable() {
// public void run() {
// dragHandle.setX(param);
// heart.setVisibility(View.VISIBLE);
//
// Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
// heart.startAnimation(pulse);
// }
// });
//
// }
// catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// }
// }
//
// new SimpleThread().start();
}
else{
Log.e("drop",""+"outside target");
dragHandle.setX(param);
// TranslateAnimation transAnimation= new TranslateAnimation(x, 300, y, 300);
// transAnimation.setDuration(1000);//set duration
// view.startAnimation(transAnimation);
}
// if()
// updateDragPosition(motionEvent);
Log.d("drag", "drag end");
// find out what drop target, if any, the drag handle was dropped on
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) { // if drop was on a target, select the target
Log.d("drag", "drop on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
// snapDragHandleToDropTarget(dropTargetIndex);
// lastDroppedIndex = dropTargetIndex;
if(dropListener != null) {
dropListener.onDrop(dropTargetIndex, dropTargets.get(dropTargetIndex));
}
} else { // if drop was not on a target, re-select the last selected target
// deselectDropTarget();
// snapDragHandleToDropTarget(lastDroppedIndex);
}
}
else{
Log.e("condition not","satisfied");
}
}
protected void onActionMove(View view, MotionEvent motionEvent) {
Log.d("Action move", "action move");
if (dragging && motionEvent.getPointerId(0) == pointerId) {
updateDragPosition(motionEvent);
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) {
Log.d("drag", "hover on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
} else {
// deselectDropTarget();
}
}
}
#SuppressLint("NewApi")
protected void updateDragPosition(MotionEvent motionEvent) {
// this is where we constrain the movement of the dragHandle
if(allowHorizontalDrag) {
float candidateX = motionEvent.getX() - dragHandle.getWidth() / 2;
if(candidateX > 0 && candidateX + dragHandle.getWidth() < this.getWidth()) {
dragHandle.setX(candidateX);
}
}
if(allowVerticalDrag) {
float candidateY = motionEvent.getY() - dragHandle.getHeight() / 2;
if(candidateY > 0 && candidateY + dragHandle.getHeight() < this.getHeight()) {
dragHandle.setY(candidateY);
}
}
}
#SuppressLint("NewApi")
protected void snapDragHandleToDropTarget(int dropTargetIndex) {
if(dropTargetIndex > -1) {
View dropTarget = dropTargets.get(dropTargetIndex);
float xCenter = dropTarget.getX() + dropTarget.getWidth() / 2;
float yCenter = dropTarget.getY() + dropTarget.getHeight() / 2;
float xOffset = dragHandle.getWidth() / 2;
float yOffset = dragHandle.getHeight() / 2;
float x = xCenter - xOffset;
float y = yCenter - yOffset;
dragHandle.setX(x);
dragHandle.setY(y);
}
}
protected boolean isDragHandleTouch(MotionEvent motionEvent) {
Point point = new Point(
new Float(motionEvent.getRawX()).intValue(),
new Float(motionEvent.getRawY()).intValue()
);
return isPointInView(point, dragHandle);
}
protected int findDropTargetIndexUnderDragHandle() {
int dropTargetIndex = -1;
for(int i = 0; i < dropTargets.size(); i++) {
if(isCollision(dragHandle, dropTargets.get(i))) {
dropTargetIndex = i;
break;
}
}
return dropTargetIndex;
}
/**
* Determines whether a raw screen coordinate is within the bounds of the specified view
* #param point - Point containing screen coordinates
* #param view - View to test
* #return true if the point is in the view, else false
*/
protected boolean isPointInView(Point point, View view) {
int[] viewPosition = new int[2];
view.getLocationOnScreen(viewPosition);
int left = viewPosition[0];
int right = left + view.getWidth();
int top = viewPosition[1];
int bottom = top + view.getHeight();
return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;
}
#SuppressLint("NewApi")
protected boolean isCollision(View view1, View view2) {
boolean collision = false;
do {
if(view1.getY() + view1.getHeight() < view2.getY()) {
break;
}
if(view1.getY() > view2.getY() + view2.getHeight()) {
break;
}
if(view1.getX() > view2.getX() + view2.getWidth()) {
break;
}
if(view1.getX() + view1.getWidth() < view2.getX()) {
break;
}
collision = true;
} while(false);
return collision;
}
protected void selectDropTarget(int index) {
if(index > -1) {
deselectDropTarget();
selectedDropTargetIndex = index;
dropTargets.get(selectedDropTargetIndex).setSelected(true);
}
}
protected void deselectDropTarget() {
if(selectedDropTargetIndex > -1) {
dropTargets.get(selectedDropTargetIndex).setSelected(false);
lastSelectedDropTargetIndex = selectedDropTargetIndex;
selectedDropTargetIndex = -1;
}
}
}
This Activity Code move Like a Iphone Horizontal Scroll.
second Code is ScrollView Library.
The Better Idea If you have, Comment Please.
Or Critics Welcome.
public class HorizontalScrollActivity extends Activity {
private StickyHorizontalScrollView scrollView;
private ArrayList<View> viewList = new ArrayList<View>();
private ViewGroup mLayout;
private ViewGroup mLayout2;
private ViewGroup mLayout3;
private LinearLayout mLayoutContainer;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
scrollView = new StickyHorizontalScrollView(this);
scrollView.setHorizontalScrollBarEnabled(false);
scrollView.setFadingEdgeLength(0);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
int deviceWidth = mDisplayMetrics.widthPixels;
int deviceHeight = mDisplayMetrics.heightPixels;
mLayout = (ViewGroup)inflater.inflate(R.layout.main, null);
mLayout.setLayoutParams(new LayoutParams(deviceWidth, deviceHeight));
mLayout2 = (ViewGroup)inflater.inflate(R.layout.main2, null);
mLayout2.setLayoutParams(new LayoutParams(deviceWidth, deviceHeight));
mLayout3 = (ViewGroup)inflater.inflate(R.layout.main3, null);
mLayoutContainer = (LinearLayout)mLayout3.findViewById(R.id.bodyLayout);
mLayout3.removeView(mLayoutContainer);
viewList.add(mLayout);
viewList.add(mLayout2);
int i = 0;
for(View v : viewList){
mLayoutContainer.addView(v);
scrollView.addStickyPosition(i++ * deviceWidth);
}
scrollView.addView(mLayoutContainer);
setContentView(scrollView);
}
}
And This Code for Iphonish HorizontalScrollView Library.
Library Page
public class StickyHorizontalScrollView extends HorizontalScrollView {
protected ArrayList<Integer> stickyPositions = new ArrayList<Integer>();
private boolean flinged = false;
private final String TAG = "StickyHorizontalScrollView ==========";
public StickyHorizontalScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
public void fling(int velocityX) {
// TODO Auto-generated method stub
Log.d(TAG, "FLING");
flinged = true;
int lastSmaller = 0;
for(int sticky : stickyPositions){
if(velocityX > 0 && sticky > getScrollX()){
smoothScrollTo(sticky, getScrollY());
break;
}else if(velocityX < 0){
if(sticky > getScrollX()){
smoothScrollTo(lastSmaller, getScrollY());
break;
}else{
lastSmaller = sticky;
}
}
}
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
Log.d(TAG, "TOUCH");
flinged = false;
boolean res = super.onTouchEvent(ev);
if(ev.getAction() == MotionEvent.ACTION_UP && !flinged){
sanitizeScrollPosition();
}
return res;
}
public void sanitizeScrollPosition(){
Log.d(TAG, "SANITIZE");
Integer minDistance = 0;
Integer minStickyPosition = 0;
for(int sticky : stickyPositions){
int distance = Math.abs(getScrollX() - sticky);
if(minDistance == null || minDistance > distance){
minStickyPosition = sticky;
minDistance = distance;
}
}
smoothScrollTo(minStickyPosition, getScrollY());
}
public void addStickyPosition(int x){
Log.d(TAG, "ADD STICKY POSITION");
stickyPositions.add(x);
Collections.sort(stickyPositions);
}
public void clearStickyPositions(){
Log.d(TAG, "CLEAR STICKY POSITION");
stickyPositions.clear();
}
}
I know you asked this question a year ago but for those who are still looking for that I found this amazing example and it made my day :
https://github.com/ysamlan/horizontalpager
hope you find it useful as well :)
I'm puzzled with the problem "AnimationDrawable not change frames" for some time.I'm confirmed I've added all the frames I need into the AnimationDrawable object,and I've called start(),and the result I called isRunning() is true,but the AnimationDrawable can't change the frame.
I called the start() in MainActivity's handler,not in onCreate() or onResume(),although the the called of start() is in the onResume() state.
Thanks for your thinkings.
----^_^ banlalaotou.
Added code which has the problem.
public class MainActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ma = new Ma(this);
ablt = ma.ablt;
setContentView(ablt);
mt = new MinorThread(this);
new Thread(mt).start();
while(true){
if(mt.mHandler==null) continue;
else{
Message msg = new Message();
mt.mHandler.sendMessage(msg);
break;
}
}
}
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
ma.control();
Message msg1 = new Message();
mt.mHandler.sendMessage(msg1);
}
};
#Override
public boolean onKeyDown(int keyCode,KeyEvent event){
switch(keyCode){
case KeyEvent.KEYCODE_BACK:
System.exit(0);
}
return true;
}
private MinorThread mt = null;
private ImageView v1 = null;
private Ma ma = null;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
private AbsoluteLayout ablt = null;
}
class MinorThread implements Runnable{
#Override
public void run() {
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg){
Message msg2 = new Message();
mainActivity.handler.sendMessage(msg2);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Looper.loop();
}
public MinorThread(MainActivity mainAcitivy){
this.mainActivity = mainAcitivy;
}
private MainActivity mainActivity = null;
public Handler mHandler = null;
}
class Ma{
public Ma(MainActivity context){
ablt = new AbsoluteLayout(context);
TestView v = new TestView(context);
AbsoluteLayout.LayoutParams lp = new LayoutParams(480,320,0,0);
ablt.addView(v, lp);
Drawable d = null;
ad = new AnimationDrawable();
d = context.getResources().getDrawable(R.drawable.f1);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f2);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f3);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f4);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f5);
ad.addFrame(d, 100);
v1 = new ImageView(context);
v1.setImageDrawable(ad);
String tag = "test";
v1.setTag(tag);
ablt.addView(v1, new LayoutParams(100, 40, 20, 20));
}
public void control(){
v1 = (ImageView) ablt.findViewWithTag("test");
if(x<480&&y<320){
x+=10;
y+=5;
v1.layout(x, y, x+100, y+40);
AnimationDrawable ad = (AnimationDrawable)v1.getDrawable();
ad.start();
}
}
public AbsoluteLayout ablt = null;
private AnimationDrawable ad = null;
private ImageView v1 = null;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
}
class TestView extends View{
public TestView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas){
paint.setColor(Color.WHITE);
canvas.drawRect(0,0,480,320, paint);
}
private Paint paint = new Paint();
}
I'sorry for not uploaded the frames,because my reputation is less than 10.
If you execute the code,you need to find some pictures to let the animation run.
thanks.
=============================
Now,I know how to let the result show,but I can't know the resaon.
The solution of the problem is that add a ImageView object into the layout object before show the all ImageView,and, "add a ImageView..." and "show the all ImageView" can't been processed in an function.The right method is like that "if(..){add a ImageView}else{show the all ImageView}".
Although,this method can resolve the problem I'd puzzeled,but why Android can't show the all ImageView's animations at first time?
Try to use start() in onWindowFocusChange(boolean focus) when focus is true.