Android strange onClick() behavior with 2D scrolling

41 views Asked by At

I've written my own "Minesweeper" game, trying to make it as faithful as possible to the original Microsoft game.

To create a variable-sized minefield, my XML has a (vertical) TableLayout nested inside the horizontal and vertical ScrollViews. I populate the TableLayout with TableRows, to which I add ImageViews representing the minefield squares in each row. I give each ImageView an id representing its row/column. My onClick() handler converts the id to a row/column and handles it. It works fine, except that scrolling the minefield can be done in only one dimension at a time.

I found a very nice technique for 2D scrolling published on YouTube by William Kwan ( https://www.youtube.com/watch?v=Y-q6eWFyS54 ). I incorporated it into my app, and it scrolls very nicely. But it has produced a strange onClick() result when I scroll horizontally (not when I scroll vertically).

In the new implementation, when I scroll horizontally and click (touch) a square, onClick() receives an id that corresponds, not to the square I clicked, but to the square that would have been in that position if I had not scrolled. For example, if, before scrolling, I click a square whose coordinates are (1,3), onClick receives an ImageView whose id corresponds to (1,3). But if I scroll a distance that corresponds to 2 squares to the left, and I click the same position on the screen, which should represent the ImageView at coordinates (1,5), onClick returns the ImageView whose id corresponds to (1,3). It's as if the scroll had not happened.

I tried a circumvention using getScrollX() (the number of pixels that the OuterHorizontalScrollView has scrolled) and getWidth() (the width of a "square") to calculate how may "squares" have been scrolled, and adjusting the y in the (x,y) coordinates. But when the scroll is close to "half a square", the result is sometimes off by one.

Any suggestions?

Thank you.

My XML:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:id="@+id/fullscreen"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/rMines100"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />

            <ImageView
                android:id="@+id/rMines10"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />

            <ImageView
                android:id="@+id/rMines1"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />

            <ImageButton
                android:id="@+id/smileyButton"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="right"
                android:layout_weight="3"
                android:paddingLeft="40dp" />

            <ImageButton
                android:id="@+id/flagOrMineButton"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1.5"
                android:text="New Button" />

            <ImageView
                android:id="@+id/eTime100"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />

            <ImageView
                android:id="@+id/eTime10"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />

            <ImageView
                android:id="@+id/eTime1"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:src="@drawable/digit8" />m
        </LinearLayout>


        <com.mpa.minesweeper.OuterHorizontalScrollView
            android:id="@+id/horizontal"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="9">

            <ScrollView
                android:id="@+id/vertical"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <TableLayout
                    android:id="@+id/tableLayout"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical"></TableLayout>

            </ScrollView>
        </com.mpa.minesweeper.OuterHorizontalScrollView>


    </LinearLayout>
 </layout>

The OuterHorizontalScrollView Class:

package com.mpa.minesweeper;

        import android.content.Context;
        import android.util.AttributeSet;
        import android.view.MotionEvent;
        import android.widget.HorizontalScrollView;
        import android.widget.ScrollView;

/**
 * Created by willi on 2017-06-08.
 */

public class OuterHorizontalScrollView extends HorizontalScrollView {
    public ScrollView scrollView;

    public OuterHorizontalScrollView(Context context) {
        super(context);
    }

    public OuterHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OuterHorizontalScrollView(Context context, AttributeSet attrs, 
int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        super.onInterceptTouchEvent(ev);
        scrollView.onInterceptTouchEvent(ev);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);
        scrollView.dispatchTouchEvent(ev);
        return true;
    }
}
0

There are 0 answers