(二)android下拉刷新的两种方式之设置topMargin

这种方法的原理就是Layout包含loadingLayout显示加载布局和Listview显示数据布局,通过onTouch监听下拉时间,然后设置这个Layout的顶距和loadingLayout的动画来达到刷新的效果。

布局文件xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <RelativeLayout android:id="@+id/test_parent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        >
         // loadingLayout显示刷新的效果
        <LinearLayout
            android:id="@+id/test_top"
            android:layout_width="fill_parent"
            android:layout_height="50dip"
            android:background="#cc3366"
            android:layout_alignParentTop="true" 
            android:layout_alignParentLeft="true"
            android:orientation="horizontal">
            
              <ImageView
                android:id="@+id/test_image"
                android:layout_width="40dip"
                android:layout_height="40dip"
                android:layout_marginLeft="30dip"
                android:layout_marginTop="5dip"
                android:src="@drawable/indicator_arrow" />

            <TextView android:id="@+id/test_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="正在刷新......"
                android:layout_marginLeft="30dip"
                android:layout_marginTop="15dip" />

          

        </LinearLayout>// end
        // 显示ListView 数据
        <ListView android:id="@+id/test_listview"
            android:layout_below="@+id/test_top"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </ListView>// end
        // 底部菜单 
        <RelativeLayout android:id="@+id/test_bottom"
            android:layout_width="fill_parent"
            android:layout_height="50dip"
            android:layout_alignParentBottom="true"
            android:background="#ccff99"
            android:visibility="gone" >

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
        </RelativeLayout>
    </RelativeLayout>

</LinearLayout>

下面是实现的一个activity类,当然也可以设置成自己的自定义类,以后用方便。

public class TestPullToRefreshActivity extends Activity implements OnScrollListener,OnTouchListener {
	private static final String TAG = "TestPullToRefreshActivity";
	private ListView listview;
	// loadingLayout 
	private LinearLayout  topLayout;
	// 底部菜单
	private RelativeLayout bottomLayout;
	// 整个layout
	private RelativeLayout parentLayout ; 
	private MarginLayoutParams parentLayoutParams;
	// 整个高度
	private int parentLayoutHeight;
	private int allViewheight;
	private boolean ableToPull = true;
	private int hideHeaderHeight;
	// 下拉状态
	private static final int status_pull_to_refresh = 0;
	// 释放立即刷新
	private static final int status_refresh_to_refresh = 1;
	// 正在刷新
	private static final int status_refreshing = 2;
	// 刷新完成
	private static final int status_refresh_finished= 3;
	// 当前状态
	private int currentStatus = status_refresh_finished;
	private static final int status_top_start = 1;
	private static final int status_top_stop = 0;
	private int topStatus = status_top_start;
	
	private ArrayAdapter<String> adapter;
	private List<String> data = new ArrayList<String>();
	

