一、前言:

很多应用都会用到ListView,当然如果是iOS就会用UITableViewController,这两个控件在不同的OS上,功能是一样的,只是有些细微的不同(iOS的UITableViewController支持静态与动态两种),不过,大多数应用都用的是动态属性,那么,这里就涉及到一个问题:刷新及加载更多内容。

目前网上流行的有两种方式:

1. 通用的方法,即将ListView, GridView和ScrollView当成ChildView,在这顶部及底部各加一个Layout,但是,一但出现了,就一直显示在顶部或底部,并不会随着ChildView的滚动而滚动,功能实用,就是有点破坏美感;

2. 各自实现,即如果需要实现ListView的下拉刷新和上拉更多,那么就得去继承ListView,并对它的HeaderView和FooterView做一些扩展,同理,GridView和ScrollView;

本篇将使用第二种方法来实现,如果通过继承ListView的方式,来实现下拉刷新,以及上拉更多,或者是点击底部加载更多的。

二、实现:

2.1 HeaderView的布局,以及代码实现

<?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="wrap_content"
android:background="#ffffff"
android:gravity="bottom"> <RelativeLayout
android:id="@+id/header_content"
android:layout_width="match_parent"
android:layout_height="60dip"> <LinearLayout
android:id="@+id/layoutTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"> <TextView
android:id="@+id/refresh_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text="@string/pull_down_for_refresh"/> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="4dip"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="@string/label_update"/>
<TextView
android:id="@+id/refresh_last_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="@string/label_last_time"/> </LinearLayout> </LinearLayout> <ImageView
android:id="@+id/ivArrow"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toLeftOf="@id/layoutTitle"
android:layout_centerInParent="true"
android:layout_marginRight="30dip"
android:contentDescription="@string/image_desc"
android:src="@drawable/refresh_arrow_down"/> <ProgressBar
android:id="@+id/pbWaiting"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toLeftOf="@id/layoutTitle"
android:layout_centerInParent="true"
android:layout_marginRight="30dip"
style="?android:attr/progressBarStyleSmall"/> </RelativeLayout> </LinearLayout>

布局很简单,一些TextView,一个ImageView和一个ProgressBar。再来看看代码实现

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; public class HeaderView extends LinearLayout { public final static int STATE_NORMAL = 0;
public final static int STATE_WILL_RELEASE = 1;
public final static int STATE_REFRESHING = 2;
private int mState = STATE_NORMAL; private View mHeader = null;
private ImageView mArrow = null;
private ProgressBar mProgressBar = null;
private TextView mRefreshTips = null;
//private TextView mRefreshLastTime = null;
private RotateAnimation mRotateUp = null;
private RotateAnimation mRotateDown = null;
private final static int ROTATE_DURATION = 250; public HeaderView(Context context) {
this(context, null);
} public HeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView(context);
} private void initHeaderView(Context context){
LinearLayout.LayoutParams lp = new LayoutParams(
LayoutParams.MATCH_PARENT, 0);
mHeader = LayoutInflater.from(context).inflate(R.layout.refresh_header, null);
addView(mHeader, lp);
setGravity(Gravity.BOTTOM); mArrow = (ImageView) mHeader.findViewById(R.id.ivArrow);
mProgressBar = (ProgressBar) mHeader.findViewById(R.id.pbWaiting);
mRefreshTips = (TextView) mHeader.findViewById(R.id.refresh_tips);
//mRefreshLastTime = (TextView) mHeader.findViewById(R.id.refresh_last_time); mRotateUp = new RotateAnimation(0.0f, -180.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateUp.setDuration(ROTATE_DURATION);
mRotateUp.setFillAfter(true); mRotateDown = new RotateAnimation(-180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateDown.setDuration(ROTATE_DURATION);
mRotateDown.setFillAfter(true);
} public void setHeaderState(int state){
if(mState == state){
return;
} mArrow.clearAnimation();
if(state == STATE_REFRESHING){
mProgressBar.setVisibility(View.VISIBLE);
mArrow.setVisibility(View.GONE);
}else{
mProgressBar.setVisibility(View.GONE);
mArrow.setVisibility(View.VISIBLE);
} switch(state){
case STATE_NORMAL:
mArrow.startAnimation(mRotateDown);
mRefreshTips.setText(R.string.pull_down_for_refresh);
break; case STATE_WILL_RELEASE:
mArrow.startAnimation(mRotateUp);
mRefreshTips.setText(R.string.release_for_refresh);
break; case STATE_REFRESHING:
mRefreshTips.setText(R.string.refreshing);
break; default:
break;
} mState = state;
} public int getCurrentState(){
return mState;
} public void setHeaderHeight(int height){
if(height <= 0){
height = 0;
}
LayoutParams lp = (LayoutParams) mHeader.getLayoutParams();
lp.height = height;
mHeader.setLayoutParams(lp);
}
public int getHeaderHeight(){
return mHeader.getHeight();
}
}

