Android自定义listview布局实现上拉加载下拉刷新功能
程序员文章站
2024-03-31 12:42:58
listview实现上拉加载以及下拉刷新的方式有很多。下面是我写的一种自定义的布局,复用性也比较的强。首先就是继承的listview的自定义view。
&nb...
listview实现上拉加载以及下拉刷新的方式有很多。下面是我写的一种自定义的布局,复用性也比较的强。首先就是继承的listview的自定义view。
autolistview.java:
package com.example.mic.testdemo.view; import android.annotation.targetapi; import android.content.context; import android.os.build; import android.os.bundle; import android.util.attributeset; import android.util.log; import android.view.layoutinflater; import android.view.motionevent; import android.view.view; import android.view.viewgroup; import android.view.animation.animation; import android.view.animation.linearinterpolator; import android.view.animation.rotateanimation; import android.widget.abslistview; import android.widget.imageview; import android.widget.listview; import android.widget.progressbar; import android.widget.textview; import com.example.mic.testdemo.r; import java.text.simpledateformat; /** * created by dflenovo on 2016/8/3. */ public class autolistview extends listview implements abslistview.onscrolllistener { public static final string footer = "footer"; public static final string header = "header"; private static final int pull = 1; private static final int none = 0; // private static final int release = 2; private static final int refreshing = 2; private static final int space = 20; private static final string tag = "autolistview"; private rotateanimation downanimation; private rotateanimation upanimation; private context context; private layoutinflater inflater; private view footer; private view header; private int headercontentinitialheight; private int headercontentheight; private onrefreshlistener onrefreshlistener; private boolean loadenable; private onloadlistener onloadlistener; private int firstvisibleitem; private boolean isloadingmore = false; private int starty; private int state; private imageview iv_pull; private int footerviewheight; private progressbar mprogressbar; private textview tvstate; private textview tvlastupdatetime; private boolean isscrolltobottom; 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); } @targetapi(build.version_codes.lollipop) public autolistview(context context, attributeset attrs, int defstyleattr, int defstyleres) { super(context, attrs, defstyleattr, defstyleres); initview(context); } private void initview(context context) { initheaderview(); initfooterview(); this.setonscrolllistener(this); // } private void initheaderview() { header = view.inflate(getcontext(), r.layout.pull_to_refresh_header, null); iv_pull = (imageview) header .findviewbyid(r.id.iv_pull); mprogressbar = (progressbar) header .findviewbyid(r.id.pb_listview_header); tvstate = (textview) header .findviewbyid(r.id.tv_listview_header_state); tvlastupdatetime = (textview) header .findviewbyid(r.id.tv_listview_header_last_update_time); // 设置最后刷新时间 tvlastupdatetime.settext("最后刷新时间: " + getlastupdatetime()); header.measure(0, 0); // 系统会帮我们测量出headerview的高度 headercontentheight = header.getmeasuredheight(); header.setpadding(0, -headercontentheight, 0, 0); this.addheaderview(header,header,true); // 向listview的顶部添加一个view对象 initanimation(); } private void initanimation() { upanimation = new rotateanimation(0f, -180f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); upanimation.setduration(500); upanimation.setfillafter(true); // 动画结束后, 停留在结束的位置上 downanimation = new rotateanimation(-180f, -360f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); downanimation.setduration(500); downanimation.setfillafter(true); // 动画结束后, 停留在结束的位置上 } private string getlastupdatetime() { simpledateformat sdf = new simpledateformat("yyyy-mm-dd hh:mm:ss"); return sdf.format(system.currenttimemillis()); } private void initfooterview() { footer = view.inflate(getcontext(), r.layout.foot_view, null); footer.measure(0, 0); footerviewheight = footer.getmeasuredheight(); footer.setpadding(0, -footerviewheight, 0, 0); this.addfooterview(footer,footer,true); } private void measureview(view child) { viewgroup.layoutparams p = child.getlayoutparams(); if (p == null) { p = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content); } int childwidthspec = viewgroup.getchildmeasurespec(0, 0 + 0, p.width); int lpheight = p.height; int childheightspec; if (lpheight > 0) { childheightspec = measurespec.makemeasurespec(lpheight, measurespec.exactly);//得到的是size。 } else { childheightspec = measurespec.makemeasurespec(0, measurespec.unspecified);//得到的是子布局的实际大小。 } child.measure(childwidthspec, childheightspec); } private void toppadding(int toppadding) { header.setpadding(header.getpaddingleft(), toppadding, header.getpaddingright(), header.getpaddingbottom()); header.invalidate(); } @override public void onscrollstatechanged(abslistview abslistview, int i) { if (i == scroll_state_idle || i == scroll_state_fling) { // 判断当前是否已经到了底部 if (isscrolltobottom && !isloadingmore) { isloadingmore = true; // 当前到底部 log.i(tag, "加载更多数据"); footer.setpadding(0, 0, 0, 0); this.setselection(this.getcount()); if (onloadlistener != null) { onloadlistener.onload(); } } } } @override public void onscroll(abslistview abslistview, int i, int i1, int i2) { this.firstvisibleitem = i; if (getlastvisibleposition() == (i2 - 1)) { isscrolltobottom = true; } else { isscrolltobottom = false; } } @override public boolean ontouchevent(motionevent ev) { switch (ev.getaction()) { // case motionevent.action_down: starty = (int) ev.gety(); break; case motionevent.action_move: int movey = (int) ev.gety(); // 移动中的y - 按下的y = 间距. int diff = (movey - starty) / 2; // -头布局的高度 + 间距 = paddingtop int paddingtop = -headercontentheight + diff; // 如果: -头布局的高度 > paddingtop的值 执行super.ontouchevent(ev); if (firstvisibleitem == 0 && -headercontentheight < paddingtop) { if (paddingtop > 0 && state == none) { // 完全显示了. log.i(tag, "松开刷新"); state = pull; refreshheaderviewbystate(); } else if (paddingtop < 0 && state == pull) { // 没有显示完全 log.i(tag, "下拉刷新"); state = none; refreshheaderviewbystate(); } // 下拉头布局 header.setpadding(0, paddingtop, 0, 0); } break; case motionevent.action_up: // 判断当前的状态是松开刷新还是下拉刷新 if (state == pull) { log.i(tag, "刷新数据."); // 把头布局设置为完全显示状态 header.setpadding(0, 0, 0, 0); // 进入到正在刷新中状态 state = refreshing; refreshheaderviewbystate(); if (onrefreshlistener != null) { onrefreshlistener.onrefresh(); // 调用使用者的监听方法 } } else if (state == none) { // 隐藏头布局 header.setpadding(0, -headercontentheight, 0, 0); } break; default: break; } return super.ontouchevent(ev); } // private void refreshheaderviewbystate() { switch (state) { // case none: // 下拉刷新状态 tvstate.settext("下拉刷新"); iv_pull.startanimation(downanimation); // 执行向下旋转 break; case pull: // 松开刷新状态 tvstate.settext("松开刷新"); iv_pull.startanimation(upanimation); // 执行向上旋转 break; case refreshing: // 正在刷新中状态 iv_pull.clearanimation(); iv_pull.setvisibility(view.gone); mprogressbar.setvisibility(view.visible); tvstate.settext("正在刷新中..."); break; default: break; } } public void hideheaderview() { header.setpadding(0, -headercontentheight, 0, 0); iv_pull.setvisibility(view.visible); mprogressbar.setvisibility(view.gone); tvstate.settext("下拉刷新"); tvlastupdatetime.settext("最后刷新时间: " + getlastupdatetime()); state = none; } public void hidefooterview() { footer.setpadding(0, -footerviewheight, 0, 0); isloadingmore = false; } public void setonrefreshlistener(onrefreshlistener onrefreshlistener) { this.onrefreshlistener = onrefreshlistener; } public void setonloadlistener(onloadlistener onloadlistener) { this.onloadlistener = onloadlistener; } public void onrefresh() { if (onrefreshlistener != null) { onrefreshlistener.onrefresh(); } } public void onload() { if (onloadlistener != null) { onloadlistener.onload(); } } public interface onrefreshlistener {//定义下拉刷新接口 public void onrefresh(); } public interface onloadlistener {//定义上拉加载更多 public void onload(); } }
上面的代码就是实现的关键.下面是头布局以及脚布局:
foot_view.xml:
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="加载更多" android:textsize="20dp" android:padding="10dp" android:layout_centerhorizontal="true"/> </relativelayout>
pull_to_refresh_header.xml:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" 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_pull" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:minwidth="30dip" android:src="@mipmap/xlistview_arrow" /> <progressbar android:id="@+id/pb_listview_header" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> </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="最后刷新时间: 2014-10-10 12:56:12" android:textcolor="@android:color/black" android:textsize="14sp" /> </linearlayout> </linearlayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" 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.mic.testdemo.mainactivity"> <com.example.mic.testdemo.view.autolistview android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"> </com.example.mic.testdemo.view.autolistview> </relativelayout>
上面所完成的步骤就是在listview上下加载不同的布局,上面也是要复用的代码,下面的代码就是怎么使用的代码了.
mainactivity.java:
public class mainactivity extends appcompatactivity implements autolistview.onloadlistener,autolistview.onrefreshlistener { private textview textview; private string result; private autolistview listview; private myadater adater; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); listview = (autolistview) findviewbyid(r.id.lv);} listview.setonrefreshlistener(mainactivity.this); listview.setonloadlistener(mainactivity.this); @override public void onload() { } @override public void onrefresh() {}
下面就是实现,就是在你需要的地方设置监听,以及上面加载以及刷新需要的操作就可以了!
以上所述是小编给大家介绍的android自定义listview布局实现上拉加载下拉刷新功能,希望对大家有所帮助
推荐阅读
-
Android自定义listview布局实现上拉加载下拉刷新功能
-
Android中ListView上拉刷新的功能实现(总结)
-
3年以上勿进!最简单的Android自定义ListView下拉刷新与上拉加载,代码直接拿去用~
-
Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法
-
Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码
-
Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法
-
Android程序开发之使用PullToRefresh实现下拉刷新和上拉加载
-
Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多
-
Android ListView下拉刷新上拉自动加载更多DEMO示例
-
Android开发ListView中下拉刷新上拉加载及带列的横向滚动实现方法