	private ImageView imageview;
	private TextView textview;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_test_listview);
		
		listview = (ListView)this.findViewById(R.id.test_listview);
		topLayout = (LinearLayout)this.findViewById(R.id.test_top);
		bottomLayout = (RelativeLayout)this.findViewById(R.id.test_bottom);
		parentLayout = (RelativeLayout)this.findViewById(R.id.test_parent);
		parentLayoutHeight = parentLayout.getHeight();
		parentLayoutParams = (MarginLayoutParams) parentLayout.getLayoutParams();
		ViewTreeObserver vto = topLayout.getViewTreeObserver(); 
		vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
			private boolean hasMeasured = false;
			public boolean onPreDraw() { 
				if (!hasMeasured)
	            {
					 hideHeaderHeight = topLayout.getMeasuredHeight(); 
					 Log.i(TAG, "hideHeaderHeight-->"+hideHeaderHeight);
					 hasMeasured = true;
	            }
				return true; 
			} 
		});
		ViewTreeObserver vto2 = listview.getViewTreeObserver(); 
		vto2.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
			private boolean hasMeasured = false;
			public boolean onPreDraw() { 
				if (!hasMeasured)
	            {
					 allViewheight = listview.getMeasuredHeight(); 
					 Log.i(TAG, "allViewheight-->"+allViewheight);
					 hasMeasured = true;
	            }
				return true; 
			} 
		});
		
		
		Log.i(TAG, "parentLayoutParams.height:"+parentLayoutParams.height);
		Log.i(TAG, "hideHeaderHeight:"+hideHeaderHeight);
		allViewheight = ViewConfiguration.get(TestPullToRefreshActivity.this).getScaledTouchSlop(); 
		data.add("A-1---");data.add("A-2---");data.add("A-3---");data.add("A-4---");data.add("A-5---");
		data.add("A----");data.add("A----");data.add("A----");data.add("A----");data.add("A----");
		data.add("A----");data.add("A----");data.add("A----");data.add("A----");
		adapter= new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1,data);
		listview.setAdapter(adapter);
		listview.setOnScrollListener(this);
		// listview.setOnTouchListener(this);
		
		imageview = (ImageView)this.findViewById(R.id.test_image);
		textview = (TextView)this.findViewById(R.id.test_text);
	}
	

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//Log.i(TAG, "onScrollStateChanged()");
	}
	  
	private int concurrentVisiableItem = 0;
	
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		Log.v(TAG, "Scroll>>>first: " + firstVisibleItem + ", visible: " + visibleItemCount + ", total: " + totalItemCount);  
		Log.v(TAG, "concurrentVisiableItem:"+concurrentVisiableItem);
		
		Log.w(TAG, "msg");
		if(visibleItemCount > 3){
			// 上滑
			if(concurrentVisiableItem > firstVisibleItem){
				if(bottomLayout.getVisibility()==View.VISIBLE)
	            	bottomLayout.setVisibility(View.GONE);
				concurrentVisiableItem = firstVisibleItem;
			}
			// 下滑
			if(concurrentVisiableItem < firstVisibleItem){
				if(bottomLayout.getVisibility()==View.GONE)
	         	     bottomLayout.setVisibility(View.VISIBLE);
	           	concurrentVisiableItem = firstVisibleItem;
			}
		}
		