这个代码中,主要就两个函数:setHeaderState 和 setHeaderHeight。 前者是根据TouchEvent,以及当前移动的距离,来设置状态,同时,移动的距离去设置HeaderView的高度,达到一点一点的显示出来。

2.2 FooterView的布局,以及代码实现

看了HeaderView的布局与实现后,FooterView的布局与实现也差不多,咱们一起来看看吧

<?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="wrap_content"
android:gravity="top" > <RelativeLayout
android:id="@+id/footer_content"
android:layout_width="match_parent"
android:layout_height="60dip" > <TextView
android:id="@+id/loader_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/pull_up_for_more"
android:textSize="15sp" /> <ImageView
android:id="@+id/ivLoaderArrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginRight="30dip"
android:layout_toLeftOf="@id/loader_tips"
android:contentDescription="@string/image_desc"
android:src="@drawable/refresh_arrow_up" /> <ProgressBar
android:id="@+id/pbLoaderWaiting"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginRight="30dip"
android:layout_toLeftOf="@id/loader_tips"
android:visibility="gone" />
</RelativeLayout> </LinearLayout>

哇,这个布局比HeaderView布局还要简单!?这个布局涵盖了两部分,不过,在布局中无法体现出来,但在代码实现中体现出来了:

1. 上拉更多,这个布局全部显示;

2. 如果是滑到底部点击加载,就不会有ImageView;

