2007/03/04開始。ソフトウェア管理やDelerer SEの作者であるおにぎりくんの試行錯誤の記録です。
- [Vue.js]時計?タイムコードを表示するWebアプリ
- (2021/11/16)
- ポエム
- (2020/09/30)
- メトロノームアプリをリリース
- (2017/04/22)
- Sikulix勉強中:便利関数
- (2017/02/25)
- [JavaFX]学習メモ
- (2016/09/22)
前回の記事のものに手を加えました。縦横の画面サイズ切り替えで表示を維持したり、コードからビューを追加してみたりしています。また、名前がアレだったので直しました。
プロジェクト一式ダウンロード
HorizontalPageScrollView.java
package fsoriented.sample.horizontalscroll; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.GestureDetector.OnGestureListener; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; /** * ページごとにスナップする横方向のスクロールビュー。 * * フリック(flingイベント)によって、隣のページにスナップする。 * ドラッグ(upイベント)によって、一番近いページにスナップする。 * * Gelleryでも似たようなことができそうなんだけど。。。 * * 内部にLinearLayout(horizontal)を持たせることを期待している。 * LinearLayout直下のビューをページとし、勝手にサイズを変更する。 * * 参考: * - http://www.adamrocker.com/blog/292/we-are-the-speaker-of-google-devfest-2010-japan.html * - http://blog.global-eng.co.jp/android/2011/02/18/horizontalscrollviewにイージングをつける方法/ * - http://android.keicode.com/basics/ui-custom-horizontalscrollview.php * * @author LapisCactus * */ public class HorizontalPageScrollView extends HorizontalScrollView implements OnGestureListener { /** フリックを検出するオブジェクト */ private GestureDetector detector; /** フリックとみなさない速度の閾値 */ private final float velocityThreshold = 100f; /** 現在のページ */ private int currentPage = 0; /** ページ遷移時に呼ばれるリスナー。nullなら呼ばない。 */ private OnPageChangeListener listener = null; /** * コンストラクタ * * @param context */ public HorizontalPageScrollView(Context context) { super(context); initialize(context); } /** * コンストラクタ * * @param context * @param attrs */ public HorizontalPageScrollView(Context context, AttributeSet attrs) { super(context, attrs); initialize(context); } // フリックを検出するオブジェクトを生成する private void initialize(Context context) { detector = new GestureDetector(context, this); this.setFadingEdgeLength(0); this.setHorizontalScrollBarEnabled(false); } /** * 現在表示されているページ番号を返す * * @return ページ番号 */ public int getCurrentPage() { return currentPage; } /** * 指定したページを表示する * * @param page * ページ番号 * @param event * ページ遷移イベントを発生させるかどうか */ public void setCurrentPage(int page, boolean event) { // サイズが確定していれば、表示位置を移動する int viewWidth = this.getWidth(); if (viewWidth != 0) { scrollTo(page * viewWidth, 0); } // 現在ページを更新する。サイズが未確定なら、確定時イベント(onLayout)で現在ページへ移動する currentPage = page; // ページ遷移イベントを送信する if (event && listener != null) { listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0)) .getChildAt(currentPage)); } } /** * ページ遷移時に呼ばれるリスナーを登録する。 * * @param listener */ public void setOnPageChangedListener(OnPageChangeListener listener) { this.listener = listener; } // ビューのサイズが変更されたときの処理 protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // ページの幅と高さを設定する int count = ((LinearLayout) getChildAt(0)).getChildCount(); for (int i = 0; i < count; i++) { ((LinearLayout) getChildAt(0)).getChildAt(i).setLayoutParams( new android.widget.LinearLayout.LayoutParams(w, h)); } } // レイアウトされたときの処理 // currentPageの適用はここで行う。 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); // カレントページに移動 int w = r - l; smoothScrollTo(currentPage * w, 0); } // 画面にタッチしたときの処理 @Override public boolean onTouchEvent(MotionEvent event) { // フリック判定を優先して行う if (detector.onTouchEvent(event)) return true; // フリックでなければ、指が離れたイベントを使用する switch (event.getAction()) { case MotionEvent.ACTION_UP: // もっとも近い境界へスナップする int currentx = this.getScrollX(); int viewWidth = this.getWidth(); int destPage = (currentx + viewWidth / 2) / viewWidth; smoothScrollTo(destPage * viewWidth, 0); if (currentPage != destPage) { currentPage = destPage; listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0)) .getChildAt(currentPage)); } return true; } // そのほかはデフォルト return super.onTouchEvent(event); } // フリック時の処理 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // フリックなら隣に移動 int currentx = this.getScrollX(); int viewWidth = this.getWidth(); if (velocityX < -velocityThreshold) { // 右ページ int destPage = currentx / viewWidth + 1; smoothScrollTo(destPage * viewWidth, 0); if (destPage < ((LinearLayout) getChildAt(0)).getChildCount()) { currentPage = destPage; listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0)) .getChildAt(currentPage)); } return true; } else if (velocityX > velocityThreshold) { // 左ページ int destPage = currentx / viewWidth; smoothScrollTo(destPage * viewWidth, 0); if (destPage >= 0 && destPage != currentPage) { currentPage = destPage; listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0)) .getChildAt(currentPage)); } return true; } return false; } // 不使用 public boolean onDown(MotionEvent e) { return false; } // 不使用 public void onLongPress(MotionEvent e) { } // 不使用 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } // 不使用 public void onShowPress(MotionEvent e) { } // 不使用 public boolean onSingleTapUp(MotionEvent e) { return false; } /** * フリックやドラッグにより、ページが遷移したときに呼ばれるコールバック定義 * * @author LapisCactus * */ public static interface OnPageChangeListener { /** * ページが遷移したときの処理 * * @param pageIndex * ページ番号(0~) * @param showing * 表示中のViewオブジェクト */ public abstract void onPageChanged(int pageIndex, View showing); } }
PR
スポンサード・リンク
この記事にコメントする
Re:参考にさせて頂きます
ありがとうございます。ソースコードはどうぞご自由にお使いください。
フリーソフト指向::開発日記 by LapisCactus