/*
* Copyright 2013 wada811<at.wada811@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.wada811.view;
import android.view.MotionEvent;
import android.view.View;
import at.wada811.utils.LogUtils;
import java.util.EventListener;
public class FlickTouchListener implements View.OnTouchListener {
/** x coordinate on MotionEvent.ACTION_DOWN */
private float mDownX;
/** y coordinate on MotionEvent.ACTION_DOWN */
private float mDownY;
/** x coordinate on MotionEvent.ACTION_UP */
private float mUpX;
/** y coordinate on MotionEvent.ACTION_UP */
private float mUpY;
/** 最低限移動しないといけない距離 */
protected static final float MIN_DISTANCE = 100;
/** event time on MotionEvent.ACTION_DOWN */
private long mDownTime;
/** event time on MotionEvent.ACTION_UP */
private long mUpTime;
/** 最大移動時間 */
protected static final long MAX_MOVE_TIME = 150;
private OnFlickListener mListener;
public interface OnFlickListener extends EventListener {
public void onFlickUp();
public void onFlickDown();
public void onFlickRight();
public void onFlickLeft();
}
public FlickTouchListener(OnFlickListener listener) {
mListener = listener;
}
@Override
public boolean onTouch(View v, MotionEvent event){
// タッチされている指の本数
LogUtils.v("touch_count = " + event.getPointerCount());
// タッチされている座標
LogUtils.v("X: " + Float.toString(event.getX()));
LogUtils.v("Y: " + Float.toString(event.getY()));
switch(event.getAction()){
case MotionEvent.ACTION_DOWN: // タッチ
LogUtils.v("motionEvent: ACTION_DOWN");
mDownX = event.getX();
mDownY = event.getY();
mDownTime = event.getEventTime();
return true;
case MotionEvent.ACTION_POINTER_DOWN: // タッチ中に追加でタッチした場合
LogUtils.v("motionEvent: ACTION_POINTER_DOWN");
return true;
case MotionEvent.ACTION_MOVE: // スライド
LogUtils.v("motionEvent: ACTION_MOVE");
return true;
case MotionEvent.ACTION_UP: // タッチが離れた
LogUtils.v("motionEvent: ACTION_UP");
mUpX = event.getX();
mUpY = event.getY();
mUpTime = event.getEventTime();
return detectFlickDirection();
case MotionEvent.ACTION_POINTER_UP: // アップ後にほかの指がタッチ中の場合
LogUtils.v("motionEvent: ACTION_POINTER_UP");
return true;
case MotionEvent.ACTION_CANCEL: // UP+DOWNの同時発生(タッチのキャンセル)
LogUtils.v("motionEvent: ACTION_CANCEL");
return true;
case MotionEvent.ACTION_OUTSIDE: // ターゲットとするUIの範囲外を押下
LogUtils.v("motionEvent: ACTION_OUTSIDE");
return true;
default:
return false;
}
}
/**
* フリック方向を検出してリスナーに通知する
*
* @return フリック方向を検出できなかった場合はfalse
*/
private boolean detectFlickDirection(){
// 左上を原点とし、右下が正
float moveX = mDownX - mUpX; // 正: 左, 負: 右
float moveY = mDownY - mUpY; // 正: 上, 負: 下
LogUtils.d("moveX: " + moveX);
LogUtils.d("moveY: " + moveY);
// 移動量のチェック
float absMoveX = Math.abs(moveX);
float absMoveY = Math.abs(moveY);
if(absMoveX < MIN_DISTANCE && absMoveY < MIN_DISTANCE){
LogUtils.d("absMoveX < MIN_DISTANCE: " + absMoveX + " < " + MIN_DISTANCE);
LogUtils.d("absMoveY < MIN_DISTANCE: " + absMoveY + " < " + MIN_DISTANCE);
return false;
}
// 移動時間のチェック
long moveTime = mUpTime - mDownTime;
LogUtils.d("moveTime: " + moveTime);
if(moveTime > MAX_MOVE_TIME){
LogUtils.d("moveTime > MAX_MOVE_TIME: " + moveTime + " > " + MAX_MOVE_TIME);
return false;
}
// 方向の決定
if(absMoveX > absMoveY){ // 左右
if(moveX > 0){ // 左
mListener.onFlickLeft();
}else{ // 右
mListener.onFlickRight();
}
}else{ // 上下
if(moveY > 0){ // 上
mListener.onFlickUp();
}else{ // 下
mListener.onFlickDown();
}
}
return true;
}
}