scrollview中停止滚动的监听

[补充]可以在主线程控制,特别注意

scrollView3.postDelayed(new Runnable() {

                @Override
                public void run() {
                    scrollView3.scrollTo(0, num * scrollItemHeight);
                }
            }, 500);
 if (mScrollX != x || mScrollY != y) 这个判断语句有没有通过是关键所在. 这也间接说明了, 在Activity 没初始化完成, ScrollView 对象获取的一些信息是不准确的, 直接导致了scrollTo() 方法无效.
package com.exmyth.ui.adapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextSwitcher;
import android.widget.TextView;

import com.sunskyjun.fwproject.R;
import com.sunskyjun.fwproject.adapter.PhotoScrollAdapter;
import com.sunskyjun.fwproject.ui.model.Entry;
import com.sunskyjun.fwproject.ui.model.ProductItem;
import com.sunskyjun.fwproject.ui.view.ObservableScrollView;
import com.sunskyjun.fwproject.ui.view.ObservableScrollView.OnScrollChangeListener;
import com.sunskyjun.fwproject.ui.view.ObservableScrollView.OnScrollStopListener;
import com.sunskyjun.fwproject.widgts.viewflow.CircleFlowIndicator;
import com.sunskyjun.fwproject.widgts.viewflow.ViewFlow;

public class ProductItemAdapter extends BaseAdapter{

    public class ScrollViewTouchListener implements OnTouchListener {

        private int lastY = 0;
        private int touchEventId = 16;
        private ObservableScrollView scrollView3;
        private int position;
        private TextView txtValue;
        
        public ScrollViewTouchListener(ObservableScrollView scrollView3,
                int position, TextView txtValue) {
            super();
            this.scrollView3 = scrollView3;
            this.position = position;
            this.txtValue = txtValue;
        }

        private Handler handler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                View scroller = (View) msg.obj;
                if (msg.what == touchEventId) {
                    if (lastY == scroller.getScrollY()) {
                        handleStop(scroller);
                    } else {
                        handler.sendMessageDelayed(handler.obtainMessage(
                                touchEventId, scroller), 5);
                        lastY = scroller.getScrollY();
                    }
                }
            }
        };

        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                handler.sendMessageDelayed(
                        handler.obtainMessage(touchEventId, v), 5);
            }
            return false;
        }

        private void handleStop(Object view) {
            ScrollView scroller = (ScrollView) view;
            int scrollY = scroller.getScrollY();
            final int num = (scrollY + scrollItemHeight / 2)/ scrollItemHeight;
            
            entryList.get(position -  1).setIndex(num);
            txtValue.setText(entryList.get(position-1).getValue()[num]);
            
//            scrollView3.scrollTo(0, num * scrollItemHeight);
            scrollView3.postDelayed(new Runnable() {

                @Override
                public void run() {
                    scrollView3.scrollTo(0, num * scrollItemHeight);
                }
            }, 500);
        }
        
    }
    public class ScrollStopListener implements OnScrollStopListener {
        private TextView txtValue;
        private int position;
        private ObservableScrollView scrollView3;
        public ScrollStopListener(ObservableScrollView scrollView3,TextView txtValue, int position) {
            this.scrollView3 = scrollView3;
            this.txtValue = txtValue;
            this.position = position;
        }
        @Override
        public void onScrollStop(ObservableScrollView observableScrollView) {
            int num = (scrollView3.getScrollY() + scrollItemHeight / 2)
                    / scrollItemHeight;
            scrollView3.scrollTo(0, num * scrollItemHeight);
            entryList.get(position -  1).setIndex(num);
            txtValue.setText(entryList.get(position-1).getValue()[num]);
        }
    }
    
    
    

    public class ScrollChangeListener implements OnScrollChangeListener {
        private ObservableScrollView scrollView1;
        private ObservableScrollView scrollView2;
        public ScrollChangeListener(ObservableScrollView scrollView1,ObservableScrollView scrollView2) {
            super();
            this.scrollView1 = scrollView1;
            this.scrollView2 = scrollView2;
        }
        @Override
        public void onScrollChanged(ObservableScrollView scrollView, int x,
                int y, int oldx, int oldy) {
            this.scrollView1.scrollTo(x, y);
            this.scrollView2.scrollTo(x, y);
        }
    }

    public class OnItemClickListener implements OnClickListener {
        private LinearLayout lytOption;
        private ImageView imgTrigger;
        public OnItemClickListener(LinearLayout lytOption, ImageView imgTrigger) {
            super();
            this.lytOption = lytOption;
            this.imgTrigger = imgTrigger;
        }
        @Override
        public void onClick(View v) {
            if(View.VISIBLE == this.lytOption.getVisibility()){
                this.lytOption.setVisibility(View.GONE);
                this.imgTrigger.setImageResource(R.drawable.fragment_product_detail_entry_combo_collapse);
            }
            else{
                this.lytOption.setVisibility(View.VISIBLE);
                this.imgTrigger.setImageResource(R.drawable.fragment_product_detail_entry_combo_expand);
            }
        }
    }

    private Context mContext;
    private LayoutInflater mInflater;
    private List<Entry> entryList = new ArrayList<Entry>();
    public ProductItem productItem = new ProductItem();
    private final int VIEW_TYPE_SUMMARY = 0;
    private final int VIEW_TYPE_COMBO = 1;
    private final int VIEW_TYPE_TEXT = 2;
