在4.2.2系统上ScrollView包含LinearLayout不滚动的问题

之前写过的一个APP每日美图,支持最低的API版本是7,也就是2.1以上系统都没有问题,过了一年多没有维护了,前不久用安装有最新的4.2.2系统的手机测试,发现瀑布流图墙不滚动了,这里面其实是自定义的ScrollView中OnTouchListenr捕获手指事件后分发流程的问题,早期的实现有好多方式,大致都是通过在ScrollView上实现自定义的onTouchListener,重写onTouch()方法,把事件进行捕获,但是在API17以上不知道为啥就总是失败,会被ScrollView里面的LinearLayout给屏蔽掉了。

我重新梳理了这部分流程,用实现onGestureListener的自定义ScrollView方式搞定,因为我还需要在这个里面得到手指滚动的方向,这就是曾经一度很流行的LazyScrollView的改进版,支持判断方向的版本,经我测试,在API7-17的版本上都能正常滚动和捕获事件。

下面是ScrollView代码部分,layout和Activity部分就不贴了,和大部分的实现类似。


package com.poyy.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;

public class MyScrollView extends ScrollView implements OnGestureListener {

private View view;
private Handler handler;
private GestureDetector mGestureDetector;

public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
protected int computeVerticalScrollOffset() {
return super.computeVerticalScrollOffset();
}
protected int computeVerticalScrollRange() {
return super.computeVerticalScrollRange();
}
public void getView(){
view = getChildAt(0);
if (view != null) init();
}

@SuppressLint(“HandlerLeak”)
private void init() {
mGestureDetector = new GestureDetector(this);

handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
if (view.getMeasuredHeight() <= getScrollY() + getHeight() + 150) { //Utils.doLog("onBottom: " + view.getMeasuredHeight() + " = " + getScrollY() + " + " + getHeight()); if (onScrollListener != null) { onScrollListener.onBottom(); } } else { if (onScrollListener != null) { onScrollListener.onScroll(1); } } break; case 2: if (getScrollY() < 50) { //Utils.doLog("onTop(): " + getScrollY()); if (onScrollListener != null) { onScrollListener.onTop(); } } if (onScrollListener != null) { onScrollListener.onScroll(2); } break; default: break; } } }; } // 定义在Activity里面实现的接口,用于回调接收来自scrollView的滚动事件 public interface OnScrollListener { void onBottom(); void onTop(); void onScroll(int direct); } private OnScrollListener onScrollListener; public void setOnScrollListener(OnScrollListener onScrollListener){ this.onScrollListener = onScrollListener; } @Override public boolean onTouchEvent(MotionEvent event) { /** * 此处是关键,onTouchEvent是ScrollView的手指动作处理事件 * 在这里面捕获事件后传递给GestureDector的onTouchEvent来处理 * 从而实现onFling, onScroll等事件的处理 */ mGestureDetector.onTouchEvent(event); return super.onTouchEvent(event); } //////////////////////// 以下为 onGestureListener 的方法 ////////////////////// public boolean onDown(MotionEvent e) { return false; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (velocityY < 0 ) { //手指向上,屏幕向上滑动 handler.sendMessageDelayed(handler.obtainMessage(1), 100); } else if (velocityY > 0) { //手指向下,屏幕向下滑动
handler.sendMessageDelayed(handler.obtainMessage(2), 200);
}
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;
}

}

新版的每日美图将在最近几天发布,改进一些bug并提升性能,后台service部分的逻辑也会大大改进。

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

Your email address will not be published. Required fields are marked *

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image