懒加载的Scrollview

来源:互联网 发布:电子人单片机开发板 编辑:程序博客网 时间:2024/05/21 08:02
要实现一个功能:当Scrollview滑动到最底端的时候需要触发事件加载其他数据。很多人都以为ScrollView可以像ListViev那样setOnScrollListener,其实沒那么简单,因为ScrollView压根就没有该接口,在baidu上兜了一圈没有找到合适的答案,没办法只能google去了,居然一下子解决了这个问题,还是老外比较牛,呵呵,这是我访问的网址:
http://stackoverflow.com/questions/2864563/how-do-i-know-that-the-scrollview-is-already-scrolled-to-the-bottom

注意,如果数据不满一页的话,会执行onBottom方法!通常要使用懒加载的话数据都会超过一页,所以我沒仔细考虑这个问题!

我把ScrollView封装成类了,源码如下:
package com.ql.view;import android.content.Context;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.ScrollView; public class LazyScrollView extends ScrollView{private static final String tag="LazyScrollView";private Handler handler;private View view;public LazyScrollView(Context context) {super(context);// TODO Auto-generated constructor stub}public LazyScrollView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}public LazyScrollView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stub}//这个获得总的高度public int computeVerticalScrollRange(){return super.computeHorizontalScrollRange();}public int computeVerticalScrollOffset(){return super.computeVerticalScrollOffset();}private void init(){this.setOnTouchListener(onTouchListener);handler=new Handler(){        @Overridepublic void handleMessage(Message msg) {// process incoming messages heresuper.handleMessage(msg);switch(msg.what){case 1:if(view.getMeasuredHeight() <= getScrollY() + getHeight()) {if(onScrollListener!=null){onScrollListener.onBottom();}}else if(getScrollY()==0){if(onScrollListener!=null){onScrollListener.onTop();}}else{if(onScrollListener!=null){onScrollListener.onScroll();}}break;default:break;}}        };}  OnTouchListener onTouchListener=new OnTouchListener(){@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN:break;case MotionEvent.ACTION_UP:if(view!=null&&onScrollListener!=null){handler.sendMessageDelayed(handler.obtainMessage(1), 200);}break;default:break;}return false;}        };        /**     * 获得参考的View,主要是为了获得它的MeasuredHeight,然后和滚动条的ScrollY+getHeight作比较。     */    public void getView(){    this.view=getChildAt(0);    if(view!=null){    init();    }    }        /**     * 定义接口     * @author admin     *     */    public interface OnScrollListener{    void onBottom();    void onTop();    void onScroll();    }    private OnScrollListener onScrollListener;    public void setOnScrollListener(OnScrollListener onScrollListener){    this.onScrollListener=onScrollListener;    }}


用的时候也很简单,通常这样使用:
scrollView=(LazyScrollView)findViewById(R.id.scrollView);        scrollView.getView();        scrollView.setOnScrollListener(new OnScrollListener() {@Overridepublic void onTop() {// TODO Auto-generated method stubLog.d(tag,"------滚动到最上方------");}@Overridepublic void onScroll() {// TODO Auto-generated method stubLog.d(tag,"没有到最下方,也不是最上方");}@Overridepublic void onBottom() {// TODO Auto-generated method stubLog.d(tag,"------滚动到最下方------");}});

感激我吧,我呕心沥血才出来了这么个类。呵呵。

重写onScrollChanged()的模式
import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.widget.ScrollView;/** * BorderScrollView * <ul> * <li>onTop and onBottom response ScrollView</li> * <li>you can {@link #setOnBorderListener(OnBorderListener)} to set your top and bottom response</li> * </ul> *  * @author trinea@trinea.cn 2013-5-21 */public class BorderScrollView extends ScrollView {    private OnBorderListener onBorderListener;    private View             contentView;    public BorderScrollView(Context context) {        super(context);    }    public BorderScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public BorderScrollView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    @Override    protected void onScrollChanged(int x, int y, int oldx, int oldy) {        super.onScrollChanged(x, y, oldx, oldy);        doOnBorderListener();    }    public void setOnBorderListener(final OnBorderListener onBorderListener) {        this.onBorderListener = onBorderListener;        if (onBorderListener == null) {            return;        }        if (contentView == null) {            contentView = getChildAt(0);        }    }    /**     * OnBorderListener, Called when scroll to top or bottom     *      * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-22     */    public static interface OnBorderListener {        /**         * Called when scroll to bottom         */        public void onBottom();        /**         * Called when scroll to top         */        public void onTop();    }    private void doOnBorderListener() {        if (contentView != null && contentView.getMeasuredHeight() <= getScrollY() + getHeight()) {            if (onBorderListener != null) {                onBorderListener.onBottom();            }        } else if (getScrollY() == 0) {            if (onBorderListener != null) {                onBorderListener.onTop();            }        }    }}


顺便记一下老外使用fullScroll的做法。当然也可以直接fullScroll而不需要放入post()。
 scrollView.post(new Runnable() {            @Override            public void run() {            scrollView.fullScroll(View.FOCUS_DOWN);            }        });

只要把fullScroll改成scrollTo就可以做一个书签效果了:
http://yangsongjing.iteye.com/blog/1855063

Android-ObservableScrollView
https://github.com/ksoichiro/Android-ObservableScrollView

在HorizontalScrollView中使用ScrollView相互影响问题的解决办法:
On my ScrollView, I needed to override the onInterceptTouchEvent method to only intercept the touch event if the Y motion is > the X motion. It seems like the default behavior of a ScrollView is to intercept the touch event whenever there is ANY Y motion. So with the fix, the ScrollView will only intercept the event if the user is deliberately scrolling in the Y direction and in that case pass off the ACTION_CANCEL to the children.

Here is the code for my Scroll View class that contains the HorizontalScrollView:
public class CustomScrollView extends ScrollView {    private GestureDetector mGestureDetector;    View.OnTouchListener mGestureListener;    public CustomScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        mGestureDetector = new GestureDetector(new YScrollDetector());        setFadingEdgeLength(0);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);    }    // Return false if we're scrolling in the x direction      class YScrollDetector extends SimpleOnGestureListener {        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            if(Math.abs(distanceY) > Math.abs(distanceX)) {                return true;            }            return false;        }    }}


android监听ScrollView滑动停止

在ScrollView中嵌入GridView
http://fariytale.iteye.com/blog/1420254
做android程序开发的都知道,不能在一个拥有Scrollbar的组件中嵌入另一个拥有Scrollbar的组件,因为这不科学,会混淆滑动事件,导致只显示一到两行数据。那么就换一种思路,首先让子控件的内容全部显示出来,禁用了它的滚动。如果超过了父控件的范围则显示父控件的scrollbar滚动显示内容,思路是这样,一下是代码。
具体的方法是自定义GridView组件,继承自GridView。重载onMeasure方法:
public class MyGridView extends GridView{public MyGridView(android.content.Context context,android.util.AttributeSet attrs){super(context, attrs);}/** * 设置不滚动 */public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec, expandSpec);}}

其中onMeasure函数决定了组件显示的高度与宽度;
makeMeasureSpec函数中第一个函数决定布局空间的大小,第二个参数是布局模式
MeasureSpec.AT_MOST的意思就是子控件需要多大的控件就扩展到多大的空间
之后在ScrollView中添加这个组件就OK了,同样的道理,ListView也适用。

滚动监听的ScrollView
import android.content.Context;import android.util.AttributeSet;import android.widget.ScrollView;public class NotifyingScrollView extends ScrollView {    public interface OnScrollChangedListener {        void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt);    }    private OnScrollChangedListener mOnScrollChangedListener;    public NotifyingScrollView(Context context) {        super(context);    }    public NotifyingScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public NotifyingScrollView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        if (mOnScrollChangedListener != null) {            mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt);        }    }    public void setOnScrollChangedListener(OnScrollChangedListener listener) {        mOnScrollChangedListener = listener;    }}