还是来看看代码实现吧

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; public class FooterView extends LinearLayout { public final static int FOOTER_OPTIONS_PULL = 0;
public final static int FOOTER_OPTIONS_CLICK = 1;
private static int sFooterOps = FOOTER_OPTIONS_PULL; public final static int STATE_NORMAL = 0;
public final static int STATE_WILL_RELEASE = 1;
public final static int STATE_LOADING = 2;
private int mState = STATE_NORMAL; private View mFooter = null;
private ImageView mArrow = null;
private ProgressBar mProgressBar = null;
private TextView mLoaderTips = null; private RotateAnimation mRotateUp = null;
private RotateAnimation mRotateDown = null;
private final static int ROTATE_DURATION = 250; public FooterView(Context context) {
this(context, null);
} public FooterView(Context context, AttributeSet attrs) {
super(context, attrs);
initFooterView(context);
} private void initFooterView(Context context){
LinearLayout.LayoutParams lp = new LayoutParams(
LayoutParams.MATCH_PARENT, 0);
mFooter = LayoutInflater.from(context).inflate(R.layout.loader_footer, null);
addView(mFooter, lp); mArrow = (ImageView) mFooter.findViewById(R.id.ivLoaderArrow);
mProgressBar = (ProgressBar) mFooter.findViewById(R.id.pbLoaderWaiting);
mLoaderTips = (TextView) mFooter.findViewById(R.id.loader_tips); mRotateDown = new RotateAnimation(0.0f, 180.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateDown.setDuration(ROTATE_DURATION);
mRotateDown.setFillAfter(true); mRotateUp = new RotateAnimation(180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateUp.setDuration(ROTATE_DURATION);
mRotateUp.setFillAfter(true); setFooterViewOptions(FOOTER_OPTIONS_CLICK);
} public void setFooterViewOptions(int options){
sFooterOps = options; switch(sFooterOps){
case FOOTER_OPTIONS_PULL:
hide();
break; case FOOTER_OPTIONS_CLICK:
show();
break; default:
break;
}
} public int getFooterViewOptions(){
return sFooterOps;
} public void setFooterState(int state){
if(mState == state){
return;
} mArrow.clearAnimation();
if(state == STATE_LOADING){
mProgressBar.setVisibility(View.VISIBLE);
mArrow.setVisibility(View.GONE);
}else{
mProgressBar.setVisibility(View.GONE);
mArrow.setVisibility(View.VISIBLE);
} switch(state){
case STATE_NORMAL:
mArrow.startAnimation(mRotateUp);
mLoaderTips.setText(R.string.pull_up_for_more);
break; case STATE_WILL_RELEASE:
mArrow.startAnimation(mRotateDown);
mLoaderTips.setText(R.string.release_for_more);
break; case STATE_LOADING:
mLoaderTips.setText(R.string.loading);
break; default:
break;
}
mState = state;
} public int getCurrentState(){
return mState;
} public void setFooterHeight(int height){
if(height <= 0){
height = 0;
} LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
lp.height = height;
mFooter.setLayoutParams(lp);
} public int getFooterHeight(){
return mFooter.getHeight();
} public void hide(){
mArrow.clearAnimation();
mArrow.setVisibility(View.VISIBLE);
mLoaderTips.setText(R.string.pull_up_for_more);
setFooterHeight(0);
} public void show(){
mArrow.clearAnimation();
mArrow.setVisibility(View.GONE);
mLoaderTips.setText(R.string.click_for_more); LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
lp.height = LayoutParams.WRAP_CONTENT;
mFooter.setLayoutParams(lp);
}
}

代码中,有个Options函数,用来提供设置:上拉或点击。同样,也有设置状态,和设计高度。

2.3 扩展ListView的实现

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.AbsListView.OnScrollListener; public class ListViewExt extends ListView implements OnScrollListener { private final static String TAG = "ChrisLV"; private HeaderView mHeaderView = null;
private RelativeLayout mHeaderContent = null;
private int iHeaderHeight = 0; private FooterView mFooterView = null;
private RelativeLayout mFooterContent = null;
private int iFooterHeight = 0; private final static int SCROLL_HEADER = 0;
private final static int SCROLL_FOOTER = 1;
private int iScrollWhich = SCROLL_HEADER; private Scroller mScroller = null;
private final static float OFFSET_Y = 0.7f;
private float iLastY = 0;
private int mTotalNumber = 0; public ListViewExt(Context context) {
this(context, null, 0);
}
public ListViewExt(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ListViewExt(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
} private void initView(Context context){
/*
* mScroller用来回弹下拉刷新/上拉更多
* 配合computerScroll来使用
*/
mScroller = new Scroller(context, new DecelerateInterpolator());
super.setOnScrollListener(this); initHeaderView(context);
initFooterView(context);
} @Override
public void setAdapter(ListAdapter adapter) {
if(getFooterViewsCount() == 0){
addFooterView(mFooterView);
}
super.setAdapter(adapter);
} @Override
public boolean onTouchEvent(MotionEvent ev) { switch(ev.getAction()){
case MotionEvent.ACTION_DOWN:
iLastY = ev.getY();
break; case MotionEvent.ACTION_MOVE:
float deltaY = ev.getY() - iLastY;
iLastY = ev.getY();
if(canHeaderPull() && getFirstVisiblePosition() == 0 &&
(deltaY > 0 || mHeaderView.getHeaderHeight() > 0)){
updateHeaderState(deltaY * OFFSET_Y);
}else if(canFooterPull() && getLastVisiblePosition() == mTotalNumber - 1
&& (deltaY < 0 || mFooterView.getFooterHeight() > 0)){
updateFooterState(-deltaY * OFFSET_Y);
}
break; case MotionEvent.ACTION_UP:
if(getFirstVisiblePosition() == 0){
if(mHeaderView.getHeaderHeight() > iHeaderHeight){
mHeaderView.setHeaderState(HeaderView.STATE_REFRESHING);
if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
mFooterView.hide();
}
}
resetHeader();
}else if(getLastVisiblePosition() == mTotalNumber - 1){
if(mFooterView.getFooterHeight() > iFooterHeight){
mFooterView.setFooterState(FooterView.STATE_LOADING);
}
resetFooter();
}
break; default:
break;
}
return super.onTouchEvent(ev);
} @Override
public void computeScroll() {
if(mScroller.computeScrollOffset()){
if(iScrollWhich == SCROLL_HEADER){
mHeaderView.setHeaderHeight(mScroller.getCurrY());
}else if(iScrollWhich == SCROLL_FOOTER){
mFooterView.setFooterHeight(mScroller.getCurrY());
}
}
super.computeScroll();
} /*
* 获取ListView有多少个item:
* 1. 在init中,需要设置super.setOnScrollListener;
* 2. 重载以下两个函数;
* 3. 在onScroll中取得totalItemCount即可;
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mTotalNumber = totalItemCount;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/////////////////////////////////////////////////////////////////////////////
private boolean canHeaderPull(){
if(mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
return true;
}
return false;
} private boolean canFooterPull(){
if(mHeaderView.getCurrentState() == HeaderView.STATE_NORMAL){
return true;
}
return false;
}
///////////////////////////////////// Header ////////////////////////////////
public void stopRefresh(){
if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
resetHeader();
if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
mFooterView.show();
}
}
} private void initHeaderView(Context context){
mHeaderView = new HeaderView(context);
mHeaderContent = (RelativeLayout) mHeaderView.findViewById(R.id.header_content);
addHeaderView(mHeaderView);
mHeaderView.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
iHeaderHeight = mHeaderContent.getHeight();
Log.d(TAG, "iHeaderHeight = " + iHeaderHeight);
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
} private void updateHeaderState(float delta){
mHeaderView.setHeaderHeight((int)(delta + mHeaderView.getHeaderHeight()));
if(mHeaderView.getCurrentState() != HeaderView.STATE_REFRESHING){
if(mHeaderView.getHeaderHeight() > iHeaderHeight){
mHeaderView.setHeaderState(HeaderView.STATE_WILL_RELEASE);
}else{
mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
}
}
setSelection(0);
} private void resetHeader(){
int height = mHeaderView.getHeaderHeight();
if(height == 0){
return;
} int finalHeight = 0;
if(height > iHeaderHeight){
/*
* 如果超过HeaderView高度,则回滚到HeaderView高度即可
*/
finalHeight = iHeaderHeight;
}else if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
/*
* 如果HeaderView未完全显示
* 1. 处于正在刷新中,则不管;
* 2. 回滚HeaderView当前可视高度
*/
return;
} iScrollWhich = SCROLL_HEADER;
mScroller.startScroll(0, height, 0, finalHeight - height, 250);
invalidate();
}
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// Footer ////////////////////////////////
public void setFooterMode(int options){
mFooterView.setFooterViewOptions(options);
} public void stopLoad(){
if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
mFooterView.setFooterState(FooterView.STATE_NORMAL);
resetFooter();
}
} private void initFooterView(Context context){
mFooterView = new FooterView(context);
mFooterContent = (RelativeLayout) mFooterView.findViewById(R.id.footer_content);
mFooterContent.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK
&& mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
mFooterView.setFooterState(FooterView.STATE_LOADING);
}
}
});
mFooterView.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
iFooterHeight = mFooterContent.getHeight();
Log.d(TAG, "iFooterHeight = " + iFooterHeight);
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
} private void updateFooterState(float delta){
if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
return;
} mFooterView.setFooterHeight((int)(delta + mFooterView.getFooterHeight()));
if(mFooterView.getCurrentState() != FooterView.STATE_LOADING){
if(mFooterView.getFooterHeight() > iFooterHeight){
mFooterView.setFooterState(FooterView.STATE_WILL_RELEASE);
}else{
mFooterView.setFooterState(FooterView.STATE_NORMAL);
}
}
} private void resetFooter(){
int height = mFooterView.getFooterHeight();
if(height == 0){
return;
} if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
return;
} int finalHeight = 0;
if(height > iFooterHeight){
finalHeight = iFooterHeight;
}else if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
return;
} iScrollWhich = SCROLL_FOOTER;
mScroller.startScroll(0, height, 0, finalHeight - height, 250);
invalidate();
}
/////////////////////////////////////////////////////////////////////////////
}

