在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