ScrollView也可以实现OnTouchListener来监听是否滑动到最底部
import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.widget.ScrollView;import android.app.Activity;/** * Demo描述: * 监听ScrollView滑动到顶端和底部 *  * 注意事项: * 1 mScrollView.getChildAt(0).getMeasuredHeight()表示: *   ScrollView所占的高度.即ScrollView内容的高度.常常有一 *   部分内容要滑动后才可见,这部分的高度也包含在了 *   mScrollView.getChildAt(0).getMeasuredHeight()中 *    * 2 view.getScrollY表示: *   ScrollView顶端已经滑出去的高度 *    * 3 view.getHeight()表示: *   ScrollView的可见高度 *    */public class MainActivity extends Activity {    private ScrollView mScrollView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        init();    }    private void init(){        mScrollView=(ScrollView) findViewById(R.id.scrollView);        mScrollView.setOnTouchListener(new TouchListenerImpl());    }    private class TouchListenerImpl implements OnTouchListener{        @Override        public boolean onTouch(View view, MotionEvent motionEvent) {            switch (motionEvent.getAction()) {            case MotionEvent.ACTION_DOWN:                 break;            case MotionEvent.ACTION_MOVE:                 int scrollY=view.getScrollY();                 int height=view.getHeight();                 int scrollViewMeasuredHeight=mScrollView.getChildAt(0).getMeasuredHeight();                 if(scrollY==0){                        System.out.println("滑动到了顶端 view.getScrollY()="+scrollY);                    }                 if((scrollY+height)==scrollViewMeasuredHeight){                        System.out.println("滑动到了底部 scrollY="+scrollY);                        System.out.println("滑动到了底部 height="+height);                        System.out.println("滑动到了底部 scrollViewMeasuredHeight="+scrollViewMeasuredHeight);                    }                break;             default:                break;            }            return false;        }             };}