代码结构比较清楚,相关的都集中在一起,大致流程是:

1. down时,记住坐标;

2. move时,判断当前可见是否是第一个或是最后一个,如果是,则将移动的距离去设置HeaderView或FooterView的高度,达到一点一点的显示出来;

3. up时,判断HeaderView或FooterView是否滚动的距离超过它们的高度,如果是,则表示是刷新或加载,且回弹到移动的距离-高度;

4. 代码还提供了冲突设置,即如果当前正在刷新中,则不允许滚动到底部上拉更多,或者显示“点击加载更多”,同样,如果是底部正在加载,则不允许滚动到顶多,下拉刷新;

2.4 使用举例

首页布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" > <com.chris.list.refresh.ListViewExt
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#000000"
android:dividerHeight="0.5dip"/> </RelativeLayout>

首页Activity代码实现,和一般的使用ListView方法一样

package com.chris.list.refresh;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.app.Activity; public class MainActivity extends Activity { private final static String TAG = "ChrisLV";
private ListViewExt mListView = null;
private String[] mList = {
"abcd1", "abcd2", "abcd3", "abcd4", "abcd5", "abcd6",
"abcd7", "abcd8", "abcd9", "abcd10", "abcd11", "abcd12",
"abcd13", "abcd14", "abcd15", "abcd16", "abcd17", "abcd18",
"abcd19", "abcd20", "abcd21", "abcd22", "abcd23", "abcd24"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mListView = (ListViewExt) findViewById(R.id.listview);
mListView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
mList)); mListView.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Log.d(TAG, "arg2 = " + arg2);
if(arg2 > 0){
mListView.stopRefresh();
mListView.stopLoad();
} mListView.setFooterMode(arg2 % 2);
}
});
} }