//    private OnComboClickListener onComboClickListener;
    private int scrollItemHeight = 70;
    public ScrollView loadDetailLayout;
    
    public ProductItemAdapter(Context mContext) {
        super();
        this.mContext = mContext;
        this.mInflater = LayoutInflater.from(mContext);
    }

    public ProductItemAdapter(Context mContext,List<Entry> entryList) {
        super();
        this.mContext = mContext;
        this.mInflater = LayoutInflater.from(mContext);
        this.entryList = entryList;
    }

    public ProductItemAdapter(Context mContext, ProductItem productItem) {
        super();
        this.mContext = mContext;
        this.mInflater = LayoutInflater.from(mContext);
        this.productItem = productItem;
        this.entryList = productItem.getParams();
    }

    public ProductItemAdapter(Context mContext, List<Entry> entryList,
            int scrollItemHeight) {
        super();
        this.mContext = mContext;
        this.mInflater = LayoutInflater.from(mContext);
        this.entryList = entryList;
        this.scrollItemHeight = scrollItemHeight;
    }

    @Override
    public int getCount() {
        return (entryList.size()+1);
    }

    @Override
    public Object getItem(int position) {
        if(0 == position){
            return productItem;
        }
        return entryList.get(position - 1);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
    
    @Override
    public boolean isEnabled(int position) {
        if (0 == position) {
            return false;
        }
        if(Entry.PARAM_TYPE_TEXT.equals(entryList.get(position - 1).getType())){
            return false;
        }
        return super.isEnabled(position);
    }
    
    @Override
    public int getViewTypeCount() {
        return 3;
    }
    
    @Override
    public int getItemViewType(int position) {
        if(0 == position){
            return VIEW_TYPE_SUMMARY;
        }
        if(Entry.PARAM_TYPE_COMBO.equals(entryList.get(position - 1).getType())){
            return VIEW_TYPE_COMBO;
        }
        return VIEW_TYPE_TEXT;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        if(VIEW_TYPE_SUMMARY == getItemViewType(position)){
            view = getSummaryConvertView(position, convertView, parent);
        }
        else if(VIEW_TYPE_COMBO == getItemViewType(position)){
             view = getComboConvertView(position, convertView, parent);
        }
        else{
            view = getTextConvertView(position, convertView, parent);
        }
        return view;
    }

    private View getSummaryConvertView(int position, View convertView,
            ViewGroup parent) {
        View view = convertView;
        SummaryViewHolder holder = null;
        if (null == convertView) {
            view = mInflater.inflate(R.layout.fragment_product_detail_entry_summary, null);
            holder = new SummaryViewHolder();
            holder.txtProductName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_productName);
            holder.txtStandard = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_standard);
            holder.txtFeatureDesc = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_featureDesc);
            
            
            holder.viewFlow = (ViewFlow) view.findViewById(R.id.fragment_product_detail_entry_summary_viewflow);
            holder.viewFlow.setOnScrollListener(new ViewFlow.ScrollListener(){

                @Override
                public void onScrolling() {
                    loadDetailLayout.requestDisallowInterceptTouchEvent(true); 
                }

                @Override
                public void scrollEnd() {
                    loadDetailLayout.requestDisallowInterceptTouchEvent(false); 
                }});
            holder.circleFlowIndicator = (CircleFlowIndicator) view
                    .findViewById(R.id.fragment_product_detail_entry_summary_viewflowindic);
            
            view.setTag(holder);
        } else {
            holder = (SummaryViewHolder)view.getTag();
        }
        holder.txtProductName.setText(productItem.getProductName());
        holder.txtStandard.setText(productItem.getProductName());
        holder.txtFeatureDesc.setText(productItem.getFeatureDesc());
        
        if(null !=  productItem.getProductUrls() && 0 < productItem.getProductUrls().length){
            PhotoScrollAdapter photoscrollAdapter = new PhotoScrollAdapter(mContext,productItem.getProductUrls(), holder.viewFlow);
            photoscrollAdapter.setData(productItem.getProductUrls());
            holder.viewFlow.setAdapter(photoscrollAdapter);
            holder.viewFlow.setFlowIndicator(holder.circleFlowIndicator);
            holder.viewFlow.setTimeSpan(6000);
            holder.viewFlow.startAutoFlowTimer();
        }
        
        return view;
    }

    private View getComboConvertView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        ComboViewHolder holder = null;
        if (null == convertView) {
            view = mInflater.inflate(R.layout.fragment_product_detail_entry_combo, null);
            holder = new ComboViewHolder();
            holder.lytItem = (FrameLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_item);
            holder.txtName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_combo_name);
            holder.txtValue = (TextView) view.findViewById(R.id.fragment_product_detail_entry_combo_value);
            holder.imgTrigger = (ImageView) view.findViewById(R.id.fragment_product_detail_entry_combo_trigger);
            holder.lytOption = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_option);
            holder.lytScrollView1 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView1);
            holder.lytEnums1 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums1);
            holder.lytScrollView2 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView2);
            holder.lytEnums2 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums2);
            holder.lytScrollView3 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView3);
            holder.lytEnums3 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums3);
            view.setTag(holder);
        } else {
            holder = (ComboViewHolder)view.getTag();
        }
        Entry entry = entryList.get(position - 1);
        holder.txtName.setText(entry.getName());
        holder.txtValue.setText(entry.getValue()[entry.getIndex()]);
        holder.lytEnums3.setBackgroundColor(Color.TRANSPARENT);
        inflateScrollView(holder.lytEnums1,holder.lytEnums2,holder.lytEnums3,entry.getValue());
        holder.lytItem.setOnClickListener(new OnItemClickListener(holder.lytOption,holder.imgTrigger));
