效果图:

第一步:编写需要在ListView中增加头加载的布局文件,与底部加载的布局文件:

头布局文件:

<?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="wrap_content"
android:orientation="horizontal" > <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip" > <ImageView
android:id="@+id/iv_listview_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@mipmap/common_listview_headview_red_arrow" /> <ProgressBar
android:id="@+id/pb_listview_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/custom_progressbar"
android:visibility="invisible" />
</FrameLayout> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="vertical" > <TextView
android:id="@+id/tv_listview_header_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#FF0000"
android:textSize="18sp" /> <TextView
android:id="@+id/tv_listview_header_last_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:text="最后刷新时间: 1990-09-09 09:09:09"
android:textColor="@android:color/darker_gray"
android:textSize="14sp" />
</LinearLayout> </LinearLayout>

底部布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_centerInParent="true"
android:gravity="center_vertical"> <ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/custom_progressbar"
/> <TextView
android:id="@+id/tv_bottom_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载更多"
android:layout_marginLeft="10dp"/> </LinearLayout> </RelativeLayout>

自定义ListView需要的接口回调给UI,告诉UI ListView执行了下拉加载/上拉加载动作

public interface ICustomUpdateListViewBack {

    public void downUpdateListData();

    public void upUpdateListData();

}

自定义ListView:

public class CustomUpdateListView extends ListView implements AbsListView.OnScrollListener{

    private static final String TAG = CustomUpdateListView.class.getSimpleName();

