ListView下拉刷新,上拉加载
来源:互联网 发布:js弹出路径选择对话框 编辑:程序博客网 时间:2024/06/02 04:40
最近不忙,想到自己用到的PullToRefreshListView,就自己写着看看,之前都是用现成的,主要还是知道原理吧,
借鉴的一篇文章ListView下拉刷新,上拉自动加载更多
这篇文章写的很清楚,我就不重复了,直接贴代码吧
activity_mainxml:
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.shop.hsz88.autolistviewdemo.MainActivity"> <com.shop.hsz88.autolistviewdemo.AutoListView android:id="@+id/atlv" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>
MainActiviyt.java
package com.shop.hsz88.autolistviewdemo;import android.content.Context;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import java.util.ArrayList;public class MainActivity extends AppCompatActivity { private Context mContext; private String tag; private ArrayList<String> datas; private AutoListView aulv; private MyAdapter myAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext=this; tag="MainActivity"; initView(); initData(); } private void initView() { aulv = (AutoListView) findViewById(R.id.atlv); } private void initData() { datas=new ArrayList<String>(); //添加数据 for (int i=0;i<20;i++){ datas.add("第"+i+"条数据"); } myAdapter = new MyAdapter(mContext, datas); aulv.setAdapter(myAdapter); }}
重点:自定义ListView
package com.shop.hsz88.autolistviewdemo;import android.content.Context;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.ListView;import android.widget.TextView;/** * Created by Administrator on 2017/11/16. */public class AutoListView extends ListView implements AbsListView.OnScrollListener { private String tag = "AutoListView"; // 定义header的四种状态和当前状态 private static final int NONE = 0; private static final int PULL = 1; private static final int RELEASE = 2; private static final int REFRESHING = 3; private int state; // 区分PULL和RELEASE的距离的大小 private static final int SPACE = 50; //头部顶部内边距 private int headerContentInitialHeight; //头布局实际高度,而不是显示的高度 private int headerContentHeight; //记录手指滑动ListView的状态 private int scrollState; private int firstVisibleItem; private View header_view; private View foot_view; //加一个标记,记录显示的第一个item是否是数据源的第一个 private boolean isFist = false; //记录手指刚按下的位置 private float startY; public AutoListView(Context context) { super(context); initView(context); } public AutoListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public AutoListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } //初始化头布局和尾布局 private void initView(Context context) { //1.获取头布局 header_view = View.inflate(context, R.layout.layout_header, null); /** * 重点 */ //获取头部的顶部内边距 headerContentInitialHeight = header_view.getPaddingTop(); //计算header_view的大小 measureView(header_view); //获取header的测量高度(实际高度,另一个高度是显示高度(getHeight)) headerContentHeight = header_view.getMeasuredHeight(); //打印 38 Log.i(tag, "头布局测量高度==:" + headerContentHeight); //将头布局顶部内边距设置为负让其不显示出来 topPadding(header_view, -headerContentHeight); //2.获取脚布局 foot_view = View.inflate(context, R.layout.layout_foot, null); //3.将头布局和脚布局添加到ListView中去,添加到第1条数据的前面和最后一条数据的后面 this.addHeaderView(header_view); this.addFooterView(foot_view); //一开始为初始状态 state = NONE; //让头布局和脚布局都不显示// header_view.setVisibility(GONE);// foot_view.setVisibility(GONE); //设置滑动监听 this.setOnScrollListener(this); } /** * *监听着ListView的滑动状态改变。官方的有三种状态SCROLL_STATE_TOUCH_SCROLL、SCROLL_STATE_FLING、SCROLL_STATE_IDLE: * SCROLL_STATE_TOUCH_SCROLL:手指正拖着ListView滑动 * SCROLL_STATE_FLING:ListView正自由滑动 * SCROLL_STATE_IDLE:ListView滑动后静止 * * @param view * @param scrollState */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //记录手指滑动的状态 this.scrollState = scrollState; } /** * @param view * @param firstVisibleItem 表示在屏幕中第一条显示的数据在adapter中的位置 * @param visibleItemCount 则表示屏幕中最后一条数据在adapter中的数据, * @param totalItemCount 则是在adapter中的总条数 */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //记录屏幕上显示的第一条数据在数据源的位置 this.firstVisibleItem = firstVisibleItem; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN://手指按下 //先判断显示的第一个item是不是数据源的第一个 if (firstVisibleItem == 0) { isFist = true; //记录手指按下y方向的位置 startY = ev.getY(); } break; case MotionEvent.ACTION_MOVE://手指滑动 //根据移动距离去切换头布局的状态 //每移动一像素就调用一次 whenMove(ev); break; //当用户保持按下操作,并从你的控件转移到外层控件时,会触发ACTION_CANCEL case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: //手指抬起或者移到控件外时,让头布局隐藏,或者执行刷新操作 if (state == PULL) { //移动距离太小,执行隐藏 state = NONE; Log.i(tag, "onTouchEvent None"); refreshHeaderViewByState(); } else if (state == RELEASE) { //执行刷新操作,刷新完后要隐藏掉 state = REFRESHING; refreshHeaderViewByState(); Log.i(tag, "onTouchEvent REFeeshing"); //在这里写获取数据请求 } break; } return super.onTouchEvent(ev); } /** * 手指滑动走一遍的顺序为 12 4 32 * 获取手势状态,根据状态不同显示不同效果 * * @param ev */ private void whenMove(MotionEvent ev) { //显示的数据是否是数据源的第一个,不是直接返回 if (!isFist) { return; } //手指移动的y方向位置 int tmpY = (int) ev.getY(); //计算位置差 int space = (int) (tmpY - startY); Log.i(tag,"手指移动位置差==:"+space); //根据手指移动距离减去头布局初始高度,来设置头布局的高度 int topPadding = space - headerContentHeight; switch (state) { case NONE: if (space > 0) { state = PULL; //下拉刷新 refreshHeaderViewByState(); Log.i(tag, "状态:1"); } break; case PULL: //将头部显示出来,动态显示,参数2根据手指滑动距离而改变 topPadding(header_view, topPadding); //当处于手指正拖着ListView滑动,且滑动的距离大于头布局距离与设置距离大小时,就可以进行刷新操作 if (scrollState == SCROLL_STATE_TOUCH_SCROLL && space > headerContentHeight + SPACE) { state = RELEASE; //头布局显得是内容,松手刷新 refreshHeaderViewByState(); Log.i(tag, "状态2"); } break; //刷新操作 case RELEASE: //设置头布局内边距 topPadding(header_view, topPadding); Log.i(tag, "状态4"); //拉动距离小,就不刷新 if (space > 0 && space < headerContentHeight + SPACE) { state = PULL; //下拉刷新 refreshHeaderViewByState(); Log.i(tag, "状态3"); } else if (space <= 0) { //回到初始位置 state = NONE; refreshHeaderViewByState(); } break; } } /** * 头部页面显示效果 */ // 根据当前状态,调整header private void refreshHeaderViewByState() { switch (state) { //初始状态,啥都没做, case NONE: //调整头部的大小 topPadding(header_view, -headerContentHeight); ((TextView) header_view.findViewById(R.id.tv_content)).setText("下拉刷新"); break; case PULL: //下拉状态,此时松开会还原到状态NONE,并不进行刷新 ((TextView) header_view.findViewById(R.id.tv_content)).setText("下拉刷新"); //让其显示出来 header_view.findViewById(R.id.tv_content).setVisibility(VISIBLE); break; case RELEASE: //同样是下拉状态,但此刻松开会执行刷新,进入状态REFRESHING ((TextView) header_view.findViewById(R.id.tv_content)).setText("松手刷新"); break; case REFRESHING: //正在执行刷新操作, // 刷新结束后进入状态NONE。 //headerContentInitialHeight,为0 topPadding(header_view, headerContentInitialHeight); Log.i(tag, "刷新结束==:" + headerContentInitialHeight); //隐藏掉,不让其显示 ((TextView) header_view.findViewById(R.id.tv_content)).setText("正在刷新"); /** * 回到初始位置,如果不写咋只能刷新一次,延时回到刷新完成 */ new Handler().postDelayed(new Runnable() { @Override public void run() { state = NONE; refreshHeaderViewByState(); } }, 3 * 1000); break; } } /** * 用来计算header大小的。比较隐晦。因为header的初始高度就是0,貌似可以不用。 * 计算一个控件的大小 * * @param child 需要计算的控件 */ private void measureView(View child) { //获取工具的配置参数对象 ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { //如果p为空则创建一个,宽度匹配父布局,高度包裹内容 p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } /** * 计算子布局尺寸的最主要部分: * 为特定子控件计算出它的MeasureSpec,(测量说明) * 这个方法为一个子布局的任一一个维度(高度/宽度)计算出正确的MeasureSpec。 */ int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } /** * 调整一个控件的内边距,距离顶部的距离 * * @param view 需要调整的控件 * @param topPadding 顶部距离 */ private void topPadding(View view, int topPadding) { //左。上。右,下 view.setPadding(view.getPaddingLeft(), topPadding, view.getPaddingRight(), view.getPaddingBottom()); view.invalidate(); }}
头布局
<?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"> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="头布局" /></LinearLayout>
item布局
<?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"> <TextView android:id="@+id/tv_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="测试数据" android:textSize="40sp"/></LinearLayout>
阅读全文
0 0
- listView上拉刷新下拉加载
- Listview 下拉刷新,上拉加载更多
- Android ListView 下拉刷新 上拉加载
- listView上拉刷新下拉加载
- android listview 上拉加载 下拉刷新
- Listview下拉刷新上拉加载更多
- ListView上拉加载下拉刷新
- 下拉刷新,上拉加载更多ListView
- ListView下拉刷新,上拉加载更多
- Android--listview下拉刷新,上拉加载
- ListView下拉刷新上拉加载更多
- Appcan listview上拉加载下拉刷新
- ListView下拉刷新&上拉加载
- listview上拉刷新下拉加载
- ListView下拉刷新,上拉加载
- 下拉刷新+上拉加载的listview
- ListView上拉刷新下拉加载
- listview的上拉刷新,下拉加载
- Linux下启动tomcat的脚本文件
- 【angular】gyp ERR! build error msbuild.exe` failed with exit code: 1
- AndroidStudio 缓存文件夹配置
- 【算法】单源最短路径和任意两点最短路径总结(补增:SPFA)
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- ListView下拉刷新,上拉加载
- c语言基础知识2
- sklearn 机器学习练习
- 以root身份登录Linux
- 【Java笔记】 Week07
- HTML 转 Word
- *C语言操作符总结*
- U3D工程自动保存
- Spring boot + redis 实现session 共享管理