0

I'm creating a small application for practice some in Android programming. It's a kind of puzzle game like this:

Screen from application

I have a following issue: when I slide a button left or right in x property all is OK. I can move each button frequently left and right. The problem begins when I move the button down or up in y property. I can only move the button once and next it will be no longer available for the onTouchListener. It become immobile in any direction and any action isn't performed. Here is my java activity file and the layout xml.

MainActivity.java

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

class MyPoint{

    private boolean canMove;
    private View associatedView;
    private int x;
    private int y;
    private MyPoint nord;
    private MyPoint south;
    private MyPoint est;
    private MyPoint west;

    MyPoint(int x, int y, View associatedView){
        this.x = x;
        this.y = y;
        this.associatedView = associatedView;
        canMove = false;
    }

    public MyPoint getEst() {
        return est;
    }

    public MyPoint getNord() {
        return nord;
    }

    public MyPoint getSouth() {
        return south;
    }

    public MyPoint getWest() {
        return west;
    }

    public void setNeighbors(MyPoint nord, MyPoint south, MyPoint west, MyPoint est){
        this.nord = nord;
        this.south = south;
        this.est = est;
        this.west = west;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public View getAssociatedView() {
        return associatedView;
    }

    public void setAssociatedView(View associatedView) {
        this.associatedView = associatedView;
    }

    public boolean isSpace(){
        if(associatedView.getId() == R.id.space)
            return true;
        else
            return false;
    }

    public void allowMovement(){
         canMove = true;
    }

    public void denyMovement(){
        canMove = false;
    }

    public void allowMovementNeighbords(){
        nord.allowMovement();
        south.allowMovement();
        est.allowMovement();
        west.allowMovement();
    }

    public boolean isMoveable(){
        if(canMove) return true;
        else return false;
    }
}

public class MainActivity extends ActionBarActivity {

    LinearLayout mainScreen;
    MyPoint[] board = new MyPoint[16];
    View[] views = new View[16];
    View blank;
    MyPoint blankPoint, associatedPoint;
    int DX,DY;

    private MyPoint findPointByView(View target){
        MyPoint tempResult = blankPoint;
        for(int i=0; i<16; i++)
            if(board[i].getAssociatedView().getId() == target.getId())
                tempResult = board[i];
        return tempResult;
    }

    private MyPoint findSpace(){
        MyPoint tempResult = blankPoint;
        for(int i=0; i<16; i++)
            if(board[i].isSpace()){
                tempResult = board[i];
            }

        return tempResult;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainScreen = (LinearLayout) findViewById(R.id.main_screen);
        blank = findViewById(R.id.blank);
        blankPoint = new MyPoint(0,0,blank);
        blankPoint.setNeighbors(blankPoint,blankPoint,blankPoint,blankPoint);
        associatedPoint = blankPoint;

        final View.OnTouchListener mTouchListener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event){

               float x1=0, x2, y1=0, y2, dx, dy;

               switch(event.getActionMasked()) {
                    case(MotionEvent.ACTION_DOWN):
                        associatedPoint = findPointByView(v);
                        x1 = event.getX();
                        y1 = event.getY();
                        break;
                    case(MotionEvent.ACTION_UP): {
                        x2 = event.getX();
                        y2 = event.getY();
                        dx = x2-x1;
                        dy = y2-y1;

                        if(associatedPoint.isMoveable()){
                            if(Math.abs(dx) > Math.abs(dy)) {
                                if(dx>0){
                                    if(associatedPoint.getEst().isSpace()){
                                       v.animate().xBy(DX);
                                        associatedPoint.setAssociatedView(findViewById(R.id.space));
                                        associatedPoint.getEst().setAssociatedView(v);
                                    }
                                }
                                else{
                                    if(associatedPoint.getWest().isSpace()){
                                        v.animate().xBy(-DX);
                                        associatedPoint.setAssociatedView(findViewById(R.id.space));
                                        associatedPoint.getWest().setAssociatedView(v);
                                    }
                                }
                            } else {
                                if(dy>0){
                                    if(associatedPoint.getSouth().isSpace()){
                                        v.animate().yBy(DY);
                                        associatedPoint.setAssociatedView(findViewById(R.id.space));
                                        associatedPoint.getSouth().setAssociatedView(v);
                                    }
                                }
                                else{
                                    if(associatedPoint.getNord().isSpace()){
                                        v.animate().yBy(-DY);
                                        associatedPoint.setAssociatedView(findViewById(R.id.space));
                                        associatedPoint.getNord().setAssociatedView(v);
                                    }
                                }
                            }

                        denyMovementAll();
                        findSpace().allowMovementNeighbords();
                        }
                    return true;
                    }
               }
            return false;
            }
        };