//        holder.lytScrollView1.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView2));
//        holder.lytScrollView2.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView1));
//        ScrollStopListener stopListener1 = new ScrollStopListener(holder.lytScrollView1, holder.lytScrollView2,holder.txtValue,position);
//        ScrollStopListener stopListener2 = new ScrollStopListener(holder.lytScrollView2, holder.lytScrollView1,holder.txtValue,position);
//        holder.lytScrollView1.setOnScrollStopListener(stopListener1);
//        holder.lytScrollView1.setOnScrollStopListener(stopListener2);
        
//        ScrollStopListener stopListener = new ScrollStopListener(holder.lytScrollView3,holder.lytScrollView1, holder.lytScrollView2,holder.txtValue,position);
        holder.lytScrollView3.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView1,holder.lytScrollView2));
        
        holder.lytScrollView3.scrollTo(0, entry.getIndex() * scrollItemHeight);
        
        holder.lytScrollView3.setOnTouchListener(new ScrollViewTouchListener(holder.lytScrollView3,position,holder.txtValue));
        return view;
    }
    
    private void inflateScrollView(LinearLayout lytEnums1,
            LinearLayout lytEnums2, LinearLayout lytEnums3, String[] value) {
        
        LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, scrollItemHeight);
        
        lytEnums1.removeAllViews();
        lytEnums2.removeAllViews();
        lytEnums3.removeAllViews();
        TextView blankBegin =  getTextView("",14);
        
        View viewStart = new View(mContext);
