Đây là nỗ lực của tôi tại thư viện hoạt động với dọc ScrollViews
.
Nó sử dụng trường hợp riêng của mình là GestureDetector
và cấp dữ liệu với MotionEvents
từ onInterceptTouchEvent
.
Khi máy dò cử chỉ nhận dạng cuộn, chúng tôi xác định xem nó có nằm ngang hay dọc và khóa theo hướng cho đến khi cử chỉ kết thúc. Điều này tránh di chuyển chéo.
Nếu đó là cuộn ngang, onInterceptTouchEvent
sẽ trả về true để các sự kiện chuyển động trong tương lai được chuyển đến thừa kế Gallery.onTouchEvent
để thực hiện cuộn thực tế.
Máy dò cử chỉ riêng của Gallery
(mGestureDetector
trong Gallery.java
) không nhận được tất cả sự kiện chuyển động và do đó đôi khi báo cáo các cuộn giấy bất ngờ khiến thư viện nhảy xung quanh. Tôi đã đặt trong một hack khó chịu mà loại bỏ những người.
Mã:
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.Gallery;
public class BetterGallery extends Gallery {
/* This gets set when we detect horizontal scrolling */
private boolean scrollingHorizontally = false;
/* This gets set during vertical scrolling. We use this to avoid detecting
* horizontal scrolling when vertical scrolling is already in progress
* and vice versa. */
private boolean scrollingVertically = false;
/* Our own gesture detector, Gallery's mGestureDetector is private.
* We'll feed it with motion events from `onInterceptTouchEvent` method. */
private GestureDetector mBetterGestureDetector;
public BetterGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mBetterGestureDetector = new GestureDetector(new BetterGestureListener());
}
public BetterGallery(Context context, AttributeSet attrs) {
super(context, attrs);
mBetterGestureDetector = new GestureDetector(new BetterGestureListener());
}
public BetterGallery(Context context) {
super(context);
mBetterGestureDetector = new GestureDetector(new BetterGestureListener());
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// Limit velocity so we don't fly over views
return super.onFling(e1, e2, 0, velocityY);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Documentation on this method's contract:
// http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
// Reset our scrolling flags if ACTION_UP or ACTION_CANCEL
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
scrollingHorizontally = false;
scrollingVertically = false;
}
// Feed our gesture detector
mBetterGestureDetector.onTouchEvent(ev);
// Intercept motion events if horizontal scrolling is detected
return scrollingHorizontally;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// Hack: eat jerky scrolls caused by stale state in mGestureDetector
// which we cannot directly access
if (Math.abs(distanceX) > 100) return false;
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Reset our scrolling flags if ACTION_UP or ACTION_CANCEL
switch(event.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
scrollingHorizontally = false;
scrollingVertically = false;
}
super.onTouchEvent(event);
return scrollingHorizontally;
}
private class BetterGestureListener implements GestureDetector.OnGestureListener {
@Override
public boolean onDown(MotionEvent arg0) {
return false;
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (scrollingHorizontally || scrollingVertically) {
// We already know we're scrolling, ignore this callback.
// This avoids changing scrollingHorizontally/scrollingVertically
// flags mid-scroll.
return false;
}
scrollingHorizontally |= Math.abs(distanceX) > Math.abs(distanceY);
// It's a scroll, and if it's not horizontal, then it has to be vertical
scrollingVertically = !scrollingHorizontally;
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
return false;
}
}
}
Cảnh báo: Từ "Better" trong tên lớp có khả năng gây nhầm lẫn!
Cập nhật:
Quên đề cập đến, tôi cũng đã thiết lập hoạt động để chuyển tiếp onTouchEvent
của nó vào thư viện:
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGallery.onTouchEvent(event);
}
Cập nhật 2:
Tôi đã thực hiện một số cải tiến cho mã này và đặt nó lên trên bitbucket. Ngoài ra còn có một ứng dụng ví dụ. Nó chứng tỏ rằng widget này có vấn đề với ListView như đứa trẻ: -/
Cập nhật 3:
Switched Gallery
-HorizontalScrollView
là lớp cơ sở cho widget tùy chỉnh của tôi. More on this here. Flings hoạt động, ListViews và ExpandableListViews khi trẻ em làm việc, được thử nghiệm trên Android 1.6, 2.2, 2.3.4. Hành vi của nó bây giờ khá gần với ứng dụng của Google, IMO.
Cập nhật 4:
Google đã công bố ViewPager!
hey nourdine đã bao giờ bạn có được điều này cố định? bạn đã sử dụng câu trả lời nào? – MikeIsrael