您的位置:首页 > 移动开发 > Android开发

Android实现ListView的下拉刷新、上拉加载更多

2016-12-24 14:57 459 查看

Android实现ListView的下拉刷新、上拉加载更多

在Andoird编程中经常使用的控件包括ListView,就个人而言,我还是很喜欢ListView的,在使用ListView的过程中,必不可少的就是下拉刷新、上拉加载更多。下面是我自己写出一个小Demo便于大家理解。希望大家可以理解。共同进步!

自己bb那么多,希望大家见谅,我直接上图说话



第一步:先定义一个自定义控件SlipListView继承与ListView,在SlipListView中增加ListView的头布局与脚布局并实现其滑动监听的功能(代码虽然多,但是原理很简单,聪明的你们肯定可以看明白的。)

public class SlipListView extends ListView implements OnScrollListener {

private Context mContext;
private int startY;
private int moveY;
private int mHeaderViewHeight;
private View mHeaderview;

/**
* 下拉刷新
*/
private static final int downRefresh = 0;

/**
* 正在刷新
*/
private static final int refreshing = 1;

/**
* 释放刷新
*/
private static final int upRefresh = 2;

private int currentState = downRefresh;

private RotateAnimation mUpAnimation;
private RotateAnimation mDownAnimation;
private TextView tvTiTile;
private ProgressBar pbUp;
private ImageView ivRefresh;
private RefreshListener mListener;
private View mFootView; // 脚布局
private boolean isLoadingMore; // 是否正在加载更多
private int mFootViewHeight;

public SlipListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

public SlipListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public SlipListView(Context context) {
super(context);
init();
}

/**
* 初始化界面,及动画
*/
private void init() {
mContext = getContext();

setOnScrollListener(this);

// 初始化头布局
initHeaderView();
// 初始化脚布局
initFootView();
initAnimation();
}

/**
* 初始化脚布局
*/
private void initFootView() {
mFootView = View.inflate(mContext, R.layout.layout_foot, null);

mFootView.measure(0, 0);
mFootViewHeight = mFootView.getMeasuredHeight();

addFooterView(mFootView);
}

/**
* 初始化动画
*/
private void initAnimation() {
mUpAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mUpAnimation.setDuration(300);
mUpAnimation.setFillAfter(true);

mDownAnimation = new RotateAnimation(-180, -360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mDownAnimation.setDuration(300);
mDownAnimation.setFillAfter(true);
}

/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderview = View.inflate(mContext, R.layout.layout_header, null);
ivRefresh = (ImageView) mHeaderview.findViewById(R.id.iv_refresh);
pbUp = (ProgressBar) mHeaderview.findViewById(R.id.pb_up);
tvTiTile = (TextView) mHeaderview.findViewById(R.id.tv_title);

mHeaderview.measure(0, 0);
mHeaderViewHeight = mHeaderview.getMeasuredHeight();
// 隐藏头布局
mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);

addHeaderView(mHeaderview);
}

// 监听listview的滑动事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:
startY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
moveY = (int) ev.getY();
if (currentState == refreshing) {
return super.onTouchEvent(ev);
}

int valueY = moveY - startY;
if (valueY > 0 && getFirstVisiblePosition() == 0) {
int result = -mHeaderViewHeight + valueY;
mHeaderview.setPadding(0, result, 0, 0);

// 判断状态
if (result < 0 && currentState != downRefresh) {
currentState = downRefresh;
updateHeader();
} else if (result >= 0 && currentState != upRefresh) {
currentState = upRefresh;
updateHeader();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
// 松开
if (currentState == downRefresh) {
mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);
} else if (currentState == upRefresh) {
mHeaderview.setPadding(0, 0, 0, 0);
currentState = refreshing;
updateHeader();
}
break;

default:
break;
}

return super.onTouchEvent(ev);
}

/**
* 更改头布局的状态
*/
private void updateHeader() {
switch (currentState) {
case downRefresh:
ivRefresh.startAnimation(mDownAnimation);
tvTiTile.setText("下拉刷新");
break;
case refreshing:
// 正在刷新
ivRefresh.clearAnimation();
ivRefresh.setVisibility(View.INVISIBLE);
pbUp.setVisibility(View.VISIBLE);
tvTiTile.setText("正在刷新...");

// 利用回调增加listview中的内容
if (mListener != null) {
mListener.onRefresh();
}
break;
case upRefresh:
// 释放刷新
ivRefresh.startAnimation(mUpAnimation);
tvTiTile.setText("释放刷新");
break;
}
}