//        viewStart.getBackground().setAlpha(0);//0~255透明度值
        viewStart.setLayoutParams(param);
        lytEnums3.addView(viewStart);
        
        lytEnums1.addView(blankBegin);
        for(int i = 0; i < value.length; i++){
            TextView txt1 = getTextView(value[i],14,R.color.fragment_product_detail_entry_combo_enums1,R.color.white);
            TextView txt2 = getTextView(value[i],16,R.color.fragment_product_detail_entry_combo_enums2,R.color.fragment_product_detail_entry_combo_enums2bg);
            lytEnums1.addView(txt1);
            lytEnums2.addView(txt2);
            
            View view = new View(mContext);
//            view.getBackground().setAlpha(0);//0~255透明度值
            view.setLayoutParams(param);
            lytEnums3.addView(view);
        }
        TextView blankEnd =  getTextView("",14);
        lytEnums1.addView(blankEnd);
        
        View viewEnd = new View(mContext);
//        viewEnd.getBackground().setAlpha(0);//0~255透明度值 
        viewEnd.setLayoutParams(param);
        
        lytEnums3.addView(viewEnd);
    }
    
    private TextView getTextView(String text,int size) {
        return this.getTextView(text, size, R.color.fragment_product_detail_entry_combo_enums1, R.color.white);
    }
    private TextView getTextView(String text,int size, int txtColorId, int bgColorId) {
        TextView textView = new TextView(mContext);
        textView.setText(text);
        textView.setGravity(Gravity.CENTER);
        textView.setTextColor(mContext.getResources().getColor(txtColorId));
        textView.setBackgroundColor(mContext.getResources().getColor(bgColorId));
        textView.setLayoutParams(new TextSwitcher.LayoutParams( 
                LayoutParams.MATCH_PARENT, scrollItemHeight));
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
        return textView;
    }

    private View getTextConvertView(int position, View convertView,ViewGroup parent) {
        View view = convertView;
        TextViewHolder holder = null;
        if (null == convertView) {
            view = mInflater.inflate(R.layout.fragment_product_detail_entry_text, null);
            holder = new TextViewHolder();
            holder.txtName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_text_name);
            holder.txtValue = (TextView) view.findViewById(R.id.fragment_product_detail_entry_text_value);
            
            view.setTag(holder);
        } else {
            holder = (TextViewHolder)view.getTag();
        }
        final Entry entry = entryList.get(position - 1);
        holder.txtName.setText(entry.getName());
        holder.txtValue.setText(entry.getValue()[0]);
        return view;
    }
    
    public interface OnComboClickListener {
        public void onComboClick();
    }
    
    public class TextViewHolder{
        public TextView txtName;
        public TextView txtValue;
    }
    
    public class ComboViewHolder{
        public LinearLayout lytEnums3;
        public ObservableScrollView lytScrollView3;
        public LinearLayout lytEnums2;
        public LinearLayout lytEnums1;
        public ObservableScrollView lytScrollView2;
        public ObservableScrollView lytScrollView1;
        public LinearLayout lytOption;
        public FrameLayout lytItem;
        public ImageView imgTrigger;
        public TextView txtValue;
        public TextView txtName;
    }
    
    public class SummaryViewHolder {

        public CircleFlowIndicator circleFlowIndicator;
        public ViewFlow viewFlow;
        public TextView txtFeatureDesc;
        public TextView txtStandard;
        public TextView txtProductName;

    }
}

 http://stackoverflow.com/questions/3738965/android-detect-when-scrollview-has-finished-scrolling-and-bouncing-back

ScrollView 用的是scroller做的滑动, 但是 scroller 被scrollView隐藏了 你无法调用   你可以直接自己写个Scrollview 代码完全copy 自带的scrollView 然后把scroller暴露出来!

