Android中ListView下拉重新整理上拉載入更多效果實現
在Android開發中,下拉重新整理和上拉載入更多在很多app中都會有用到,下面就是具體的實現的方法。
首先,我們自定義一個RefreshListView來繼承與ListView,下面是程式碼:
package com.example.downrefresh;
import java.text.SimpleDateFormat;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* 包含下拉重新整理功能的ListView
* @author poplar
*
*/
public class RefreshListView extends ListView implements OnScrollListener{
private float downY; // 按下的y座標
private float moveY; // 移動後的y座標
private int mHeaderViewHeight; // 頭佈局高度
public static final int PULL_TO_REFRESH = 0;// 下拉重新整理
public static final int RELEASE_REFRESH = 1;// 釋放重新整理
public static final int REFRESHING = 2; // 重新整理中
private int currentState = PULL_TO_REFRESH; // 當前重新整理模式
private RotateAnimation rotateDownAnim; // 箭頭向下動畫
private View mArrowView;// 箭頭佈局
private TextView mTitleText;// 頭佈局標題
private ProgressBar pb;// 進度指示器
private TextView mLastRefreshTime; // 最後重新整理時間
private OnRefreshListener mListener; // 重新整理監聽
private View mFooterView;// 腳佈局
private boolean isLoadingMore; // 是否正在載入更多
public RefreshListView(Context context) {
super(context);
init();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* 初始化頭佈局, 腳佈局
* 滾動監聽
*/
private void init() {
initHeaderView();
initAnimation();
initFooterView();
setOnScrollListener(this);
}
/**
* 初始化腳佈局
*/
private void initFooterView() {
mFooterView = View.inflate(getContext(), R.layout.layout_header_list, null);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
// 隱藏腳佈局
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
addFooterView(mFooterView);
}
/**
* 初始化頭佈局的動畫
*/
private void initAnimation() {
// 向上轉, 圍繞著自己的中心, 逆時針旋轉0 -> -180.
rotateUpAnim = new RotateAnimation(0f, -180f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateUpAnim.setDuration(300);
rotateUpAnim.setFillAfter(true); // 動畫停留在結束位置
// 向下轉, 圍繞著自己的中心, 逆時針旋轉 -180 -> -360
rotateDownAnim = new RotateAnimation(-180f, -360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateDownAnim.setDuration(300);
rotateDownAnim.setFillAfter(true); // 動畫停留在結束位置
}
/**
* 初始化頭佈局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);
mArrowView = mHeaderView.findViewById(R.id.iv_arrow);
pb = (ProgressBar) mHeaderView.findViewById(R.id.pb_bar);
mTitleText = (TextView) mHeaderView.findViewById(R.id.tv_refresh);
mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
// 提前手動測量寬高
mHeaderView.measure(0, 0);// 按照設定的規則測量
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
System.out.println(" measuredHeight: " + mHeaderViewHeight);
// 設定內邊距, 可以隱藏當前控制元件 , -自身高度
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
// 在設定資料介面卡之前執行新增 頭佈局/腳佈局 的方法.
addHeaderView(mHeaderView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// 判斷滑動距離, 給Header設定paddingTop
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = ev.getY();
System.out.println("downY: " + downY);
break;
case MotionEvent.ACTION_MOVE:
moveY = ev.getY();
System.out.println("moveY: " + moveY);
// 如果是正在重新整理中, 就執行父類的處理
if(currentState == REFRESHING){
return super.onTouchEvent(ev);
}
float offset = moveY - downY; // 移動的偏移量
// 只有 偏移量>0, 並且當前第一個可見條目索引是0, 才放大頭部
if(offset > 0 && getFirstVisiblePosition() == 0){
// int paddingTop = -自身高度 + 偏移量
int paddingTop = (int) (- mHeaderViewHeight + offset);
mHeaderView.setPadding(0, paddingTop, 0, 0);
if(paddingTop >= 0 && currentState != RELEASE_REFRESH){// 頭佈局完全顯示
System.out.println("切換成釋放重新整理模式: " + paddingTop);
// 切換成釋放重新整理模式
currentState = RELEASE_REFRESH;
updateHeader(); // 根據最新的狀態值更新頭佈局內容
}else if(paddingTop < 0 && currentState != PULL_TO_REFRESH){ // 頭佈局不完全顯示
System.out.println("切換成下拉重新整理模式: " + paddingTop);
// 切換成下拉重新整理模式
currentState = PULL_TO_REFRESH;
updateHeader(); // 根據最新的狀態值更新頭佈局內容
}
return true; // 當前事件被我們處理並消費
}
break;
case MotionEvent.ACTION_UP:
// 根據剛剛設定狀態
if(currentState == PULL_TO_REFRESH){
// - paddingTop < 0 不完全顯示, 恢復
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
}else if(currentState == RELEASE_REFRESH){
// - paddingTop >= 0 完全顯示, 執行正在重新整理...
mHeaderView.setPadding(0, 0, 0, 0);
currentState = REFRESHING;
updateHeader();
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 根據狀態更新頭佈局內容
*/
private void updateHeader() {
switch (currentState) {
case PULL_TO_REFRESH: // 切換回下拉重新整理
// 做動畫, 改標題
mArrowView.startAnimation(rotateDownAnim);
mTitleText.setText("下拉重新整理");
break;
case RELEASE_REFRESH: // 切換成釋放重新整理
// 做動畫, 改標題
mArrowView.startAnimation(rotateUpAnim);
mTitleText.setText("釋放重新整理");
break;
case REFRESHING: // 重新整理中...
mArrowView.clearAnimation();
mArrowView.setVisibility(View.INVISIBLE);
pb.setVisibility(View.VISIBLE);
mTitleText.setText("正在重新整理中...");
if(mListener != null){
mListener.onRefresh(); // 通知呼叫者, 讓其到網路載入更多資料.
}
break;
default:
break;
}
}
/**
* 重新整理結束, 恢復介面效果
*/
public void onRefreshComplete() {
if(isLoadingMore){
// 載入更多
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
isLoadingMore = false;
}else {
// 下拉重新整理
currentState = PULL_TO_REFRESH;
mTitleText.setText("下拉重新整理"); // 切換文字
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隱藏頭佈局
pb.setVisibility(View.INVISIBLE);
mArrowView.setVisibility(View.VISIBLE);
String time = getTime();
mLastRefreshTime.setText("最後重新整理時間: " + time);
}
}
private String getTime() {
long currentTimeMillis = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(currentTimeMillis);
}
public interface OnRefreshListener{
void onRefresh(); // 下拉重新整理
void onLoadMore();// 載入更多
}
public void setRefreshListener(OnRefreshListener mListener) {
this.mListener = mListener;
}
// public static int SCROLL_STATE_IDLE = 0; // 空閒
// public static int SCROLL_STATE_TOUCH_SCROLL = 1; // 觸控滑動
// public static int SCROLL_STATE_FLING = 2; // 滑翔
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 狀態更新的時候
System.out.println("scrollState: " + scrollState);
if(isLoadingMore){
return; // 已經在載入更多.返回
}
// 最新狀態是空閒狀態, 並且當前介面顯示了所有資料的最後一條. 載入更多
if(scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() >= (getCount() - 1)){
isLoadingMore = true;
System.out.println("scrollState: 開始載入更多");
mFooterView.setPadding(0, 0, 0, 0);
setSelection(getCount()); // 跳轉到最後一條, 使其顯示出載入更多.
if(mListener != null){
mListener.onLoadMore();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 滑動過程
}
}
----------------------------------------------我是美麗分割線···················································································
上面就是我們自定義的listview,我們自己寫了上拉載入更多和下拉重新整理的功能,接下來就是具體的使用
這是佈局檔案,使用了我們剛才自己寫的RefreshListView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.downrefresh.MainActivity" >
<com.example.downrefresh.RefreshListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</com.example.downrefresh.RefreshListView>
</RelativeLayout>
接下來就是listview的具體使用類MainActivity,
package com.example.downrefresh;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.example.downrefresh.RefreshListView.OnRefreshListener;
public class MainActivity extends Activity {
private RefreshListView listview;
private MyAdapter myAdapter;
private List<String> listDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
listview = (RefreshListView) findViewById(R.id.listview);
listview.setRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
new Thread(){
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listDatas.add(0,"我是下拉刷新出來的資料!");
runOnUiThread(new Runnable() {
@Override
public void run() {
myAdapter.notifyDataSetChanged();
listview.onRefreshComplete();
}
});
};
}.start();
}
@Override
public void onLoadMore() {
new Thread(){
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listDatas.add("我是載入更多出來的資料!1");
listDatas.add("我是載入更多出來的資料!2");
listDatas.add("我是載入更多出來的資料!3");
runOnUiThread(new Runnable() {
@Override
public void run() {
myAdapter.notifyDataSetChanged();
listview.onRefreshComplete();
}
});
};
}.start();
}
});
listDatas = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
listDatas.add("這是一個大妹子:" + i);
}
myAdapter = new MyAdapter();
listview.setAdapter(myAdapter);
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
return listDatas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return listDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView textView = new TextView(getApplicationContext());
textView.setTextSize(18f);
textView.setTextColor(Color.BLACK);
textView.setText(listDatas.get(position));
return textView;
}
}
}
這是效果圖:
最後這裡是 下載連結 http://download.csdn.net/detail/qq_32673327/9584533