from : http://gundumw100.iteye.com/blog/1164066
要实现一个功能:当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,"------滚动到最下方------");
- }
- });
感激我吧,我呕心沥血才出来了这么个类。呵呵。
顺便记一下老外使用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 + "");
- }
- });