//		  if(firstVisibleItem==0){  
//              Log.e(TAG, "滑到顶部");  
//          }  
//          if(visibleItemCount+firstVisibleItem==totalItemCount){  
//              Log.e(TAG, "滑到底部");  
//              if(bottomLayout.getVisibility()==View.GONE){
//            	  bottomLayout.setVisibility(View.VISIBLE);
//              }
//          } 
	}

	private float mY = 0;
	private float mX = 0;
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		setIsAbleToPull(event);
		if(ableToPull){
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:Log.i(TAG, "ACTION_DOWN()---------");
				mY = event.getRawY();
				Log.i(TAG, "mY:"+mY);
				Log.i(TAG, "ACTION_DOWN()------------");
				break;
			case MotionEvent.ACTION_MOVE:Log.i(TAG, "ACTION_MOVE()-----------");
				float yMove = event.getRawY();
				int distance = (int) (yMove - mY);
				Log.i(TAG, "distance:"+distance);
				Log.i(TAG, "hideHeaderHeight:"+hideHeaderHeight);
				Log.i(TAG, " parentLayoutParams.topMargin:"+ parentLayoutParams.topMargin);
				if( distance>0 && parentLayoutParams.topMargin >= 0){
					return false;
				}
				if(distance < 0 && parentLayoutParams.topMargin <= hideHeaderHeight){
					Log.i(TAG, "超过了不移动");
					return false;
				} 
				// 不是正在刷新中就不做任何事情
				if(currentStatus != status_refreshing){
					currentStatus = status_pull_to_refresh;
					Log.i(TAG, "可以刷新了");
				}
				parentLayoutParams.topMargin = -hideHeaderHeight + (distance / 2) ;
				parentLayout.setLayoutParams(parentLayoutParams);

				Log.i(TAG, "ACTION_MOVE()-----------");
				break;
			case MotionEvent.ACTION_UP:Log.i(TAG, "ACTION_UP()--------------");
				if(currentStatus == status_pull_to_refresh){
					new TopAsyncTask().execute();
				}
				Log.i(TAG, "ACTION_UP()--------------");
				break;
			default:
				break;
			}
			// 时刻记得更新下拉头中的信息  
            if (currentStatus == status_pull_to_refresh  || currentStatus == status_refresh_to_refresh) {  
                updateHeaderView();  
                topStatus  = status_top_stop;
            }  
            // 当前正处于下拉或释放状态,要让ListView失去焦点,否则被点击的那一项会一直处于选中状态  
            listview.setPressed(false);  
            listview.setFocusable(false);  
            listview.setFocusableInTouchMode(false);  
            return true;  
		}
		return false;
	}
	
	public void updateHeaderView(){
	    if (topStatus == status_top_start) {  
            if (currentStatus == status_pull_to_refresh) {  
            	rotateArrow();
            } else if (currentStatus == status_refresh_to_refresh) {  
                 
            } else if (currentStatus == status_refresh_finished) {  
            	
            }  
//             refreshUpdatedAtValue();  
        }  
	}
	
	/** 
     * 根据当前的状态来旋转箭头。 
     */  
    private void rotateArrow() {  
        float pivotX = imageview.getWidth() / 2f;  
        float pivotY = imageview.getHeight() / 2f;  
        float fromDegrees = 0f;  
        float toDegrees = 0f;  
        if (currentStatus == status_pull_to_refresh) {  
            fromDegrees = 180f;  
            toDegrees = 360f;  
        } else if (currentStatus == status_refresh_to_refresh) {  
            fromDegrees = 0f;  
            toDegrees = 180f; 
        }  
        RotateAnimation animation = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY);  
        animation.setDuration(800);  
        animation.setFillAfter(true);  
        imageview.startAnimation(animation);  
    }  
  
	
	
	  /** 
     * 根据当前ListView的滚动状态来设定 {@link #ableToPull} 
     * 的值,每次都需要在onTouch中第一个执行,这样可以判断出当前应该是滚动ListView,还是应该进行下拉。 
     *  
     * @param event 
     */  
    private void setIsAbleToPull(MotionEvent event) {  
        View firstChild = listview.getChildAt(0);  
        if (firstChild != null) {  
            int firstVisiblePos = listview.getFirstVisiblePosition();  
			// Log.i(TAG, "firstVisiblePos:" + firstVisiblePos);
			// Log.i(TAG, "firstChild.getTop():" + firstChild.getTop());
            if (firstVisiblePos == 0 && firstChild.getTop() == 0) {  
                if (!ableToPull) {  
                    mY = event.getRawY();  
                }  
                
                // 如果首个元素的上边缘,距离父布局值为0,就说明ListView滚动到了最顶部,此时应该允许下拉刷新  
                ableToPull = true;  
            } else {  
                if (parentLayoutParams.topMargin != hideHeaderHeight) {  
                    parentLayoutParams.topMargin = -hideHeaderHeight;  
                    parentLayout.setLayoutParams(parentLayoutParams);  
                }  
                ableToPull = false;  
            }  
        } else {  
            // 如果ListView中没有元素,也应该允许下拉刷新  
            ableToPull = true;  
        }  
    }  
    
    class TopAsyncTask extends AsyncTask<Void, Integer, String[]>{
    	
    	@Override
    	protected void onPreExecute() {
    		super.onPreExecute();
    		currentStatus = status_refreshing;
    	}
		@Override
		protected String[] doInBackground(Void... params) {
			Log.i(TAG, "doInBackground");
			int topMargin = parentLayoutParams.topMargin;  
            while (true) {  
                topMargin = topMargin + 1;  
                if (topMargin >= -hideHeaderHeight) {  
                    topMargin = -hideHeaderHeight;  
                    break;  
                }  
                publishProgress(topMargin);  
                sleep(10);  
            }  
            publishProgress(-hideHeaderHeight);
            Log.i(TAG, "doInBackground  end()");
			return null;
		}
    	@Override
    	protected void onPostExecute(String[] result) {
    		super.onPostExecute(result);
    		currentStatus = status_refresh_finished;
    		topStatus = status_top_start;
    	}
    	 @Override  
         protected void onProgressUpdate(Integer... topMargin) {  
    		 parentLayoutParams.topMargin = topMargin[0];  
             parentLayout.setLayoutParams(parentLayoutParams);
             data.add(0, "B--");data.add(1, "B--");data.add(2, "添加了两个B--");
             adapter.notifyDataSetChanged();
             
         }  
    	
    }
    private void sleep(int time) {  
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }

这种效果有个弊端:滑动不够流畅,所以使用动画才最可靠。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值