        views[0] = findViewById(R.id.button1);
        views[1] = findViewById(R.id.button2);
        views[2] = findViewById(R.id.button3);
        views[3] = findViewById(R.id.button4);
        views[4] = findViewById(R.id.button5);
        views[5] = findViewById(R.id.button6);
        views[6] = findViewById(R.id.button7);
        views[7] = findViewById(R.id.button8);
        views[8] = findViewById(R.id.button9);
        views[9] = findViewById(R.id.button10);
        views[10] = findViewById(R.id.button11);
        views[11] = findViewById(R.id.button12);
        views[12] = findViewById(R.id.button13);
        views[13] = findViewById(R.id.button14);
        views[14] = findViewById(R.id.button15);
        views[15] = findViewById(R.id.space);

        for(int i=0; i<15; i++)
            views[i].setOnTouchListener(mTouchListener);
    }

    private void denyMovementAll() {
        for(int i=0; i<16; i++)
            board[i].denyMovement();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int offsetY = displayMetrics.heightPixels - mainScreen.getMeasuredHeight();

        for (int i=0 ; i<16; i++){
            int[] tempCoords = new int[2];
            views[i].getLocationOnScreen(tempCoords);
            int x = tempCoords[0];
            int y = tempCoords[1] - offsetY;
            board[i] = new MyPoint(x,y,views[i]);
        }

        board[0].setNeighbors(blankPoint,board[4],blankPoint,board[1]);
        board[1].setNeighbors(blankPoint,board[5],board[0],board[2]);
        board[2].setNeighbors(blankPoint,board[6],board[1],board[3]);
        board[3].setNeighbors(blankPoint,board[7],board[2],blankPoint);
        board[4].setNeighbors(board[0],board[8],blankPoint,board[5]);
        board[5].setNeighbors(board[1],board[9],board[4],board[6]);
        board[6].setNeighbors(board[2],board[10],board[5],board[7]);
        board[7].setNeighbors(board[3],board[11],board[6],blankPoint);
        board[8].setNeighbors(board[4],board[12],blankPoint,board[9]);
        board[9].setNeighbors(board[5],board[13],board[8],board[10]);
        board[10].setNeighbors(board[6],board[14],board[9],board[11]);
        board[11].setNeighbors(board[7],board[15],board[10],blankPoint);
        board[12].setNeighbors(board[8],blankPoint,blankPoint,board[13]);
        board[13].setNeighbors(board[9],blankPoint,board[12],board[14]);
        board[14].setNeighbors(board[10],blankPoint,board[13],board[15]);
        board[15].setNeighbors(board[11],blankPoint,board[14],blankPoint);

        DX = board[1].getX() - board[0].getX();
        DY = board[4].getY() - board[0].getY();

        denyMovementAll();
        findSpace().allowMovementNeighbords();
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"        android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:collapseColumns="4"
android:orientation="vertical"
android:clipChildren="false"
android:id="@+id/main_screen"
android:clipToPadding="false">


<LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:id="@+id/row1">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b1"
        android:id="@+id/button1"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b2"
        android:id="@+id/button2"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b3"
        android:id="@+id/button3"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b4"
        android:id="@+id/button4"
        android:layout_weight="1" />
</LinearLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:id="@+id/row2">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b5"
        android:id="@+id/button5"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b6"
        android:id="@+id/button6"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b7"
        android:id="@+id/button7"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b8"
        android:id="@+id/button8"
        android:layout_weight="1" />
</LinearLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:id="@+id/row3">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b9"
        android:id="@+id/button9"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b10"
        android:id="@+id/button10"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b11"
        android:id="@+id/button11"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b12"
        android:id="@+id/button12"
        android:layout_weight="1" />
</LinearLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:id="@+id/row4">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b13"
        android:id="@+id/button13"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b14"
        android:id="@+id/button14"
        android:layout_weight="1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:text="@string/b15"
        android:id="@+id/button15"
        android:layout_weight="1" />

    <Space
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/space"
        android:visibility="invisible"/>

     <Space
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:visibility="invisible"
        android:id="@+id/blank"/>


</LinearLayout>
</LinearLayout>

I have really no idea what cause this problem. Please give me a small prompt on what may cause this issue. Thanks in advance

lukasz-zimnoch
  • 107
  • 1
  • 14
  • There are a couple of problems I see, but these don't seem to cause the behavior you observe. One is that you are trying to move the views but you determine DX and DY based on fixed views. If these views have moved, this will change the DX and DY values even if the grid should stay the same. Another issue is that animating a view changes the appearance of the view but normally does not change the actual location, such as where you can touch the view. – Douglas Zare Jan 03 '15 at 03:02
  • Do you get the same vertical versus horizontal behavior if you put the buttons in vertical linear layouts instead of horizontal ones? – Douglas Zare Jan 03 '15 at 03:03
  • It looks like you are trying to do a classic 15 puzzle, but the logic doesn't fit that. For example, in the 15 puzzle, you can only move a tile to the space. Did you mean x1 and y1 to be local variables in OnTouch or in the OnTouchListener? – Douglas Zare Jan 03 '15 at 03:10
  • It's just a part of my code. I cut of the logic responsible for correct movement of button . I wanted to check if it cause this issue. But after removing the logic my problem still remains so I posted only the code responsible for animation. I will apply all your suggestions and change the layout following your tip for check if it will solve my bug – lukasz-zimnoch Jan 03 '15 at 11:57
  • I changed the layout for vertical linear layouts and the problem is now in the x property so I think that the translation between layouts cause my issue but I don't know how I can fix that. If someone can help thanks in advance – lukasz-zimnoch Jan 07 '15 at 22:42
  • Well, if you don't post your actual logic, and we don't see exactly what is going wrong, it is hard to guess, but you could make this work in many ways. There are step-by-step tutorials on how to make a 15 game and I gave you several important points. Did SLee's answer solve your problem? If not, why accept it? – Douglas Zare Jan 08 '15 at 00:12
  • I updated my MainActivity.java . It presents my full activity code of this app. I know it's full of things to correct but It the logic seems to work correct.I know that I do wrong using onWindowFocusChanging for do that kind of work but it's a temporary solution. I try to do all in my own without tutorials but I can't solve the issue which I describe in this topic. Sory for the code quality, I'm totally beginner ;) – lukasz-zimnoch Jan 08 '15 at 00:52
  • Avoiding tutorials at first is ok, but after you try something you should look up how other people approach the problem. As I stated above, animations don't normally move the Views being animated, and if you touch outside the parent, this will not be passed to the child. If you want to keep the numbers permanently attached to the buttons, don't use a LinearLayout of LinearLayouts. If you do want to use those layouts, you will need the buttons to represent whatever is in that location. – Douglas Zare Jan 08 '15 at 13:17
  • OK , thank you for yours explanations. – lukasz-zimnoch Jan 08 '15 at 19:13