可以派生的。如果(mScroller.computeScrollOffset()返回false则表示滚动结束了。

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class ObservableScrollView extends ScrollView {

    private OnScrollChangeListener onScrollChangeListener = null;
    private OnScrollStopListener onScrollStopListener = null;

    private OnBorderListener onBorderListener = null;
    
    private boolean isBorderMonitor = false;

    private boolean isStart = false;

    public ObservableScrollView(Context context) {
        this(context, null);
        // TODO Auto-generated constructor stub
    }

    public ObservableScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initObservableScrollView();
        // this(context, attrs, com.android.internal.R.attr.scrollViewStyle);
        // TODO Auto-generated constructor stub
    }

    public ObservableScrollView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        initObservableScrollView();
        // TODO Auto-generated constructor stub
    }

    private void initObservableScrollView() {
        
    }
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //requestDisallowInterceptTouchEvent(disallowIntercept);
        //disallowIntercept=true不让父元素拦截元素;disallowIntercept=false,没有拦截
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

    public void setOnScrollStopListener(OnScrollStopListener onScrollStopListener) {
        this.onScrollStopListener = onScrollStopListener;
    }

    public void setOnScrollChangeListener(
            OnScrollChangeListener onScrollChangeListener) {
        this.onScrollChangeListener = onScrollChangeListener;
    }

    public void setOnBorderListener(OnBorderListener onBorderListener) {
        this.isBorderMonitor = true;
        this.onBorderListener = onBorderListener;
    }
    
    private void onScrollFinished(){
        if(null != onScrollStopListener){
            onScrollStopListener.onScrollStop(this);
        }
    }

    private void onScrollStart(int l, int t) {
        if (!isStart) {
            isStart = true;
            new ScrollListener(l,t).start();
        }
    }
    
    class ScrollListener extends Thread {
        int oldX, oldY;

        public ScrollListener(int oldx, int oldy) {
            this.oldX = oldx;
            this.oldY = oldy;
        }

        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (isStart) {
                int newX = getScrollX();
                int newY = getScrollY();
                if (newX == oldX && newY == oldY) {
                    onScrollFinished();
                    isStart = false;
                } else {
                    oldX = newX;
                    oldY = newY;
                }
            }
        }
    }
    
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        onScrollStart(l,t);
        super.onScrollChanged(l, t, oldl, oldt);
        if (onScrollChangeListener != null) {
            onScrollChangeListener.onScrollChanged(this, l, t, oldl, oldt);
        }
        if (isBorderMonitor) {
            if (0 == t && null != onBorderListener) {
                onBorderListener.onBottom();
            } else if ((getChildAt(0).getMeasuredHeight() <= t + getHeight())
                    && null != onBorderListener) {
                onBorderListener.onTop();
            }
        }
    }
                
    public interface OnScrollChangeListener {
        public void onScrollChanged(ObservableScrollView scrollView, int x, int y,
                int oldx, int oldy);
    }
    
    public interface OnScrollStopListener {
        public void onScrollStop(ObservableScrollView scrollView);
    }

    /**
     * OnBorderListener, Called when scroll to top or bottom
     * 
     * @author Myth 2013-5-22
     */
    public static interface OnBorderListener {

        /**
         * Called when scroll to bottom
         */
        public void onBottom();

        /**
         * Called when scroll to top
         */
        public void onTop();
    }

    public void setBorderMonitor(boolean isBorderMonitor) {
        this.isBorderMonitor = isBorderMonitor;
    }
}
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class ObservableScrollView extends ScrollView {

    private OnScrollChangeListener onScrollChangeListener = null;
    private OnScrollStopListener onScrollStopListener = null;

    private OnBorderListener onBorderListener = null;
    
    private boolean isBorderMonitor = false;

    private boolean isStart = false;

    public ObservableScrollView(Context context) {
        this(context, null);
        // TODO Auto-generated constructor stub
    }

    public ObservableScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initObservableScrollView();
        // this(context, attrs, com.android.internal.R.attr.scrollViewStyle);
        // TODO Auto-generated constructor stub
    }

    public ObservableScrollView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        initObservableScrollView();
        // TODO Auto-generated constructor stub
    }

    private void initObservableScrollView() {
        
    }
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //requestDisallowInterceptTouchEvent(disallowIntercept);
        //disallowIntercept=true不让父元素拦截元素;disallowIntercept=false,没有拦截
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

    public void setOnScrollStopListener(OnScrollStopListener onScrollStopListener) {
        this.onScrollStopListener = onScrollStopListener;
    }

    public void setOnScrollChangeListener(
            OnScrollChangeListener onScrollChangeListener) {
        this.onScrollChangeListener = onScrollChangeListener;
    }

    public void setOnBorderListener(OnBorderListener onBorderListener) {
        this.isBorderMonitor = true;
        this.onBorderListener = onBorderListener;
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(ev.getAction() == MotionEvent.ACTION_UP){
            // 手指松开.
            if (null != onScrollStopListener) {
                onScrollStopListener.onScrollStop(this);
            }
        }
        return super.onTouchEvent(ev);
    }
    
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (onScrollChangeListener != null) {
            onScrollChangeListener.onScrollChanged(this, l, t, oldl, oldt);
        }
        if (isBorderMonitor) {
            if (0 == t && null != onBorderListener) {
                onBorderListener.onBottom();
            } else if ((getChildAt(0).getMeasuredHeight() <= t + getHeight())
                    && null != onBorderListener) {
                onBorderListener.onTop();
            }
        }
    }
                
    public interface OnScrollChangeListener {
        public void onScrollChanged(ObservableScrollView scrollView, int x, int y,
                int oldx, int oldy);
    }
    
    public interface OnScrollStopListener {
        public void onScrollStop(ObservableScrollView scrollView);
    }

    /**
     * OnBorderListener, Called when scroll to top or bottom
     * 
     * @author Myth 2013-5-22
     */
    public static interface OnBorderListener {

        /**
         * Called when scroll to bottom
         */
        public void onBottom();

        /**
         * Called when scroll to top
         */
        public void onTop();
    }

    public void setBorderMonitor(boolean isBorderMonitor) {
        this.isBorderMonitor = isBorderMonitor;
    }
}
public class CustomScrollView extends ScrollView {
        
