`

懒加载的Scrollview

阅读更多
要实现一个功能:当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(){
        	@Override
			public void handleMessage(Message msg) {
				// process incoming messages here
				super.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(){

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				switch (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() {
			
			@Override
			public void onTop() {
				// TODO Auto-generated method stub
				Log.d(tag,"------滚动到最上方------");
			}
			
			@Override
			public void onScroll() {
				// TODO Auto-generated method stub
				Log.d(tag,"没有到最下方,也不是最上方");
			}
			
			@Override
			public void onBottom() {
				// TODO Auto-generated method stub
				Log.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 + "");  
  
            }  
        });  
分享到:
评论
10 楼 xfx108 2016-01-11  
下面这行代码。 如果lazyScrollview里含有 水平滑动的组件,比如HorizontalScrollView .会与水平滑动的组件上下左右滑动冲突。  

//这个获得总的高度 
    public int computeVerticalScrollRange(){ 
        return super.computeHorizontalScrollRange(); 
    }
9 楼 wwwkp1236 2013-05-27  
楼主、用了懒加载嵌套listView和GridView后滚动条都不见了、求解决办法!
8 楼 gundumw100 2013-04-26  
feiyu0526 写道
为什么这个地方 scrollView.setOnScrollListener(new OnScrollListener() 让我定义成android.widget.AbsListView.OnScrollListener;这个类型 定义 后 onBottom就会出错了求解

scrollView  又不继承自absListView!
7 楼 feiyu0526 2013-04-26  
为什么这个地方 scrollView.setOnScrollListener(new OnScrollListener() 让我定义成android.widget.AbsListView.OnScrollListener;这个类型 定义 后 onBottom就会出错了求解
6 楼 feiyu0526 2013-04-26  
为什么这个地方 scrollView.setOnScrollListener(new OnScrollListener() 让我定义成android.widget.AbsListView.OnScrollListener;这个类型 定义 后 onBottom就会出错了求解
5 楼 崮rz教隍 2012-09-19  
学习了。!!
4 楼 hlyaowan 2012-06-16  
非常感谢楼主啊,很重要的东西
3 楼 蓝桥魔兽 2012-05-23  
  学习了,多谢!!!!!
2 楼 Samanoseky 2011-11-24  
太感谢了...   
1 楼 llty 2011-09-25  
顶  学习 、。。。。

相关推荐

    scrollview懒加载

    "ScrollView懒加载"是一个重要的优化技术,主要用于处理数据量大或者资源占用高的场景,如图片或者视图数组。在这个场景中,我们不一次性加载所有内容,而是仅在用户滚动到可视区域时才加载相应的子视图,以此减少...

    Android代码-应用模块化和懒加载在 Instagram 中的实现

    Ig-Lazy-Module-Loader This library helps with loading modules (features) in Android apps on demand, whenever needed. Before this library can be used a module needs to be compiled to a separate jar/...

    Android做的一个滑动到底部自动加载

    在提供的" douBanList(滚动到底部加载新的,软缓存,懒加载)"文件中,可能包含了实现上述功能的代码示例,包括网络请求、数据解析、适配器更新等方面的实现细节。通过研究这个代码,你可以更深入地理解如何在...

    UGUI Super ScrollView 2.4.2.rar

    4. **预加载和懒加载**:自动预加载相邻内容,同时提供懒加载机制,只在需要时加载数据,避免一次性加载过多资源导致的性能问题。 5. **事件处理**:提供了简便的事件监听和处理机制,方便开发者在用户交互时执行...

    IOS图片自适应大小后绘制在Scrollview上

    8. 可能还包含了一个懒加载机制,当ScrollView滚动到新的图片时,加载并显示新图片。 通过这样的实现,用户可以在ScrollView中平滑地滚动浏览等比缩放的图片,提供良好的用户体验。对于大型图片集或需要自定义滚动...

    cocos2dx scrollview优化

    1.2 内容预加载:预加载ScrollView内可能被滚动到的可视区域的内容,避免用户滚动时加载新内容导致的卡顿。 二、懒加载与可见性检查 2.1 懒加载:仅在需要时才加载或创建子节点。例如,当一个节点进入可视区域时才...

    scrollView实现下拉刷新

    3. **性能优化**:在处理大量数据或复杂视图时,要考虑到性能问题,避免在滚动时进行昂贵的操作,可以利用异步加载或懒加载技术。 4. **动画平滑**:确保刷新状态的切换和自定义视图的动画过渡平滑自然,提升用户...

    cocos creator ScrollView列表优化

    可以采用懒加载策略,只在滚动到某个列表项即将进入视口时才加载对应的资源,离开视口后释放。这样可以显著减少初始加载时间和内存占用。 3. **资源优化**:对于列表项中的图片和纹理,可以使用精灵表(Sprite ...

    scrollView

    2. **懒加载**:对于需要加载大量数据的情况,可以实现懒加载机制,即只在需要时才加载和渲染子视图。这样可以减少启动时的内存占用,并且在用户滚动时提供更好的响应速度。 3. **优化视图层次**:尽量减少...

    SuperScrollView 2.4.2

    而SuperScrollView通过批量渲染和懒加载策略,显著降低了内存占用和CPU消耗,确保在大规模数据展示时依然保持流畅的滚动体验。它智能地只加载可视区域内的元素,非可视区域的内容则会在需要时按需加载,大大提升了...

    UGUI Super ScrollView v2.4.4

    3. **动态加载**:通过懒加载技术,只有当内容进入可视区域时才会加载,降低了内存占用,提高了应用性能。 4. **缓动效果**:内置多种缓动动画,可以为滚动操作添加平滑过渡,提升用户体验。 5. **事件系统**:...

    scrollview

    4. **性能优化**:通过合理的数据加载策略(如懒加载)和视图复用来提高滚动流畅度。 5. **解决滚动冲突**:当多个滚动视图在同一层级时,正确处理它们之间的滚动事件传递。 学习和研究 LTScrollView-master 这样的...

    iOS学习——ScrollView图片轮播和同类控件优先级问题-代码

    7. 注意事项:为了优化性能,避免一次性加载所有图片,可以使用UIImageView的imageWithContentsOfFile:或网络加载库(如SDWebImage)实现图片的懒加载。此外,还要注意处理ScrollView的contentInset和contentOffset...

    IOS ScrollView自动翻页

    - 对于大量内容的ScrollView,应使用视图懒加载策略,只有当页面即将显示时才加载对应的视图内容,以减少内存占用和提高滚动流畅性。 - 如果使用UIPageViewController,注意配置其`spineLocation`属性以优化内存...

    ScrollView解决列表卡顿.zip

    这种技术称为懒加载,可以显著降低内存占用和CPU负荷。当用户滚动到新的区域,通过监听ScrollView的ScrollPosition变化,判断是否需要加载新内容。 优化策略3:降低精灵的分辨率和纹理大小 对于列表中的每个元素,...

    ScrollView+LinearLayout 仿Listview 效果

    为了提高性能,可以考虑在数据较少时使用这种方式,或者在用户滚动时动态加载和移除条目,类似ListView的懒加载机制。 6. **注意滚动性能**: 由于ScrollView自身并不优化滚动性能,如果内容过多,滚动可能会变得...

    图片多选显示在scrollView

    综上所述,实现“图片多选显示在scrollView”涉及到的技术点包括:使用Photos Framework进行图片选择,利用`UIImagePickerController`实现多选功能,通过`UIScrollView`展示滚动图片,子视图的布局和懒加载策略,...

    UGUI Super ScrollView 2.4.3.zip

    3. **动态加载**:可以实现内容的懒加载,只在需要时加载可见部分,减少内存占用和初始化时间。 4. **复用池**:通过对象复用机制,降低创建和销毁对象带来的开销,提高性能。 5. **事件系统**:提供丰富的事件回调...

    ScrollView循环滚动

    例如,可以使用ViewStub或懒加载策略减少不必要的视图初始化。 7. **动画效果**:为了让用户体验更好,可以添加一些动画效果,如淡入淡出,使得滚动更加自然。 8. **数据绑定**:如果内容是动态数据,如列表项,...

Global site tag (gtag.js) - Google Analytics