android下拉重新整理ListView的介紹和實現代碼

來源:互聯網
上載者:User

    大致上,我們發現,下拉重新整理的列表和一般列表的區別是,當捲軸在頂端的時候,再往下拉動就會把整個列表拉下來,顯示出鬆開重新整理的提示。由此可以看出,在構建這個下拉重新整理的組件的時候,只用繼承ListView,然後重寫onTouchEvent就能實現。還有就是要能在xml布局檔案中引用,還需要一個參數為Context,AttributeSet的建構函式。

  表面上的功能大概就這些了。另一方面,重新整理的行為似乎還沒有定義,在重新整理前做什麼,重新整理時要做什麼,重新整理完成後要做什麼,這些行為寫入一個介面中,然後讓組件去實現。

  在整個組件的實現中,主體部分自然是onTouchEvent的部分。這裡需要做一些說明,在ListView中,資料的滾動和ListView.scrollTo的行為是不一樣的。資料的滾動是大概適配器的事。所以在不滿足下拉整個列表的條件下,onTouchEvent 應該返回super.onTouchEvent(ev),讓ListView組件原本的OnTouchEvent去處理。

  考慮到組件的id和表頭的布局需要事先定義,同時我想把這個組件應用於多重專案裡,所以就把這個組件作為一個Library去實現。

下面就是具體的實現代碼。

  首先來看一下表頭的布局檔案chenzong_push_refresh_header.xml:

複製代碼 代碼如下:<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dip"
>
<ImageView
android:layout_width="30dip"
android:layout_height="40dip"
android:background="@drawable/arrow_down"
android:layout_alignParentLeft="true"
android:id="@+id/push_refresh_header_img"
android:layout_marginLeft="10dip"
/>
<ProgressBar
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dip"
android:id="@+id/push_refresh_header_pb"
style="@android:style/Widget.ProgressBar.Inverse"
android:visibility="gone"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最近一次更新在:"
android:textColor="#000000"
/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/push_refresh_header_date"
android:textColor="#000000"
android:text="2013-03-04 08:03:38"/>
</LinearLayout>
</RelativeLayout>

箭頭、processBar和最近的一次重新整理時間,表標頭檔就這三個元素。

重新整理的行為介面RefreshOperation的代碼:

複製代碼 代碼如下:public interface RefreshOperation {
public void OnRefreshStart();
public void OnRefreshing();
public void OnRefreshEnd();
}

列表拉下來時,箭頭翻轉的動畫arrow_rotate.xml:

複製代碼 代碼如下:<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:fromDegrees="0"
android:toDegrees="180"
android:duration="300"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:repeatCount="0">

</rotate>

這些檔案和一些資源檔備齊了之後,接下來就是下拉重新整理列表PushRefreshList的具體實現:

複製代碼 代碼如下:package com.chenzong;

import java.util.Calendar;

import com.doall.pushrefreshlist.R;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ListView;
import android.widget.TextView;

public class PushRefreshList extends ListView implements RefreshOperation{

private int header_layout=R.layout.chenzong_push_refresh_header;
//表標頭檔
private int arrow_down=R.drawable.arrow_down;
//箭頭往下的資源
private int arrow_up=R.drawable.arrow_up;
//箭頭往上的資源
private int img=R.id.push_refresh_header_img;
//顯示箭頭的控制項id
private int pb=R.id.push_refresh_header_pb;
//重新整理時的進度條
private int startPoint=0;
//觸摸的起始點
private RefreshOperation refresh;
//重新整理行為的對象
private Animation animation=null;
private Context context;
private View headerView;
private int minPushHeight;

private final String TAG="pushRefresh";

public PushRefreshList(Context cotext, AttributeSet attrs) {
super(context, attrs);
View empty=new View(context);
//判斷是否到列表的頂端,通常要用到this.getFirstVisiblePosition(),這裡建立一個高度的為零View,加到headerView和資料之間
this.addHeaderView(empty);
LayoutInflater inflater=LayoutInflater.from(context);
headerView=inflater.inflate(header_layout, null);
this.addHeaderView(headerView);
this.setRefreshOperation(this);
this.context=context;

}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
this.minPushHeight=headerView.getMeasuredHeight();
//擷取下拉重新整理的觸發高度
super.onLayout(changed, l, t, r, b);
}

private boolean canHandleEvent(int dy)
{
return (dy<0&&this.getFirstVisiblePosition()==0&&!isPbVisible());
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

int action=ev.getAction();
switch(action)
{
case MotionEvent.ACTION_DOWN:
startPoint=(int)ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int dy=startPoint-(int)ev.getY();
if(canHandleEvent(dy))
{
if(animation==null)
{
if(Math.abs(this.getScrollY())>=this.minPushHeight)
{
animation=AnimationUtils.loadAnimation(context, R.anim.arrow_rotate);
View mView=headerView.findViewById(img);
mView.startAnimation(animation);
this.setScrollbarFadingEnabled(true);
}
}
this.scrollTo(0,dy/2);
return true;
}
break;
case MotionEvent.ACTION_UP:

this.setScrollbarFadingEnabled(false);
if(animation!=null)
{
setImgBackgroundUp();
switchCompent(View.INVISIBLE,View.VISIBLE);
this.scrollTo(0,-minPushHeight);
PushRefreshList.this.refresh.OnRefreshStart();
new Thread(mRunnable).start();
animation=null;
}
else
this.scrollTo(0,0);
break;
}
return super.onTouchEvent(ev);
}

private Runnable mRunnable=new Runnable()
{

@Override
public void run() {
PushRefreshList.this.refresh.OnRefreshing();
mHandler.obtainMessage().sendToTarget();
}
};

private Handler mHandler=new Handler()
{
@Override
public void handleMessage(Message msg) {
PushRefreshList.this.refresh.OnRefreshEnd();
PushRefreshList.this.scrollTo(0, 0);
PushRefreshList.this.setImgBackgroundDown();
PushRefreshList.this.switchCompent(View.VISIBLE, View.GONE);
TextView tv=(TextView)headerView.findViewById(R.id.push_refresh_header_date);
tv.setText(this.getDateStr());
}

private String getDateStr()
{
Calendar ca=Calendar.getInstance();
int year=ca.get(Calendar.YEAR);
int month=ca.get(Calendar.MONTH);
int date=ca.get(Calendar.DATE);
int hour=ca.get(Calendar.HOUR);
int mintes=ca.get(Calendar.MINUTE);
int second=ca.get(Calendar.SECOND);
return year+"-"+(month+1)+"-"+date+" "+hour+":"+mintes+":"+second;
}
};

private void switchCompent(int imgStatus,int pbStatus)
{
View img=headerView.findViewById(R.id.push_refresh_header_img);
img.clearAnimation();
//執行了動畫的控制項如果不調用clearAnimation,setVisibility(View.GONE)會失效
img.setVisibility(imgStatus);
headerView.findViewById(R.id.push_refresh_header_pb).setVisibility(pbStatus);
}

private boolean isPbVisible()
{
return View.VISIBLE==headerView.findViewById(R.id.push_refresh_header_pb).getVisibility();
}

private void setImgBackgroundUp()
{
View mView=headerView.findViewById(this.img);
mView.setBackgroundResource(arrow_up);
}

private void setImgBackgroundDown()
{
View mView=headerView.findViewById(this.img);
mView.setBackgroundResource(arrow_down);
}

public void setRefreshOperation(RefreshOperation refresh)
{
this.refresh=refresh;
}

@Override
public void OnRefreshStart() {

}

@Override
public void OnRefreshing() {

}

@Override
public void OnRefreshEnd() {
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.