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

[置顶] Android中ListView下拉刷新上拉加载更多效果实现

2016-07-24 09:13 676 查看
  在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 View mHeaderView; // 头布局
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 rotateUpAnim; // 箭头向上动画
private RotateAnimation rotateDownAnim; // 箭头向下动画
private View mArrowView;// 箭头布局
private TextView mTitleText;// 头布局标题
private ProgressBar pb;// 进度指示器
private TextView mLastRefreshTime; // 最后刷新时间
private OnRefreshListener mListener; // 刷新监听
private View mFooterView;// 脚布局
private int mFooterViewHeight;// 脚布局高度
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,我们自己写了上拉加载更多和下拉刷新的功能,接下来就是具体的使用

这是布局文件,使用了我们刚
b48b
才自己写的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: