でも、やっぱりフレームワークの 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!
返信削除