在滚动的视图观测滚动事件的Android库:Android-ObservableScrollView
http://www.open-open.com/lib/view/open1415854429070.html


import android.content.Context;  import android.util.AttributeSet;  import android.widget.ScrollView;    public class ObservableScrollView extends ScrollView {        private ScrollViewListener scrollViewListener = null;        public ObservableScrollView(Context context) {          super(context);      }        public ObservableScrollView(Context context, AttributeSet attrs,              int defStyle) {          super(context, attrs, defStyle);      }        public ObservableScrollView(Context context, AttributeSet attrs) {          super(context, attrs);      }        public void setScrollViewListener(ScrollViewListener scrollViewListener) {          this.scrollViewListener = scrollViewListener;      }        @Override      protected void onScrollChanged(int x, int y, int oldx, int oldy) {          super.onScrollChanged(x, y, oldx, oldy);          if (scrollViewListener != null) {              scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);          }      }    }  


网上说的方法乱七八糟,能用的就是自己算高度,其实sdk-9中,ScrollView已经加入了一个方法,能监听到是否已经不能滚动,稍加处理,就可以监听是否滑到底部了。

先上自定义的ScrollView方法:
import android.content.Context;  import android.util.AttributeSet;  import android.widget.ScrollView;    public class BottomScrollView extends ScrollView {        private OnScrollToBottomListener onScrollToBottom;            public BottomScrollView(Context context, AttributeSet attrs) {          super(context, attrs);      }        public BottomScrollView(Context context) {          super(context);      }        @Override      protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,              boolean clampedY) {          super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);          if(scrollY != 0 && null != onScrollToBottom){              onScrollToBottom.onScrollBottomListener(clampedY);          }      }            public void setOnScrollToBottomLintener(OnScrollToBottomListener listener){          onScrollToBottom = listener;      }        public interface OnScrollToBottomListener{          public void onScrollBottomListener(boolean isBottom);      }  }  

调用方法:
BottomScrollView scroll = (BottomScrollView)findViewById(R.id.id_scroll);          scroll.setOnScrollToBottomLintener(new OnScrollToBottomListener() {                            @Override              public void onScrollBottomListener(boolean isBottom) {                  // TODO Auto-generated method stub                  Log.e("SCROLLVIEW", isBottom + "");                }          });  
0 0
原创粉丝点击