( ゚Д゚)ハッ そういうことか…_| ̄|○ 続き


( ゚Д゚)ハッ そういうことか…_| ̄|○の続き。

前回のコードにflip – Gesture in listview androidの修正を加えたもの。

true状態、つまりはキャンセルを実行するならフリックと単純なアイテムクリックと
ロングクリックが個別にというか独立的に取得出来る…みたいだ。

動きとしてはonItemClickListenerを使わずにSimpleOnGestureListener.onSingleTapUp()で
イベントを拾ってアクティビティ側に実装したmyOnItemClick()を呼び出して任意の処理を
する感じみたい。でもこれってお作法的にはMyGestureDetector側にItemClick()メソッドを
持つMyOnItemClickListenerインターフェイスみたいなのを作ってそれをアクティビティに
実装させて呼び出す感じするべきなんだろうか?

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private GestureDetector mGestureDetector;
    private View.OnTouchListener mGestureListener;
    private static ListView listView;
    private static boolean isDoCancel;
    private static final int CONTENT_VIEW_ID = 10101010;
	private static final String[] CONFECTIONERY = {
		"Apple Pie", "Banana Bread", "Cupcake", "Donut", "Eclair", "Froyo",
		"Gingerbread", "Honeycomb", "Ice Cream Sandwich", "Jelly Bean",
		"KitKat", "Lollipop"
	};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

		LinearLayout layout=new LinearLayout(this);
		layout.setBackgroundColor(Color.WHITE);
		layout.setOrientation(LinearLayout.VERTICAL);
		layout.setId(CONTENT_VIEW_ID);

		setContentView(layout, new LayoutParams(
	            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

		final Button button = new Button(this);
		button.setText("false");
		button.setOnClickListener(new View.OnClickListener(){

			@Override
			public void onClick(View v) {
				isDoCancel = !isDoCancel;
				button.setText(""+isDoCancel);
			}

		});

		layout.addView(button);

        mGestureDetector = new GestureDetector(this,new MyGestureDetector());
        mGestureListener = new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
            	return mGestureDetector.onTouchEvent(event);
            }
         };

        listView = new ListView(this);
        listView.setOnTouchListener(mGestureListener);
		listView.setLayoutParams(new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
				CONFECTIONERY));
		listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
				Log.d("onItemLongClick", "longClick");
				Toast.makeText(MainActivity.this, "onItemLongClick longClick", Toast.LENGTH_LONG).show();
				return false;
			}
		});

		layout.addView(listView);
    }

    private void myOnItemClick(int position) {
    	Log.d("myOnItemClick", "itemClick: " + position);
    	Toast.makeText(MainActivity.this, "myOnItemClick itemClick", Toast.LENGTH_LONG).show();
    }

	class MyGestureDetector extends SimpleOnGestureListener {
		private static final int SWIPE_MIN_DISTANCE = 120;
		private static final int SWIPE_MAX_OFF_PATH = 250;
		private static final int SWIPE_THRESHOLD_VELOCITY = 200;

		@Override
        public boolean onSingleTapUp(MotionEvent e) {

            int pos = listView.pointToPosition((int)e.getX(), (int)e.getY());
            myOnItemClick(pos);
            return false;
        }


		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2,
				float velocityX, float velocityY) {
			if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
				return false;
			}

			if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				Log.d("onFling", "FlingLeft");
				Toast.makeText(MainActivity.this, "onFling FlingLeft", Toast.LENGTH_LONG).show();

				if(isDoCancel){
					MotionEvent cancelEvent = MotionEvent.obtain(e2);
		            cancelEvent.setAction(MotionEvent.ACTION_UP);
		            listView.onTouchEvent(cancelEvent);
				}

				return true;
			} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				Log.d("onFling", "FlingRight");
				Toast.makeText(MainActivity.this, "onFling FlingRight", Toast.LENGTH_LONG).show();

				if(isDoCancel){
					MotionEvent cancelEvent = MotionEvent.obtain(e2);
		            cancelEvent.setAction(MotionEvent.ACTION_UP);
		            listView.onTouchEvent(cancelEvent);
				}
				return true;
			}

			return false;
		}
	}
}

一応これでListView絡みのフリックの実装は問題なさそう。

まあしかし、今回の一番の収穫はきちんと理解していなかったGestureDetectorと
View.OnTouchListenerの辺りを理解出来たことかな。

「GestureDetectorって登録してないけど、なんで動くの(´・ω・`)?」とか
「View.OnTouchListenerって一体何なの(´・ω・`)?」と
素人丸出しの疑問を持っていたが、ソースを読んだりぐぐった結果、

View.OnTouchListenerは

Interface definition for a callback to be invoked when a touch event is dispatched to this view. The callback will be invoked before the touch event is given to the view.

“タッチイベントがこのビューへ送出される時、呼び出されるコールバック用のインターフェイス定義。コールバックはタッチイベントがビューへ与えられる前に呼び出される。”

とあるので、所謂、タッチイベントを横取りする為のフックで、そしてそのonTouch()
メソッド内でGestureDetectorのonTouchEvent()を呼び出してるからGestureDetectorが
処理出来るんだな(・∀・)

つーことはこれはListViewに限らず、あらゆるViewにおけるGestureDetectorの基本的な
使い方ということなんだろうか。


実は前回と今回のスニペットだけではよくわからなかった(ノ∀`)
だけれども、色々とぐぐっている時にヒットした
#AndroidDev OK, seems from the last post that lots of folks are interested in…
という共有からGitHubのromannurik/Android-SwipeToDismissへ辿り着き、
挙動が面白いので、SwipeDismissListViewTouchListenerのソースを頑張って読んだり、
ぐぐったりして内容を理解して行ったら、その結果として2つのスニペットの方も理解出来た。
これはGestureDetectorに処理を移譲せずにスワイプを自分で処理しているのでその部分に
ついても勉強になった(・∀・) デモスグワスレル

なんでこんなタイトルのエントリにしたんだったか忘れて、しばし悩んだ(´・ω・`)

前のコードから今回のコードに変える際にOnItemLongClickListenerをコメントアウト
しておいたのを忘れて「なんでOnItemLongClickを拾わなくなったヽ(`Д´)ノ」と
一時間位ハマった後に一眠りして、再びコードを眺めた時にそのことに気づいた時の
俺氏の心の中のつぶやきからだったことを思い出した(ノ∀`)


ああ違う、こんなことをしている場合じゃない…(ヽ’ω`)