2 Answers2

0

You should return true if the listener has consumed the event. Otherwise, it should return false as default.

View.OnTouchListener mTouchListener = new View.OnTouchListener() {
    ...
    return false;
}
sam
  • 2,780
  • 1
  • 17
  • 30
0

I changed my code following your tip :

View.OnTouchListener mTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event){

            float x1=0, x2, y1=0, y2, dx, dy;


            switch(event.getActionMasked()) {
                case(MotionEvent.ACTION_DOWN):
                    x1 = event.getX();
                    y1 = event.getY();
                    break;

                case(MotionEvent.ACTION_UP): {

                    x2 = event.getX();
                    y2 = event.getY();
                    dx = x2-x1;
                    dy = y2-y1;


                        if(Math.abs(dx) > Math.abs(dy)) {
                            if(dx>0){
                                v.animate().xBy(DX);
                                }

                            else{
                                v.animate().xBy(-DX);
                                }

                        } else {
                            if(dy>0){
                                v.animate().yBy(DY);
                                }

                            else{
                                v.animate().yBy(-DY);
                                }
                        }
                return true;

                }

            }
        return false;
        }
    };

Unfortunately, that doesn't solve my problem. Please, correct me if I made a mistake

lukasz-zimnoch
  • 107
  • 1
  • 14