在onItemClick中,只是做了简单的将HeaderView或FooterView停止,并设置FooterView的加载模式:是上拉更多,还是点击加载更多。

三、小结

本篇文章,大致就这么多,虽然,为了UI体验友好,花了很多精力,但是一通百通,其它的也不外乎是这些,所以大家学习后,希望能举一反三,同时,咱们也交流交流。

源码下载地址: http://download.csdn.net/detail/qingye_love/5597623

ListView下拉刷新及上拉更多两种状态的更多相关文章

  1. ListView下拉刷新、上拉载入更多之封装改进

    在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...

  2. google官方的下拉刷新+自定义上拉加载更多

    转载请标注转载:http://blog.csdn.net/oqihaogongyuan/article/details/50949118 google官方的下拉刷新+自定义上拉加载更多 现在很多app ...

  3. Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件

    原文 http://blog.csdn.net/bboyfeiyu/article/details/39253051       前言 下 拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采 ...

  4. Android XListView下拉刷新、上拉载入更多

    source code: https://github.com/Maxwin-z/XListView-Android 提供了两个接口: a) IXListViewListener:  触发下拉刷新.上 ...

  5. 【Android - 自定义View】之自定义可下拉刷新或上拉加载的ListView

    首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 RefreshableListView ,继承自ListView类: (2)在这个自定义View中,用户可以设置是否支持下拉刷新 ...

  6. 微信小程序开发之 下拉刷新,上拉加载更多

    本文记载了如何在微信小程序里面实现下拉刷新,上拉加载更多 先开看一下界面 大致如此的界面吧. 这个Demo使用了微信的几个Api和事件,我先列出来. 1.wx.request (获取远程服务器的数据, ...

  7. iOS开发 XML解析和下拉刷新,上拉加载更多

    iOS开发 XML解析和下拉刷新,上拉加载更多 1.XML格式 <?xml version="1.0" encoding="utf-8" ?> 表示 ...

  8. 【Web】移动端下拉刷新、上拉加载更多插件

    移动网站中常常有的功能:列表的下拉刷新.上拉加载更多 本例介绍一种简单使用的移动端下拉刷新.上拉加载更多插件,下载及参考地址:https://github.com/ximan/dropload 插件依 ...

  9. vue2.0 移动端,下拉刷新,上拉加载更多插件,修改版

    在[实现丰盛]的插件基础修改[vue2.0 移动端,下拉刷新,上拉加载更多 插件], 1.修改加载到尾页面,返回顶部刷新数据,无法继续加重下一页 2.修改加载完成文字提示 原文链接:http://ww ...

  10. vue+better-scroll 下拉刷新,上拉加载更多

    better-scroll 来做下拉刷新和 上拉加载 特别方便.  安装好vue脚手架和better-scroll 之后 直接复制粘贴就可以看到效果了 <template> <div ...

随机推荐

  1. 设置cell背景色半透明

    cell.backgroundColor = [UIColor colorWithRed:(247.0/255.0) green:(151.0/255.0) blue:(121.0/255.0) al ...

  2. 【Tomcat】使用Eclipse发布项目时,项目启动路径错误。

    这种情况下,,通常会去C:\User\[USERNAME]\或者Tomcat路径下面的一个temp文件夹里面找项目文件,由此出现报错. 这时候解决方法为: 双击Eclipse的Servers里面的to ...

  3. Mac下搭建SVN服务器

    1.检查机器上是否安装svnserve zhangdeqiangdeiMac:Downloads hengjiang$ svnserve --version svnserve, version (r1 ...

  4. 密码输入模块getpass

    getpass模块用于命令行输入密码,它提供了两个函数.         getpass.getpass([prompt[, stream]])         提示用户输入密码,同时不显示输入的密码 ...

  5. ajaxFileUpload用法

    首先要引入两个js <script type="text/javascript" src="/static/js/jquery.js"></s ...

  6. 国内外主流BI厂商对比

    BI(Business Intelligence),即商业智能或者商务智能,它是一套完整的解决方案,用来将企业中现有的数据进行有效的整合,快速准确的提供报表并提出决策依据,帮助企业做出明智的业务经营决 ...

  7. Tomcat+redis+nginx配置

    为客户开发的一个绩效系统,采用了java web的开发方式,使用了一些spring mvc, mybatis之类的框架.相比于oracle ebs的二次开发,这种开发更加灵活,虽然和ebs集成的时候遇 ...

  8. [HDU 3336]Count the String[kmp][DP]

    题意: 求一个字符串的所有前缀串的匹配次数之和. 思路: 首先仔细思考: 前缀串匹配. n个位置, 以每一个位置为结尾, 就可以得到对应的一个前缀串. 对于一个前缀串, 我们需要计算它的匹配次数. k ...

  9. Strata 2014 上的 AzureCAT 粉笔会谈

     本周,AzureCAT 团队非常高兴在 Strata 会议上首次集体亮相.对于那些对 AzureCAT 团队不太熟悉的人来说,我们是 Microsoft 云与企业部门一个核心的国际性团队,由大约 ...

  10. java学习之坦克大战游戏

    总结:由于这几天快过年比较忙然后没怎么写,写代码途中一些经验总结现在给忘记了.这次的小项目感觉比上次写的思路清楚了点.没有之前第一次写那么逻辑混乱,结构也搞的比之前的要好,添加功能比较容易.学习了之前 ...