public interface RefreshListener {

/**
* 刷新数据
*/
void onRefresh();

/**
* 加载更多
*/
void onLoadMore();
}

/**
* 刷新头布局的回调方法
*/
public void setOnRefreshListener(RefreshListener mListener) {
this.mListener = mListener;
}

/**
* 刷新结束
*/
public void setOnRefreshFinah() {
if (isLoadingMore) {
// 加载更多
mFootView.setPadding(0, -mFootViewHeight, 0, 0);
isLoadingMore = false;
}

currentState = downRefresh;
mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);
ivRefresh.setVisibility(View.VISIBLE);
pbUp.setVisibility(View.INVISIBLE);
tvTiTile.setText("下拉刷新");
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (isLoadingMore) {
return;
}
// 最新状态是空闲状态, 并且当前界面显示了所有数据的最后一条. 加载更多
if (scrollState == SCROLL_STATE_IDLE
&& getLastVisiblePosition() >= (getCount() - 1)) {
isLoadingMore = true;
mFootView.setPadding(0, 0, 0, 0);

setSelection(getCount());

if (mListener != null) {
mListener.onLoadMore();
}
}

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 滑动过程中
}
}


第二步:在布局文件中使用此自定义控件(比较简单)

<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"
tools:context="${relativePackage}.${activityClass}" >

<com.lx.pulllistview.ui.SlipListView
android:id="@+id/slv_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</RelativeLayout>


第三步:定义ListView的Item的布局(里面我将ProgressBar自定义了一个style,你们可以使用默认的)

<?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="horizontal" >

<FrameLayout
android:layout_width="60dp"
android:layout_height="50dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp" >

<ProgressBar
android:id="@+id/pb_up"
android:layout_width="match_parent"

bac2
android:layout_height="match_parent"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/progressbar_shape" />
</FrameLayout>

<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="加载更多..."
android:textColor="#ff0000"
android:textSize="16dp" />

</LinearLayout>


第四步:在MainActivity中调用(不难喲,加油)

public class MainActivity extends Activity {

private static final int PULL_DOWN = 0;
private static final int LOAD_MORE = 1;
private SlipListView slView;
private Context mContext;
private List<String> mTestList;
private MyAdapter mAdapter;

private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {

switch (msg.what) {

case PULL_DOWN:
mAdapter.notifyDataSetChanged();
slView.setOnRefreshFinah();
break;
case LOAD_MORE:

break;
}

super.handleMessage(msg);
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mContext = this;
// 初始化UI
initUI();

// 初始化数据
initData();
initEvent();
// 初始化数据适配器
initAdpater();
}

/**
* 初始化事件
*/
private void initEvent() {
slView.setOnRefreshListener(new RefreshListener() {
@Override
public void onRefresh() {

new Thread(new Runnable() {

@Override
public void run() {
SystemClock.sleep(2000);
mTestList.add(0, "我是刷新出来的测试数据");

mHandler.sendEmptyMessage(PULL_DOWN);
}
}).start();

}

@Override
public void onLoadMore() {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);

mTestList.add("我是加载出来的测试数据1");
mTestList.add("我是加载出来的测试数据2");

mHandler.sendEmptyMessage(PULL_DOWN);

}
}).start();
}
});
}

/**
* 初始化ListView的适配器
*/
private void initAdpater() {
mAdapter = new MyAdapter();
slView.setAdapter(mAdapter);
}

/**
* 初始化listview的测试数据
*/
private void initData() {
mTestList = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
mTestList.add("我是ListView的测试数据");
}
}

/**
* 初始化UI
*/
private void initUI() {
slView = (SlipListView) findViewById(R.id.slv_view);
}

/**
* 自定义适配器
*/
class MyAdapter extends BaseAdapter {

@Override
public int getCount() {
return mTestList.size();
}

@Override
public String getItem(int position) {
return mTestList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 由于item的布局就一个TextView并且数量较少,因此不使用优化了
TextView textView = new TextView(mContext);
textView.setText(mTestList.get(position));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);

return textView;
}

}
}


你是不是想说终于结束了,嘿嘿!当你阅读到这里的时候,你的知识与忍耐力已经更上一层楼了。废话不多说了,如果您有疑问请咨询我,最后谢谢大家的观看,你们的支持是给我最大的努力!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