        private OnOverScrolledListener mOnOverScrolledListener = null;
        /**
         * @param context
         */
        public CustomScrollView(Context context) {
                super(context);
                // TODO Auto-generated constructor stub
        }

        /**
         * @param context
         * @param attrs
         */
        public CustomScrollView(Context context, AttributeSet attrs) {
                super(context, attrs);
                // TODO Auto-generated constructor stub
        }

        /**
         * @param context
         * @param attrs
         * @param defStyle
         */
        public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
                // TODO Auto-generated constructor stub
        }

        /* (non-Javadoc)
         * @see android.widget.ScrollView#arrowScroll(int)
         */
        @Override
        public boolean arrowScroll(int arg0) {
                // TODO Auto-generated method stub
                return super.arrowScroll(arg0);
        }

        /* (non-Javadoc)
         * @see android.widget.ScrollView#computeScroll()
         */
        @Override
        public void computeScroll() {
                // TODO Auto-generated method stub
                super.computeScroll();
        }

/**
         * @return the mOnOverScrolledListener
         */
        public OnOverScrolledListener getOnOverScrolledListener() {
                return mOnOverScrolledListener;
        }

        /**
         * @param mOnOverScrolledListener the mOnOverScrolledListener to set
         */
        public void setOnOverScrolledListener(OnOverScrolledListener mOnOverScrolledListener) {
                this.mOnOverScrolledListener = mOnOverScrolledListener;
        }

public interface OnOverScrolledListener{
        public abstract void onOverScrolled(View view, int scrollX, int scrollY, boolean clampedX, boolean clampedY);
    }
    
    /* (non-Javadoc)
     * @see android.widget.ScrollView#onOverScrolled(int, int, boolean, boolean)
     */
    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        // TODO Auto-generated method stub
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        if(mOnOverScrolledListener != null) {
            mOnOverScrolledListener.onOverScrolled(this, scrollX, scrollY, clampedX, clampedY);
        }
        Log.i("CustomScrollView", "===DBG:onOverScrolled");
    }

}
原文地址:https://www.cnblogs.com/exmyth/p/4523408.html