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


GestureDetectorとView.onTouchListenerをListFragmentに実装して、ListViewでの
フリックを拾えるようになった(・∀・)

今のところは必要ないけど、いずれコンテクストメニュー等で必要になるかと思い、
OnItemLongClickListenerも追加した。そうしたら
Android ListView with OnItemClickListener AND GestureDetector
で投稿者が言っている、GestureDetectorのフリック処理後にItemLongClickが発生する
場合があるようになったので(フリックの仕方やタイミングによっては発生しない?)、
上記の回答を参考にして修正した。本当は回答にあるようにonFling()の後や
OnTouchListener()のonTouch()で一括して処理するべきかもしれないが取り敢えず
onFling()の各操作のところでキャンセルするようにした。


一応、最小必須SDK4.0.3で作ったデフォルトプロジェクトのMainActivityに貼れば
そのままで動作を確認出来るはず。コピペベースなのでコーディングスタイルやら
なにやらについてはキニシテナイ( ゚ 3゚)

true状態にするキャンセルを投げるので基本的にはitemLongClick()は発生しないはず。
稀にonFling()とは別に発生しているような気がするけど、頻度は低い。

うちの環境ではパワー不足等なのか、よくeclipseの挙動がおかしくなったり、LogCatが
ログを吐かなくなったりするのでToastを追加した。が、これまたちょっと変だったりするw
Toast表示の長さがToast.LENGTH_LONGの時はきちんと予期している通りにonFling()の後に
itemLongClick()のToastが表示されるが、Toast.LENGTH_SHORTにするとitemLongClick()の
Toastは表示されずitemClick()の方が表示されるw Toast表示ってなんか重そうな処理
だから、その辺の絡みでonTouchの処理が変わってしまうのだろうか? 新たな謎だw

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.AdapterView.OnItemClickListener;
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 implements OnItemClickListener{

	private GestureDetector mGestureDetector;
    private View.OnTouchListener mGestureListener;
    private static ListView listView;
    private static boolean isDoCancel;
    private static final String TAG = "MainActivity";
    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.setOnItemClickListener(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);
    }

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		Log.d(TAG,"itemClick");
		Toast.makeText(MainActivity.this, "onItemClick 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 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;
		}
	}
}

これでitemLongClick()の問題が片付くが、今度はitemClick()の問題が出て来るw
大して内容は変わらないが次のエントリにしよう(ヽ’ω`) ナガスギル…