でも、やっぱりフレームワークの ListView とか ScrollView で on/off できないってことはないんじゃないのかな?と思って調べてみました。
ScrollView の onTouchEvent メソッドのなかでは、ちゃんと overScrollBy メソッドが呼ばれています。
android.wdiget.ScrollView
- public boolean onTouchEvent(MotionEvent ev) {
- ...
- case MotionEvent.ACTION_MOVE:
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- final float y = ev.getY(activePointerIndex);
- final int deltaY = (int) (mLastMotionY - y);
- mLastMotionY = y;
- final int oldX = mScrollX;
- final int oldY = mScrollY;
- final int range = getScrollRange();
- if (overScrollBy(0, deltaY, 0, mScrollY, 0, range,
- 0, mOverscrollDistance, true)) {
- // Break our velocity if we hit a scroll barrier.
- mVelocityTracker.clear();
- }
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
- final int pulledToY = oldY + deltaY;
- if (pulledToY < 0) {
- mEdgeGlowTop.onPull((float) deltaY / getHeight());
- if (!mEdgeGlowBottom.isFinished()) {
- mEdgeGlowBottom.onRelease();
- }
- } else if (pulledToY > range) {
- mEdgeGlowBottom.onPull((float) deltaY / getHeight());
- if (!mEdgeGlowTop.isFinished()) {
- mEdgeGlowTop.onRelease();
- }
- }
- if (mEdgeGlowTop != null
- && (!mEdgeGlowTop.isFinished() ||
- !mEdgeGlowBottom.isFinished())) {
- invalidate();
- }
- }
- }
- break;
if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true))
という部分です。
この overScrollBy メソッドの 8番目の引数がキモです。
overScrollBy メソッドのリファレンスには
maxOverScrollX Number of pixels to overscroll by in either direction along the X axis.
と書いてあります。つまり、これがオーバースクロールする距離ということです。
では、この mOverscrollDistance には何が入っているでしょう?
android.wdiget.ScrollView
- private void initScrollView() {
- mScroller = new OverScroller(getContext());
- setFocusable(true);
- setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
- setWillNotDraw(false);
- final ViewConfiguration configuration = ViewConfiguration.get(mContext);
- mTouchSlop = configuration.getScaledTouchSlop();
- mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
- mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
- mOverscrollDistance = configuration.getScaledOverscrollDistance();
- mOverflingDistance = configuration.getScaledOverflingDistance();
- }
このように、initScrollView メソッドのなかで、 mOverscrollDistance に ViewConfiguration の getScaledOverscrollDistance メソッドで取得した値を入れています。
では、 ViewConfiguration クラスを見てみましょう。
android.view.ViewConfiguration
- package android.view;
- import android.content.Context;
- import android.util.DisplayMetrics;
- import android.util.SparseArray;
- /**
- * Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
- */
- public class ViewConfiguration {
- ...
- /**
- * Max distance to overscroll for edge effects
- */
- private static final int OVERSCROLL_DISTANCE = 0;
- /**
- * Max distance to overfling for edge effects
- */
- private static final int OVERFLING_DISTANCE = 4;
- ...
- private ViewConfiguration(Context context) {
- final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- final float density = metrics.density;
- mEdgeSlop = (int) (density * EDGE_SLOP + 0.5f);
- mFadingEdgeLength = (int) (density * FADING_EDGE_LENGTH + 0.5f);
- mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
- mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
- mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
- mTouchSlop = (int) (density * TOUCH_SLOP + 0.5f);
- mPagingTouchSlop = (int) (density * PAGING_TOUCH_SLOP + 0.5f);
- mDoubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f);
- mWindowTouchSlop = (int) (density * WINDOW_TOUCH_SLOP + 0.5f);
- // Size of the screen in bytes, in ARGB_8888 format
- mMaximumDrawingCacheSize = 4 * metrics.widthPixels * metrics.heightPixels;
- mOverscrollDistance = (int) (density * OVERSCROLL_DISTANCE + 0.5f);
- mOverflingDistance = (int) (density * OVERFLING_DISTANCE + 0.5f);
- }
- ...
- public int getScaledOverscrollDistance() {
- return mOverscrollDistance;
- }
- ...
- }
なんと、OVERSCROLL_DISTANCE が 0 じゃないですか!
そりゃあオーバースクロールしないですよ。。。
AbsListView でもまったく同じことをしてるので、やっぱり mOverscrollDistance は 0 です。。。
はっ!ということは、単に overScrollBy メソッドを override して mOverscrollDistance 部分に 0 以外の値を入れればいいだけかも。
ということでやってみた。
- package yanzm.example.overscroll;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.ListView;
- public class MyListView extends ListView {
- private int mOverscrollDistance = 200;
- public MyListView(Context context) {
- super(context);
- }
- public MyListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public MyListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- @Override
- protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mOverscrollDistance, isTouchEvent);
- }
- }
overScrollBy メソッドを override して、第8引数に 0 以外の値(ここでは 200) を渡すだけ!
- <?xml version="1.0" encoding="utf-8"?>
- <yanzm.example.overscroll.MyListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:overScrollMode="always"
- android:overScrollHeader="#000000"
- android:overScrollFooter="#000000"
- />
この overScrollHeader と overScrollFooter がビローンってしたときの領域の色です。(リソースIDを指定すれば画像も可能 android:overScrollHeader="@drawable/icon" とか)
- package yanzm.example.overscroll;
- import android.app.ListActivity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- public class MyActivity extends ListActivity {
- String[] mData = {
- "Apple",
- "Banana",
- "Grape",
- "Lemon",
- "Melon",
- "Orange",
- "Peach",
- "Water Melon",
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.list);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, mData);
- setListAdapter(adapter);
- }
- }
調子にのりましたw
Android Bazaar and Conference 2011 で女子部セッションあります。
「DJモグタソのオールナイトヒャッハー」
# すっごい面白いよ。
HaHa omosiroidesune. Yoku mimasita!
返信削除