    /**
* 下拉刷新
*/
private static final int DOWN_UPDATE = 111; /**
* 准备刷新
*/
private static final int PLAN_UPDATE = 112; /**
* 正在刷新
*/
private static final int PROCESS_UPDATE = 113; private int thisUpdateStatusValue = DOWN_UPDATE; // 默认一直是下拉刷新 public CustomUpdateListView(Context context, AttributeSet attrs) {
super(context, attrs); setOnScrollListener(this); initHeader();
initBottom();
} /**
* 定义头部相关
*/
private View headerView;
private int headerViewHeight; private ImageView ivHeaderArrow;
private ProgressBar pbHeader;
private TextView tvHeaderState;
private TextView tvHeaderLastUpdateTime; /**
* 定义底部相关
*/
private View bottomView;
private int bottomViewHeight;
private TextView tvBottomState;
/**
* 初始化头部 布局View相关
*/
private void initHeader() {
// 从布局中拿到一个View
headerView = View.inflate(getContext(), R.layout.listview_header, null); // 获取头部各个控件的值
ivHeaderArrow = headerView.findViewById(R.id.iv_listview_header_arrow);
pbHeader = headerView.findViewById(R.id.pb_listview_header);
tvHeaderState = headerView.findViewById(R.id.tv_listview_header_state);
tvHeaderLastUpdateTime = headerView.findViewById(R.id.tv_listview_header_last_update_time); tvHeaderLastUpdateTime.setText(getThisTiem()); // getHieight(); 方法只能获取到控件显示后的高度
// int headerViewHeight = headerView.getHeight();
// 结果 headerViewHeight: 0 // View的绘制流程:测量 onLayout onDraw // 所以先测量后,就能得到测量后的高度了
headerView.measure(0, 0); // 注意:传0系统会自动去测量View高度 // 得到测量后的高度
headerViewHeight = headerView.getMeasuredHeight();
Log.i(TAG, "headerViewHeight:" + headerViewHeight); headerView.setPadding(0, -headerViewHeight, 0 ,0); addHeaderView(headerView); initHeaderAnimation();
} private void initBottom() {
bottomView = View.inflate(getContext(), R.layout.listview_bottom, null); tvBottomState = bottomView.findViewById(R.id.tv_bottom_state); // 先测量
bottomView.measure(0, 0); // 获取高度
bottomViewHeight = bottomView.getMeasuredHeight(); bottomView.setPadding(0, -bottomViewHeight, 0, 0); addFooterView(bottomView); } private RotateAnimation upRotateAnimation;
private RotateAnimation downRotateAnimation; private void initHeaderAnimation() {
upRotateAnimation = new RotateAnimation(
0, 180,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
upRotateAnimation.setDuration(500);
upRotateAnimation.setFillAfter(true); downRotateAnimation = new RotateAnimation(
180, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
downRotateAnimation.setDuration(500);
downRotateAnimation.setFillAfter(true);
} /**
* 滑动的状态改变
* @param view
* @param scrollState 有三种状态
* SCROLL_STATE_IDLE 代表 滑动停止状态类似于手指松开UP
* SCROLL_STATE_TOUCH_SCROLL 代表滑动触摸状态
* SCROLL_STATE_FLING 快速滑动 猛的一滑
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 如果是猛地滑动 或者 手指松开UP 才显示底部布局View
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
// 判断必须是底部的Item的时候
if (getLastVisiblePosition() == (getCount() -1)) {
bottomView.setPadding(0, 0, 0, 0); // 回调接口方法
if (null != customUpdateListViewBack) {
customUpdateListViewBack.upUpdateListData();
}
}
}
} private int firstVisibleItem; /**
* ListView滑动的监听方法
* @param view 当前ListView
* @param firstVisibleItem 当前屏幕的第一个显示的Item
* @param visibleItemCount 当前屏幕显示的Item数量
* @param totalItemCount 总共Item数量
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.firstVisibleItem = firstVisibleItem;
} private int downY; @Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_UP:
if (thisUpdateStatusValue == DOWN_UPDATE) {
headerView.setPadding(0, -headerViewHeight ,0 ,0);
} else {
headerView.setPadding(0, 0, 0, 0);
thisUpdateStatusValue = PROCESS_UPDATE;
updateHeaderState();
}
break;
case MotionEvent.ACTION_MOVE:
int cha = (int) ev.getY() - downY;
if (this.firstVisibleItem == 0 && cha > 0) {
int paddingTop = -headerViewHeight + cha;
// Log.i(TAG, "paddingTop:" + paddingTop); if (thisUpdateStatusValue == PROCESS_UPDATE) {
break;
} if (paddingTop > 0 && thisUpdateStatusValue == DOWN_UPDATE) {
// 准备刷新
Log.i(TAG, "paddingTop:" + paddingTop + ">>>准备刷新");
thisUpdateStatusValue = PLAN_UPDATE; updateHeaderState(); } else if (paddingTop < 0 && thisUpdateStatusValue == PLAN_UPDATE) {
// 正在刷新
Log.i(TAG, "paddingTop:" + paddingTop + ">>>正在刷新");
thisUpdateStatusValue = DOWN_UPDATE; updateHeaderState();
} headerView.setPadding(0, paddingTop, 0, 0);
}
break;
default:
break;
}
return super.onTouchEvent(ev); // 不返回ture 而是去调用父类的方法,是保证ListView自身的滑动功能正常
} private void updateHeaderState() { switch (thisUpdateStatusValue) {
case DOWN_UPDATE:
ivHeaderArrow.startAnimation(downRotateAnimation);
tvHeaderState.setText("下拉刷新");
break;
case PLAN_UPDATE:
ivHeaderArrow.startAnimation(upRotateAnimation);
tvHeaderState.setText("准备刷新");
break;
case PROCESS_UPDATE:
ivHeaderArrow.setVisibility(INVISIBLE);
ivHeaderArrow.clearAnimation();
pbHeader.setVisibility(VISIBLE);
tvHeaderState.setText("正在刷新中..."); if (null != customUpdateListViewBack) {
customUpdateListViewBack.downUpdateListData();
}
break;
default:
break;
}
} private ICustomUpdateListViewBack customUpdateListViewBack; public void setCallback(ICustomUpdateListViewBack back) {
this.customUpdateListViewBack = back;
} public void updateHeaderResult() {
headerView.setPadding(0, -headerViewHeight, 0, 0); // 状态还原
ivHeaderArrow.clearAnimation();
tvHeaderState.setText("下拉刷新"); ivHeaderArrow.setVisibility(VISIBLE);
pbHeader.setVisibility(INVISIBLE); tvHeaderLastUpdateTime.setText(getThisTiem()); thisUpdateStatusValue = DOWN_UPDATE;
} private String getThisTiem() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// HH:mm:ss
// 获取当前时间
Date date = new Date(System.currentTimeMillis());
return simpleDateFormat.format(date);
} public void updateBottomResult() {
/*tvBottomState.setText("加载成功");
tvBottomState.setTextColor(Color.GREEN);*/ new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
bottomView.setPadding(0, -bottomViewHeight, 0, 0);
}
}, 2000);
}
}

把ProgressBar的风格修改,从白色演变成红色的形式

custom_progressbar.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" > <shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="false" >
<gradient
android:centerColor="#FF6A6A"
android:endColor="#FF0000"
android:startColor="#FFFFFF"
android:type="sweep" />
</shape> </rotate>

如何使用自定义的ListView:

    <heima.custom.CustomUpdateListView
android:id="@+id/custom_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/ll">
</heima.custom.CustomUpdateListView>

当把数据查询出来后,执行:

