1准备图片 common_listview_headview_red_arrow.png

2建立shape_progress.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
        xmlns:android="http://schemas.android.com/apk/res/android"android:innerRadiusRatio="2.5"android:shape="ring"android:thicknessRatio="10"android:useLevel="false"><gradient
            android:centerColor="#44FF0000"android:endColor="#00000000"android:startColor="#FF0000"android:type="sweep"/></shape>
</rotate>

3建立布局layout_footer_list.xml用来上拉显示更多

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:gravity="center"android:orientation="horizontal"android:layout_height="match_parent"><ProgressBar
        android:layout_margin="5dp"android:layout_width="50dp"android:indeterminateDrawable="@drawable/shape_progress"android:layout_height="50dp" /><TextView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="加载更多..."android:textColor="#F00"android:layout_marginLeft="15dp"android:textSize="18sp"/>
</LinearLayout>

4建立layout_header_list.xml用来下拉显示刷新

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:orientation="horizontal"android:layout_height="match_parent"><FrameLayout
        android:layout_margin="5dp"android:layout_width="50dp"android:layout_height="50dp"><ImageView
            android:id="@+id/iv_arrow"android:layout_gravity="center"android:src="@mipmap/common_listview_headview_red_arrow"android:layout_width="wrap_content"android:layout_height="wrap_content" /><ProgressBar
            android:id="@+id/pd"android:indeterminateDrawable="@drawable/shape_progress"android:visibility="invisible"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout><LinearLayout
        android:layout_margin="5dp"android:gravity="center_horizontal"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:id="@+id/tv_title"android:layout_marginTop="5dp"android:text="下拉刷新"android:textColor="#F00"android:textSize="18sp"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextView
            android:id="@+id/tv_desc_last_refresh"android:layout_marginTop="5dp"android:singleLine="true"android:text="最后刷新时间:2017-09-11 13:20:35"android:textColor="#666"android:textSize="14sp"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout>
</LinearLayout>

5建立自定义布局类实现自定义布局的功能

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_footer_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 -> -360rotateDownAnim = 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);mTitleText = (TextView) mHeaderView.findViewById(R.id.tv_title);mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_desc_last_refresh);// 提前手动测量宽高mHeaderView.measure(0, 0);// 按照设置的规则测量mHeaderViewHeight = mHeaderView.getMeasuredHeight();System.out.println(" measuredHeight: " + mHeaderViewHeight);// 设置内边距, 可以隐藏当前控件 , -自身高度mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 在设置数据适配器之前执行添加 头布局/脚布局 的方法.addHeaderView(mHeaderView);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {// 判断滑动距离, 给Header设置paddingTopswitch (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; // 滑翔@Overridepublic 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();}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// 滑动过程}
}

6建立主布局

<?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"><com.example.downlistupdata.UI.RefreshListView
        android:id="@+id/listView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

7在MianActivity中添加适配器(内部类)

 class MyAdapter extends BaseAdapter{@Overridepublic int getCount() {return listDatas.size();}@Overridepublic Object getItem(int i) {return listDatas.get(i);}@Overridepublic long getItemId(int i) {return i;}@Overridepublic View getView(int i, View v, ViewGroup viewGroup) {TextView textView = new TextView(viewGroup.getContext());textView.setTextSize(18f);textView.setText(listDatas.get(i));return textView;}}@Overrideprotected void onDestroy() {super.onDestroy();}
}

8为自定义控件添加响应处理

public class MainActivity extends Activity {private RefreshListView listview;private List<String> listDatas;private MyAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listview = (RefreshListView) findViewById(R.id.listView);listview.setReleaseListener(new RefreshListView.OnRefreshListener() {@Overridepublic void onRefresh() {new Thread(){public void run(){try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}listDatas.add(0,"我是下拉刷新出来的数据");runOnUiThread(new Runnable() {@Overridepublic void run() {adapter.notifyDataSetChanged();listview.onRefreshComplete();}});}}.start();}@Overridepublic void onLoadMore() {new Thread(){@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}listDatas.add("我是加载更多出来的数据!1");listDatas.add("我是加载更多出来的数据!2");listDatas.add("我是加载更多出来的数据!3");runOnUiThread(new Runnable() {@Overridepublic void run() {adapter.notifyDataSetChanged();listview.onRefreshComplete();}});}}.start();}});listDatas = new ArrayList<>();for (int i = 0; i < 10; i++)listDatas.add(i + "");adapter = new MyAdapter();listview.setAdapter(adapter);}

源码下载

