Program Resource

開発者向け各種コード、アルゴリズム、リソース情報ライブラリ もしくはねふぁの覚え書き

ジェスチャーでWebViewのブラウザ履歴を行ったり来たりする

AndroidアプリはWebViewを使う事で簡単にブラウザ機能を追加する事が出来る。表示内容についてはあまり手を入れる事は出来ないが、UI回りについては割と自由に設計する事が可能だ。

今回は、WebViewに指を左右にスワイプするジェスチャーにより、閲覧履歴を前後に移動する機能の実装について説明しよう。

参考サイト:
http://blog.global-eng.co.jp/android/2011/02/11/gesturedetector...
http://wiki.livedoor.jp/moonlight_aska/d/...

ジェスチャーにはGestureDetectorクラスを利用する。本クラスを使う事により、左右のジェスチャーだけでなくダブルタップや長押しした際の動作も定義することが出来る。ただし、ブラウザ自体の操作を横取りしすぎない様注意が必要だ。

WebViewクラスを継承してカスタムWebViewを作成し、そこでジェスチャー処理を行う。下記サンプルでは指を左から右にスワイプする事で履歴を戻るが、戻る履歴が無い場合アプリ自体を終了する様にしている。

まずは、メインのActivity側。

private BackNotify mNotify = new BackNotify();
private Handler mNotifyHandler = null;

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

	nfWebView webview;
	webview = new nfWebView(this);

	//register handler for webview terminate notification
	if(mNotifyHandler == null)
		mNotifyHandler = new Handler();
	webview.SetNotifyBackHandler(mNotifyHandler, mNotify);

	//add view
	RelativeLayout wholder = (RelativeLayout) findViewById(R.id.web);
	wholder.addView(webview, new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,RelativeLayout.LayoutParams.FILL_PARENT));
}

//called when Back gesture is done while no more backward history
public class BackNotify implements Runnable { //notify from nfWebView
	@Override
	public void run() {
		finish();
	}
}

カスタムWebViewクラス。ジェスチャーとして成立する指の移動量や速度も調整可能だ。

//custom webview
public class nfWebView extends WebView  {
	Context context;
	GestureDetector gd;
	int gesture_stx,gesture_sty;
    private Handler notifyback_handler;
    private Runnable notifyback_listener;

	public nfWebView(Context context) {
	    super(context);
	    this.context = context;
		gd = new GestureDetector(context, onGestureListener);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return (gd.onTouchEvent(event) || super.onTouchEvent(event));
	}

    public void SetNotifyBackHandler(Handler _handler, Runnable _listener)
    {
        notifyback_handler = _handler;
        notifyback_listener = _listener;
    }
    public void CallNotifyBackTakenHandler()
    {
    	notifyback_handler.post(notifyback_listener);
    }

    private final SimpleOnGestureListener onGestureListener = new SimpleOnGestureListener() {
    	@Override
    	public boolean onDoubleTap(MotionEvent e) {
    		return super.onDoubleTap(e);
    	}
    	@Override
		public boolean onDoubleTapEvent(MotionEvent e) {
    		return super.onDoubleTapEvent(e);
    	}
    	@Override
    	public boolean onDown(MotionEvent e) {
    		return super.onDown(e);
    	}
    	@Override
    	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {
    		float deltax,deltay,velo;
    		deltax = Math.abs(e1.getRawX()-e2.getRawX());
    		deltay = Math.abs(e1.getRawY()-e2.getRawY());
    		velo = Math.abs(velocityX);

    		//pref_browser_gesturevelo is how fast finger moves.
    		//pref_browser_gesturevelo set to 350 as default in my app
    		if (deltax > 200 && deltay < 90 && velo > pref_browser_gesturevelo) {
    			if (e1.getRawX() > e2.getRawX()) {
					if (canGoForward()){
						//Gesture : move forward
						goForward();
					}
					else{
						//Gesture : no more forward history
    				}
    			} else if(e1.getRawX() < e2.getRawX()){
					if (canGoBack()){
						//Gesture : go back
   						goBack();
   					}
   					else{
   						//Gesture : no more backward history, end browser
    					CallNotifyBackTakenHandler();
   					}
    			}
    		}
    		return super.onFling(e1, e2, velocityX, velocityY);
    	}
    	@Override
    	public void onLongPress(MotionEvent e) {
    		super.onLongPress(e);
    	}
    	@Override
    	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    		return super.onScroll(e1, e2, distanceX, distanceY);
    	}
    	@Override
    	public void onShowPress(MotionEvent e) {
    		super.onShowPress(e);
    	}
    	@Override
    	public boolean onSingleTapConfirmed(MotionEvent e) {
    		return super.onSingleTapConfirmed(e);
    	}
    	@Override
    	public boolean onSingleTapUp(MotionEvent e) {
    		return super.onSingleTapUp(e);
    	}
    };
}

This post is also available in: 英語

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*