listView.updateHeaderResult(); // 更新头部布局复原
listView.updateBottomResult(); // 更新底部布局复原
listView.setCallback(new ICustomUpdateListViewBack() {
@Override
public void downUpdateListData() {
new AsyncTask<Void, Void, Void>() { @Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(3000);
mData.add(0, "1最新加载出来的数据");
mData.add(1, "2最新加载出来的数据");
mData.add(2, "3最新加载出来的数据");
mData.add(3, "4最新加载出来的数据");
mData.add(4, "5最新加载出来的数据");
mData.add(5, "6最新加载出来的数据");
return null;
} @Override
protected void onPostExecute(Void aVoid) {
// super.onPostExecute(aVoid);
adapter.notifyDataSetChanged();
listView.updateHeaderResult();
}
}.execute(new Void[]{});
} @Override
public void upUpdateListData() {
new AsyncTask<Void, Void, Void>() { @Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(6000);
mData.add("1commonlibrary");
mData.add("2commonlibrary");
mData.add("3commonlibrary");
mData.add("4commonlibrary");
mData.add("5commonlibrary");
mData.add("6commonlibrary");
return null;
} @Override
protected void onPostExecute(Void aVoid) {
// super.onPostExecute(aVoid);
adapter.notifyDataSetChanged();
listView.updateBottomResult();
}
}.execute(new Void[]{});
}
});
												

Android-自定义ListView下拉刷新与上拉加载的更多相关文章

  1. Android如何定制一个下拉刷新,上滑加载更多的容器

    前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...

  2. Android之下拉刷新,上啦加载的实现(一)

    转载地址http://blog.csdn.net/leehong2005/article/details/12567757#t5 前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但 ...

  3. 【Android - 自定义View】之自定义可下拉刷新或上拉加载的ListView

    首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 RefreshableListView ,继承自ListView类: (2)在这个自定义View中,用户可以设置是否支持下拉刷新 ...

  4. Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件

    原文 http://blog.csdn.net/bboyfeiyu/article/details/39253051       前言 下 拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采 ...

  5. android ListView的上部下拉刷新下部点击加载更多具体实现及拓展

    android ListView的上部下拉刷新下部点击加载更多具体实现及拓展 ListView下拉刷新,上拉自动加载更多 下拉刷新以及加载更多

  6. ListView下拉刷新、上拉载入更多之封装改进

    在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...

  7. Android XListView下拉刷新、上拉载入更多

    source code: https://github.com/Maxwin-z/XListView-Android 提供了两个接口: a) IXListViewListener:  触发下拉刷新.上 ...

  8. Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

    本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...

  9. DCloud-MUI:下拉刷新、上拉加载

    ylbtech-DCloud-MUI:下拉刷新.上拉加载 1. 下拉刷新返回顶部 0. http://dev.dcloud.net.cn/mui/pulldown/ 1. 概述 为实现下拉刷新功能,大 ...

  10. RN-第三方之react-native-pull 下拉刷新、上拉加载

    有一个很好的下拉刷新.上拉加载库:react-native-pull地址:https://github.com/greatbsky/react-native-pull-demo 使用 import { ...

随机推荐

  1. httpclient4例子

    参考:http://hc.apache.org/httpclient-3.x/tutorial.html import org.apache.http.HttpEntity; import org.a ...

  2. 什么场景应该用 MongoDB(转)

    很多人比较关心 MongoDB 的适用场景,也有用户在话题里分享了自己的业务场景,比如: 案例1 用在应用服务器的日志记录,查找起来比文本灵活,导出也很方便.也是给应用练手,从外围系统开始使用Mong ...

  3. MongoDB 3.0 Release Notes

    MongoDB 3.0支持WiredTiger存储引擎,提供可插拔存储引擎API,新增SCRAM-SHA-1认证机制,改进explain功能. 可插拔存储引擎API 允许第三方为MongoDB开发存储 ...

  4. Golang之Mysql事务

    Mysql事务 )原子性 )一致性 )隔离性 )持久性 示例代码 package main import ( "fmt" _ "github.com/go-sql-dri ...

  5. PAT 1072 开学寄语(20)(代码+思路)

    1072 开学寄语(20 分) 下图是上海某校的新学期开学寄语:天将降大任于斯人也,必先删其微博,卸其 QQ,封其电脑,夺其手机,收其 ipad,断其 wifi,使其百无聊赖,然后,净面.理发.整衣, ...

  6. wdk Windows驱动开发

    https://www.cnblogs.com/liaoguifa/p/9049859.html 安装wdk8.1

  7. mstsc本地驱动器

    mstsc 可以把本地驱动器 挂载到服务器上

  8. 测试用例Excel模板For Quality Center

    Subject Test Name Description Step Name  Step Description Expected Result PU Regr\Component\Attribut ...

  9. 数据库链接 mybatis spring data jpa 两种方式

    jdbc mybatis                     spring data jpa dao service webservice jaxrs     jaxws  springmvc w ...

  10. URL编码转换函数:escape()、encodeURI()、encodeURIComponent()

          函数出现时间:                      escape()                                javascript 1.0           ...