自定义控件之下拉刷新列表相关推荐

  1. 微信小程序之下拉刷新,上拉更多列表实现

    代码地址如下: http://www.demodashi.com/demo/11110.html 一.准备工作 首先需要下载小程序开发工具 官方下载地址: https://mp.weixin.qq.c ...

  2. 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)...

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  3. IOS开发之下拉刷新和上拉加载更多

    IOS开发之下拉刷新和上拉加载更多 1.简介 常用的下拉刷新和上拉加载更多的实现方式 (1)UIRefreshControl (2)EGOTableViewRefresh (3)AH3DPullRef ...

  4. android自带下拉阻尼动画,android 有阻尼下拉刷新列表的实现方法

    本文将会介绍有阻尼下拉刷新列表的实现,先来看看效果预览: 这是下拉状态: 这是下拉松开手指后listView回滚到刷新状态时的样子: 1. 如何调用 虽然效果图看起来样子不太好看,主要是因为那个蓝色的 ...

  5. android下拉菜单刷新,android下拉刷新列表实现(pull to refresh)

    android中提供了ListView控件,listview能够为我们展现丰富的内容,有时候我们为了提升用户体检,需要更炫而且更好用户体验的效果,pull to refresh(下拉刷新列表效果)就应 ...

  6. 微信小程序下拉刷新列表onPullDownRefresh;微信小程序上划加载列表onReachBottom;uni-app微信小程序下拉加载数据;uni-app微信小程序上划页面加载数据

    需求:微信小程序列表加载有两种方式,分别是按住页面下拉加载数据数据(触发onPullDownRefresh)和直接上划滚动页面到底部加载数据(触发onReachBottom函数). 本文主要是使用上划 ...

  7. Android之下拉刷新的ListView

    不废话,代码里面注释很详细,直接上代码: 自定义的RefreshableListView代码: 1 public class RefreshableListView extends ListView ...

  8. 原生小程序下拉刷新列表且保存之前的数据

    用concat这个方法存入新数组中 上拉加载时再传页数回去就好了 如果把加载列表的方法写在onShow里面的话建议多加一个判断 不然会出先重复数据

  9. 使用Vant框架的组件van-pull-refresh搭配van-list和van-card完成上滑加载更多列表数据,下拉刷新当前列表数据(等同于翻页功能)

    <template><div class="sg-page-body"><div class="sg-list"><v ...

  10. ajax 下拉刷新 上拉加载更多,局部刷新iscroll控件的具体使用(下拉刷新,上拉加载更多)...

    标签下,这是调用iscroll的必要条件,否则会出现不能刷新或者不能滑动页面的情况.此外还有商量刷新及下拉刷新的标签,在iscroll中有这两个标签的样式,若不想用默认的样式,也可通过覆盖的方式添加其 ...

最新文章

  1. allgro显示网络名称_家里的路由器如何隐藏WiFi名称防止陌生人蹭网?SSID隐藏教程...
  2. git - 简明指南
  3. 内存引起的几种故障的解决
  4. windows ce操作系统能用哪个导航_微软的windows和苹果的mac操作系统,在技术难度上哪个更高...
  5. [转]非模态对话框的特点与使用
  6. Ubuntu 16.04 利用Sakurafrp工具管理多节点多隧道ID 实现 ssh 内网穿透
  7. ManualResetEvent使用说明
  8. 对联广告html,Js对联广告代码示例(入门)
  9. 教你如何查看加密的QQ空间和加密的QQ相册
  10. oracle羊毛,预言机(Oracle)简介和撸羊毛教程— 上篇
  11. c语言兵器谱,程序员兵器谱——那些男人们梦寐以求的终极键盘
  12. 汽车维修企业管理【12】
  13. C语言_malloc动态开辟内存空间
  14. Runnable小练习(网图下载)
  15. linux上创建loopback接口,在python中的特定接口的linux loopback接口
  16. cosx等价无穷小_等价无穷小替换注意事项
  17. openlayers官方教程(三)Basics——Zooming to your location
  18. nalu格式annex-B和avcc
  19. 【C++】多线程同步
  20. java 导出word试题

热门文章

  1. Order Siblings by 排序
  2. 【过一下19】学了git,看了算法竞赛讲解
  3. 商学院学习笔记(2)
  4. 路由器有信号无网络连接到服务器,路由器信号满格但是没有网络怎么办
  5. link与@import自己的一些愚见
  6. 易捷行云新一代私有云全场景智能统一运维|轻运维之场景化运维
  7. 易捷行云EasyStack与火星高科完成产品互认证,保护云上数据
  8. 通用验证码识别SDK免费开源
  9. Kiosk模式是什么?win10如何启用Kiosk模式?
  10. python列表遍历元组_Python 元组遍历排序操作方法