在写着东西之前。从网上找到非常多这方面的源代码,可是基本没有找到惬意的。包含在GitHub上的比較有名的Android-PullToRefresh-master。思来想去还是自己写吧。当然当中借鉴了一些别的开源代码!

废话不多说,直接上代码。凝视非常全乎,应该不难理解,Demo下载地址在最后:

package com.zs.pulltorefreshtest;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Scroller; /**
 * 下拉刷新控件,主要測试了ScrollView,代码中已实现ListView下拉和上拉刷新,只是没有怎么測
 * 至于GridView、WebView等,代码中没有实现。只是非常好拓展,在isReadyForPullUp() 和 
 * isReadyForPullDown()这两个方法中增加对应的View的上下边界推断就OK了
 * @author zhangshuo 
 * @version 1.0
 */
public class PullToRefreshView extends RelativeLayout { /**手指滑动距离与控件移动距离的比例为2:1*/
static final float FRICTION = 2.0f; /**显示“下拉刷新”的状态*/
static final int PULL_TO_REFRESH = 0x0;
/**显示“释放刷新”的状态*/
static final int RELEASE_TO_REFRESH = 0x1;
/**用户通过下拉进入的刷新状态*/
static final int REFRESHING = 0x2;
/**用户通过代码强制进入的刷新状态*/
static final int MANUAL_REFRESHING = 0x3; /**私有模式,不提供对外调用。
* 仅用来标示“用户下拉刷新成功后,headerView显示在头部,当用户手指向上滑动时。将headerView尾随用户滑动向上滑动”
* 及“用户上拉很多其它成功后,footerView显示在底部,当用户手指向下滑动时。将footerView尾随用户滑动向下滑动”这两个过程的模式*/
private static final int MODE_PULL_TO_SCROLL_HEADER_OR_FOOTER = 0x0;
/**标示当前支持下拉刷新模式*/
public static final int MODE_PULL_DOWN_TO_REFRESH = 0x1;
/**标示当前支持上拉很多其它模式*/
public static final int MODE_PULL_UP_TO_REFRESH = 0x2;
/**标示当前支持下拉刷新和上拉很多其它两种模式*/
public static final int MODE_BOTH = 0x3; private Context context;
/**滚动对象*/
private Scroller scroller;
/**推断用户手指的移动距离是否足以响应为move*/
private int touchSlop; private float initialMotionY;
private float lastMotionX;
private float lastMotionY;
private boolean isBeingDragged = false; /**记录headerView当前的状态*/
private int headerState = PULL_TO_REFRESH;
/**记录footerView当前的状态*/
private int footerState = PULL_TO_REFRESH;
/**当前所支持的模式*/
private int mode = MODE_PULL_DOWN_TO_REFRESH;
/**当前处于的模式*/
private int currentMode; /**依据不同的mode,contentView所在父View的位置不同,下拉刷新时为1,上拉很多其它时为1,上拉下拉都支持时为2*/
private int index = 1; /**标示当处于刷新状态时,是否须要禁用滑动*/
private boolean disableScrollingWhileRefreshing = false; /**标示是否同意滑动刷新*/
private boolean isPullToRefreshEnabled = true; private LoadingLayout headerLayout;
private LoadingLayout footerLayout;
private int headerHeight; /**记录当处于刷新状态时。用户继续下拉的次数*/
private int pullWithRefreshingCount = 0;
/**记录当处于载入很多其它状态时,用户继续上拉的次数*/
private int pullWithLoadingMoreCount = 0; /**刷新回调接口*/
private OnRefreshListener onRefreshListener; /**载入很多其它回调接口*/
private OnLoadMoreListener onLoadMoreListener; public PullToRefreshView(Context context) {
super(context);
init(context, null);
} public PullToRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
} /**
* @方法描写叙述: 初始化方法
* @作者:zhangshuo
* @param context
* @param attrs
*/
private void init(Context context, AttributeSet attrs) { scroller = new Scroller(context); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); this.context = context; this.addLoadingView();
} /**
* @方法描写叙述: 依据当前模式设置,载入头部和底部布局
* @作者:zhangshuo
*/
public void addLoadingView() { String pullDownLabel = context
.getString(R.string.pull_to_refresh_pull_down_label);
String refreshingDownLabel = context
.getString(R.string.pull_to_refresh_refreshing_down_label);
String releaseDownLabel = context
.getString(R.string.pull_to_refresh_release_down_label);
String pullUpLabel = context
.getString(R.string.pull_to_refresh_pull_up_label);
String refreshingUpLabel = context
.getString(R.string.pull_to_refresh_refreshing_up_label);
String releaseUpLabel = context
.getString(R.string.pull_to_refresh_release_up_label); /*载入头部和底部View*/
if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) {
headerLayout = new LoadingLayout(context,
MODE_PULL_DOWN_TO_REFRESH, releaseDownLabel, pullDownLabel,
refreshingDownLabel);
addView(headerLayout, 0, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
measureView(headerLayout);
headerHeight = headerLayout.getMeasuredHeight();
}
if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) {
footerLayout = new LoadingLayout(context, MODE_PULL_UP_TO_REFRESH,
releaseUpLabel, pullUpLabel, refreshingUpLabel);
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
addView(footerLayout, lp2);
measureView(footerLayout);
headerHeight = footerLayout.getMeasuredHeight();
} /*隐藏头部和底部View*/
switch (mode) {
case MODE_BOTH:
index = 2;
setPadding(0, -headerHeight, 0, -headerHeight);
break;
case MODE_PULL_UP_TO_REFRESH:
index = 1;
setPadding(0, 0, 0, -headerHeight);
break;
case MODE_PULL_DOWN_TO_REFRESH:
default:
index = 1;
setPadding(0, -headerHeight, 0, 0);
break;
} } /**
* 在头部和底部View增加完毕后。又一次布局。以避免在隐藏headerView和footerView时会把一部分内容(contentView)隐藏
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
View contentView = null;
RelativeLayout.LayoutParams lp1 = null;
switch (mode) {
case MODE_BOTH:
contentView = this.getChildAt(index);
lp1 = (LayoutParams) contentView.getLayoutParams();
lp1.setMargins(0, headerHeight, 0, headerHeight);
break;
case MODE_PULL_UP_TO_REFRESH:
contentView = this.getChildAt(index);
lp1 = (LayoutParams) contentView.getLayoutParams();
lp1.setMargins(0, 0, 0, headerHeight);
break;
case MODE_PULL_DOWN_TO_REFRESH:
default:
contentView = this.getChildAt(index);
lp1 = (LayoutParams) contentView.getLayoutParams();
lp1.setMargins(0, headerHeight, 0, 0);
break;
}
} 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);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
} @Override
public final boolean onInterceptTouchEvent(MotionEvent event) { Log.e("Intercept", "start"); if (!isPullToRefreshEnabled) {
return false;
} if ((isLoadingMore() || isRefreshing()) && disableScrollingWhileRefreshing) {
return true;
} final int action = event.getAction(); if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
isBeingDragged = false;
return false;
} if (action != MotionEvent.ACTION_DOWN && isBeingDragged) {
return true;
} switch (action) {
case MotionEvent.ACTION_DOWN: {
Log.e("Intercept", "down");
if (isReadyForPull()) {
lastMotionY = initialMotionY = event.getY();
lastMotionX = event.getX();
isBeingDragged = false;
}
break;
}
case MotionEvent.ACTION_MOVE: {
Log.e("Intercept", "move");
if (isReadyForPull()) {
final float y = event.getY();
final float dy = y - lastMotionY;
final float yDiff = Math.abs(dy);
final float xDiff = Math.abs(event.getX() - lastMotionX); if (yDiff > touchSlop && yDiff > xDiff) {
if ((mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH)
&& dy >= 0.0001f && isReadyForPullDown()) {
/*能够下拉刷新*/
lastMotionY = y;
isBeingDragged = true;
currentMode = MODE_PULL_DOWN_TO_REFRESH;
} else if ((mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH)
&& dy <= 0.0001f && isReadyForPullUp()) {
/*能够上拉很多其它*/
lastMotionY = y;
isBeingDragged = true;
currentMode = MODE_PULL_UP_TO_REFRESH;
}else if((isRefreshing() && getScrollY() < 0)|| (isLoadingMore() && getScrollY() > 0)){
/*当前headerView或footerView处于显示状态,开启尾随手指滑动模式*/
lastMotionY = y;
isBeingDragged = true;
currentMode = MODE_PULL_TO_SCROLL_HEADER_OR_FOOTER;
}
}
}
break;
}
}
return isBeingDragged;
} @Override
public final boolean onTouchEvent(MotionEvent event) {
Log.e("Touch", "start");
if (!isPullToRefreshEnabled) {
return false;
} if (isRefreshing() && disableScrollingWhileRefreshing) {
return true;
} if (event.getAction() == MotionEvent.ACTION_DOWN
&& event.getEdgeFlags() != 0) {
return false;
} switch (event.getAction()) { case MotionEvent.ACTION_DOWN: {
Log.e("Touch", "down");
if (isReadyForPull()) {
lastMotionY = initialMotionY = event.getY();
return true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
Log.e("Touch", "move");
if (isBeingDragged) {
lastMotionY = event.getY();
this.pullEvent();
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
Log.e("Touch", "up");
if (isBeingDragged) {
isBeingDragged = false; if(isRefreshing() && pullWithRefreshingCount == 0){
pullWithRefreshingCount = 1;
}
if(isLoadingMore() && pullWithLoadingMoreCount == 0){
pullWithLoadingMoreCount = 1;
} switch (currentMode) {
case MODE_PULL_TO_SCROLL_HEADER_OR_FOOTER:
/*将headerView和footerView隐藏*/
smoothScrollTo(0);
break;
case MODE_PULL_UP_TO_REFRESH:
/*推断是否激活载入很多其它*/
if (footerState == RELEASE_TO_REFRESH && null != onLoadMoreListener) {
setLoadingMoreInternal(true);
onLoadMoreListener.onLoadMore();
} else {
smoothScrollTo(0);
}
break;
case MODE_PULL_DOWN_TO_REFRESH:
/*推断是否激活刷新*/
if (headerState == RELEASE_TO_REFRESH && null != onRefreshListener) {
setRefreshingInternal(true);
onRefreshListener.onRefresh();
} else {
smoothScrollTo(0);
}
break;
} return true;
}
break;
}
} return false;
} /**
* @方法描写叙述: 处理用户滑动的方法
* @作者:zhangshuo
*
* @return
*/
private boolean pullEvent() { final int newHeight;
final int oldHeight = this.getScrollY(); switch (currentMode) {
case MODE_PULL_TO_SCROLL_HEADER_OR_FOOTER:
newHeight = Math.round((initialMotionY - lastMotionY));
break;
case MODE_PULL_UP_TO_REFRESH:
newHeight = Math.round(Math.max(initialMotionY - lastMotionY, 0)
/ FRICTION);
break;
case MODE_PULL_DOWN_TO_REFRESH:
default:
newHeight = Math.round(Math.min(initialMotionY - lastMotionY, 0)
/ FRICTION);
break;
} if(isRefreshing() && pullWithRefreshingCount == 0){
/*处于刷新状态下,第一次继续下拉。此时headerView已经显示在头部*/
if((-headerHeight + newHeight) < 0){
scrollTo(-headerHeight + newHeight);
}else{
scrollTo(0);
if(((ScrollView)getChildAt(index)).getChildAt(0).getHeight() > getChildAt(index).getHeight()){
getChildAt(index).scrollTo(0, newHeight - headerHeight);
}
}
}else if(isLoadingMore() && pullWithLoadingMoreCount == 0){
/*处于刷新状态下。第一次继续下拉。此时headerView已经显示在头部*/
if((headerHeight + newHeight) > 0){
scrollTo(headerHeight + newHeight);
}else{
scrollTo(0);
if(((ScrollView)getChildAt(index)).getChildAt(0).getHeight() > getChildAt(index).getHeight()){
getChildAt(index).scrollTo(0, newHeight + headerHeight + ((ScrollView)getChildAt(index)).getChildAt(0).getHeight() - getChildAt(index).getHeight());
}
}
}else{
scrollTo(newHeight);
} if (newHeight != 0) { switch (currentMode) {
case MODE_PULL_UP_TO_REFRESH:
if (footerState == PULL_TO_REFRESH && headerHeight < Math.abs(newHeight)) {
footerState = RELEASE_TO_REFRESH;
footerLayout.releaseToRefresh();
return true; } else if (footerState == RELEASE_TO_REFRESH
&& headerHeight >= Math.abs(newHeight)) {
footerState = PULL_TO_REFRESH;
footerLayout.pullToRefresh();
return true;
}
break;
case MODE_PULL_DOWN_TO_REFRESH:
if (headerState == PULL_TO_REFRESH && headerHeight < Math.abs(newHeight)) {
headerState = RELEASE_TO_REFRESH;
headerLayout.releaseToRefresh();
return true; } else if (headerState == RELEASE_TO_REFRESH
&& headerHeight >= Math.abs(newHeight)) {
headerState = PULL_TO_REFRESH;
headerLayout.pullToRefresh();
return true;
}
break;
} } return oldHeight != newHeight;
} /**
* @方法描写叙述: 推断当前状态能否够进行上拉很多其它或下拉刷新的滑动操作
* @作者:zhangshuo
* @return
*/
private boolean isReadyForPull() {
switch (mode) {
case MODE_PULL_DOWN_TO_REFRESH:
return isReadyForPullDown();
case MODE_PULL_UP_TO_REFRESH:
return isReadyForPullUp();
case MODE_BOTH:
return isReadyForPullUp() || isReadyForPullDown();
}
return false;
} /**
* @方法描写叙述: 推断当前状态能否够进行下拉刷新操作
* @作者:zhangshuo
* @return
*/
private boolean isReadyForPullDown() {
// TODO Auto-generated method stub
if (getChildCount() > 1) {
Log.e("Ready--down", String.valueOf(getChildCount()));
View childView = this.getChildAt(index);
if (childView instanceof ListView) {
int top = ((ListView) childView).getChildAt(0).getTop();
int pad = ((ListView) childView).getListPaddingTop();
if ((Math.abs(top - pad)) < 3
&& ((ListView) childView).getFirstVisiblePosition() == 0) {
return true;
} else {
return false;
}
} else if (childView instanceof ScrollView) {
Log.e("Ready--down", "scrollView");
if (((ScrollView) childView).getScrollY() == 0) {
return true;
} else {
return false;
}
} }
return false;
} /**
* @方法描写叙述:推断当前状态能否够上拉很多其它的滑动操作
* @作者:zhangshuo
* @return
*/
private boolean isReadyForPullUp() {
// TODO Auto-generated method stub
if (getChildCount() > 1) {
Log.e("Ready--up", String.valueOf(getChildCount()));
View childView = this.getChildAt(index);
if (childView instanceof ListView) {
int top = ((ListView) childView).getChildAt(
((ListView) childView).getCount()).getBottom();
int pad = ((ListView) childView).getListPaddingBottom();
if ((Math.abs(top - pad)) < 3
&& ((ListView) childView).getFirstVisiblePosition() == ((ListView) childView)
.getCount()) {
return true;
} else {
return false;
}
} else if (childView instanceof ScrollView) {
Log.e("Ready--up", "scrollView");
int off = ((ScrollView) childView).getScrollY()
+ ((ScrollView) childView).getHeight()
- ((ScrollView) childView).getChildAt(0).getHeight();
if (off >= 0) {
return true;
} else {
return false;
}
} }
return false;
} /**
* @方法描写叙述: 是否同意上拉很多其它或下拉刷新的滑动操作
* @作者:zhangshuo
* @return
*/
public final boolean isPullToRefreshEnabled() {
return isPullToRefreshEnabled;
} /**
* @方法描写叙述: 当处于刷新状态时,是否须要禁用滑动
* @作者:zhangshuo
* @return
*/
public final boolean isDisableScrollingWhileRefreshing() {
return disableScrollingWhileRefreshing;
} /**
* @方法描写叙述: 当前正处于刷新中
* @作者:zhangshuo
* @return
*/
public final boolean isRefreshing() {
return headerState == REFRESHING || headerState == MANUAL_REFRESHING;
} /**
* @方法描写叙述: 当前正处于载入很多其它中
* @作者:zhangshuo
* @return
*/
public final boolean isLoadingMore() {
return footerState == REFRESHING || footerState == MANUAL_REFRESHING;
} /**
* @方法描写叙述: 设置当处于刷新状态时。是否须要禁用滑动
* @作者:zhangshuo
* @param disableScrollingWhileRefreshing
*/
public final void setDisableScrollingWhileRefreshing(
boolean disableScrollingWhileRefreshing) {
this.disableScrollingWhileRefreshing = disableScrollingWhileRefreshing;
} /**
* @方法描写叙述: 结束刷新状态
* @作者:zhangshuo
*
*/
public final void onRefreshComplete() {
if (headerState != PULL_TO_REFRESH) {
resetHeader();
}
pullWithRefreshingCount = 0;
} /**
* @方法描写叙述: 结束载入很多其它状态
* @作者:zhangshuo
*
*/
public final void onLoadMoreComplete() {
if (footerState != PULL_TO_REFRESH) {
resetFooter();
}
pullWithLoadingMoreCount = 0;
} /**
* @方法描写叙述: 设置否同意滑动刷新
* @作者:zhangshuo
* @param enable
*/
public final void setPullToRefreshEnabled(boolean enable) {
this.isPullToRefreshEnabled = enable;
} /**
* @方法描写叙述: 强制设置为刷新状态
* @作者:zhangshuo
*/
public final void setRefreshing() {
this.setRefreshing(true);
} /**
* @方法描写叙述: 强制设置为载入很多其它状态
* @作者:zhangshuo
*/
public final void setLoadingMore(){
this.setLoadingMore(true);
} /**
* @方法描写叙述: 强制设置为刷新状态
* @作者:zhangshuo
* @param doScroll
*/
public final void setRefreshing(boolean doScroll) {
if (!isRefreshing()) {
setRefreshingInternal(doScroll);
headerState = MANUAL_REFRESHING;
}
} /**
* @方法描写叙述: 强制设置为载入很多其它状态
* @作者:zhangshuo
* @param doScroll
*/
public final void setLoadingMore(boolean doScroll) {
if (!isLoadingMore()) {
setLoadingMoreInternal(doScroll);
footerState = MANUAL_REFRESHING;
}
} protected final int getCurrentMode() {
return currentMode;
} protected final LoadingLayout getFooterLayout() {
return footerLayout;
} protected final LoadingLayout getHeaderLayout() {
return headerLayout;
} protected final int getHeaderHeight() {
return headerHeight;
} protected final int getMode() {
return mode;
} /**
* @方法描写叙述: 重置headerView
* @作者:zhangshuo
*/
protected void resetHeader() {
headerState = PULL_TO_REFRESH;
isBeingDragged = false; if (null != headerLayout) {
headerLayout.reset();
} smoothScrollTo(0);
} /**
* @方法描写叙述: 重置footerView
* @作者:zhangshuo
*/
protected void resetFooter() {
footerState = PULL_TO_REFRESH;
isBeingDragged = false; if (null != footerLayout) {
footerLayout.reset();
} smoothScrollTo(0);
} /**
* @方法描写叙述: 强制设置为刷新状态,并显示出headerView
* @作者:zhangshuo
* @param doScroll
*/
protected void setRefreshingInternal(boolean doScroll) {
headerState = REFRESHING;
pullWithRefreshingCount = 0; if (null != headerLayout) {
headerLayout.refreshing();
} if (doScroll) {
smoothScrollTo(-headerHeight);
}
} /**
* @方法描写叙述: 强制设置为载入很多其它状态,并显示出footerView
* @作者:zhangshuo
* @param doScroll
*/
protected void setLoadingMoreInternal(boolean doScroll) {
footerState = REFRESHING;
pullWithLoadingMoreCount = 0; if (null != footerLayout) {
footerLayout.refreshing();
} if (doScroll) {
smoothScrollTo(headerHeight);
}
} protected final void scrollTo(int y) {
scrollTo(0, y);
} protected final void smoothScrollTo(int y) { scroller.startScroll(0, getScrollY(), 0, -(getScrollY() - y), 500);
invalidate(); } @Override
public void computeScroll() {
// TODO Auto-generated method stub
if (scroller.computeScrollOffset()) {
scrollTo(0, this.scroller.getCurrY());
postInvalidate();
}
} /**
* @方法描写叙述: 设置刷新回调接口
* @作者:zhangshuo
* @param listener
*/
public final void setOnRefreshListener(OnRefreshListener listener) {
this.onRefreshListener = listener;
} /**
* @方法描写叙述: 设置载入很多其它回调接口
* @作者:zhangshuo
* @param listener
*/
public final void setOnLoadMoreListener(OnLoadMoreListener listener){
this.onLoadMoreListener = listener;
} /**
* @CLASS:OnRefreshListener
* @描写叙述: 刷新回调接口
* @作者:zhangshuo
* @版本号:v1.0
* @日期:2014年7月15日 上午11:59:50
*/
public static interface OnRefreshListener { public void onRefresh(); } /**
* @CLASS:OnLoadMoreListener
* @描写叙述: 载入很多其它回调接口
* @作者:zhangshuo
* @版本号:v1.0
* @日期:2014年7月15日 下午12:00:06
*/
public static interface OnLoadMoreListener { public void onLoadMore(); } }
<span style="font-size:24px;">因为时间关系,我主要測试了ScrollView,代码中已实现ListView下拉和上拉刷新,只是没有怎么測。</span>
<span style="font-size:24px;">至于GridView、WebView等,代码中没有实现。只是非常好拓展,在isReadyForPullUp() 和 
isReadyForPullDown()这两个方法中增加对应的View的上下边界推断就OK了!</span>

源代码下载地址:http://download.csdn.net/detail/super_spy/7642641

Android PullToRefresh 下拉刷新,上拉很多其它,支持ScrollView,ListView,可方便拓展GridView,WebView等的更多相关文章

  1. Android 下拉刷新上拉载入 多种应用场景 超级大放送(上)

    转载请标明原文地址:http://blog.csdn.net/yalinfendou/article/details/47707017 关于Android下拉刷新上拉载入,网上的Demo太多太多了,这 ...

  2. RecyclerView下拉刷新上拉加载(一)

    listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...

  3. 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载

    title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...

  4. ListView实现Item上下拖动交换位置 并且实现下拉刷新 上拉加载更多

    ListView实现Item上下拖动交换位置  并且实现下拉刷新  上拉加载更多 package com.example.ListViewDragItem; import android.app.Ac ...

  5. JS+CSS实现的下拉刷新/上拉加载插件

    闲来无事,写了一个当下比较常见的下拉刷新/上拉加载的jquery插件,代码记录在这里,有兴趣将代码写成插件与npm包可以留言. 体验地址:http://owenliang.github.io/pull ...

  6. 基于SwiperJs的H5/移动端下拉刷新上拉加载更多的效果

    最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...

  7. ListView下拉刷新上拉加载更多实现

    这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...

  8. RecyclerView下拉刷新上拉加载(三)—对Adapter的封装

    RecyclerView下拉刷新上拉加载(一) http://blog.csdn.net/baiyuliang2013/article/details/51506036 RecyclerView下拉刷 ...

  9. listview下拉刷新上拉加载扩展(二)-仿美团外卖

    经过前几篇的listview下拉刷新上拉加载讲解,相信你对其实现机制有了一个深刻的认识了吧,那么这篇文章我们来实现一个高级的listview下拉刷新上拉加载-仿新版美团外卖的袋鼠动画: 项目结构: 是 ...

  10. 基于SwiperJs的H5/移动端下拉刷新上拉加载更多

    最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...

随机推荐

  1. 文件操作-cd

    cd命令是linux实际使用当中另一个非常重要的命令,本文就为大家介绍下Linux中cd命令的用法. 转载自 https://www.cnblogs.com/waitig/p/5880719.html ...

  2. PWA天气应用

    https://codelabs.developers.google.com/codelabs/your-first-pwapp/#0 1.介绍 这里将使用PWA技术来构建一个天气web应用,这个ap ...

  3. Python把类当做字典来访问

    定义一个类将它实例化,我们可以通过obj.属性来访问类的属性,如果想获取类的所有实例变量,我们可以使用obj.__dict__来访问,如下: class A: def __init__(self): ...

  4. (原)剑指offer跳台阶和矩形覆盖

    跳台阶 时间限制:1秒空间限制:32768K 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法.   分析同样为斐波那契数列边形这样的题肯定有公式 设 ...

  5. POJ:3461-Oulipo(KMP模板题)

    原题传送:http://poj.org/problem?id=3461 Oulipo Time Limit: 1000MS Memory Limit: 65536K Description The F ...

  6. cf 1016D

    D. Vasya And The Matrix time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  7. Handler处理器和自定义Opener

    Handler处理器 和 自定义Opener opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构 ...

  8. TOJ 4701 求阴影部分面积

    4701: 求阴影部分面积  本文版权归BobHuang和博客园共有,不得转载.如想转载,请联系作者,并注明出处. Time Limit(Common/Java):1000MS/3000MS     ...

  9. 在VS2017中编写Python程序

    最近开始了python的学习,在搭建完python环境之后,在选择IDE的时候陷入了困境,首先选择的是PyCharm但是用着还是不习惯,毕竟用VS开发了几年了,突然换软件总感觉有点不适应,就想到了强大 ...

  10. Git 常用命令整理(持续更新)

    #配置 git config --global user.name "Your Name" git config --global user.email "email@e ...