android中上拉下滑布局,3年以上勿进!最简单的Android自定义ListView下拉刷新与上拉加载,代码直接拿去用~...

本文主要针对开发新手,手写实现一个最简单Android自定义listview下拉刷新和上拉加载demo。

不喜可喷,欢迎大佬留言指点。

效果图

f07a49c5a17c

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

头布局文件:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="10dip" >

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" />

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" />

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center_vertical"

android:gravity="center_horizontal"

android:orientation="vertical" >

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" />

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" />

底部布局文件:

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:layout_centerInParent="true"

android:gravity="center_vertical">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:indeterminateDrawable="@drawable/custom_progressbar"

/>

android:id="@+id/tv_bottom_state"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="加载更多"

android:layout_marginLeft="10dp"/>

二:自定义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 文件:

android:fromDegrees="0"

android:pivotX="50%"

android:pivotY="50%"

android:toDegrees="360" >

android:innerRadiusRatio="3"

android:shape="ring"

android:thicknessRatio="10"

android:useLevel="false" >

android:centerColor="#FF6A6A"

android:endColor="#FF0000"

android:startColor="#FFFFFF"

android:type="sweep" />

四:如何使用自定义的ListView:

android:id="@+id/custom_listview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_below="@id/ll">

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

listView.updateHeaderResult(); // 更新头部布局复原

listView.updateBottomResult(); // 更新底部布局复原

listView.setCallback(new ICustomUpdateListViewBack() {

@Override

public void downUpdateListData() {

new AsyncTask() {

@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() {

@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[]{});

}

};

这样,一个简单的自定义ListView下拉刷新和上拉加载就实现完成了。

觉得不错,请给文章点个赞,感谢支持~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值