Skip to content
2 changes: 1 addition & 1 deletion AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="7" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21"/>

<application
android:icon="@drawable/ic_launcher"
Expand Down
13 changes: 11 additions & 2 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ An ListView support "pull down refresh" and "pull up load" feature.
How to use:
Just replace ListView by me.maxwin.XListView.

Screenshots see the Wiki plz.
ChangeLogs:
1, the attribute of 'pull_to_bottom_refresh' was added.
2, the attribute of 'pull_to_top_load_more' was added.

已停止维护 by maxwin 2014
so, you could set 'setPullRefreshEnable(boolean)' and 'setPullLoadEnable(boolean)' by layout files not by codes.


Feature needed:

1, when the height of XListView's content is lower than the height of XListView, the footerview need to be gone/invisible automatically.

when I was available and found a solution of it, I would complete this. Wait, please.
2 changes: 1 addition & 1 deletion project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
# project structure.

# Project target.
target=android-7
target=android-21
android.library=false
10 changes: 8 additions & 2 deletions res/layout/main.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xlistview="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" android:background="#f0f0f0">
android:background="#f0f0f0"
android:orientation="vertical" >

<TextView
android:layout_width="fill_parent"
Expand All @@ -12,7 +15,10 @@
<me.maxwin.view.XListView
android:id="@+id/xListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:cacheColorHint="#00000000">
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
xlistview:pull_to_bottom_refresh="false"
xlistview:pull_to_top_load_more="false" >
</me.maxwin.view.XListView>

</LinearLayout>
9 changes: 9 additions & 0 deletions res/values/attrs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="XListView">
<attr name="pull_to_bottom_refresh" format="boolean" />
<attr name="pull_to_top_load_more" format="boolean" />
</declare-styleable>

</resources>
17 changes: 10 additions & 7 deletions src/me/maxwin/XListViewActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.format.DateFormat;
import android.widget.ArrayAdapter;

public class XListViewActivity extends Activity implements IXListViewListener {
Expand All @@ -16,34 +17,35 @@ public class XListViewActivity extends Activity implements IXListViewListener {
private Handler mHandler;
private int start = 0;
private static int refreshCnt = 0;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
geneItems();
mListView = (XListView) findViewById(R.id.xListView);
mListView.setPullLoadEnable(true);
mAdapter = new ArrayAdapter<String>(this, R.layout.list_item, items);
mListView.setAdapter(mAdapter);
// mListView.setPullLoadEnable(false);
// mListView.setPullRefreshEnable(false);
mListView.setPullLoadEnable(true);
mListView.setPullRefreshEnable(true);
mListView.setXListViewListener(this);
mHandler = new Handler();
}

private void geneItems() {
for (int i = 0; i != 20; ++i) {
for (int i = 0; i != 5; ++i) {
items.add("refresh cnt " + (++start));
}
}

private void onLoad() {
mListView.stopRefresh();
mListView.stopLoadMore();
mListView.setRefreshTime("刚刚");
mListView.setRefreshTime(DateFormat.format(
XListView.DATE_FORMAT_PARTTEN, System.currentTimeMillis()));
}

@Override
public void onRefresh() {
mHandler.postDelayed(new Runnable() {
Expand All @@ -53,7 +55,8 @@ public void run() {
items.clear();
geneItems();
// mAdapter.notifyDataSetChanged();
mAdapter = new ArrayAdapter<String>(XListViewActivity.this, R.layout.list_item, items);
mAdapter = new ArrayAdapter<String>(XListViewActivity.this,
R.layout.list_item, items);
mListView.setAdapter(mAdapter);
onLoad();
}
Expand Down
75 changes: 53 additions & 22 deletions src/me/maxwin/view/XListView.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

import me.maxwin.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.SystemClock;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
Expand All @@ -23,8 +27,19 @@
import android.widget.Scroller;
import android.widget.TextView;

/**
* @ClassName: XListView
* @Description: 1, new attrs added. For example, pull_to_bottom_refresh,
* pull_to_top_load_more. 2, set Automatically footer
* mPullLoadMore false when children isn't full of XListView
* @author SilentKnight || happychinapc@gmail.com
* @date 2015年1月20日 下午5:42:02
*
*/
public class XListView extends ListView implements OnScrollListener {

private static final String TAG = XListView.class.getSimpleName();
public static final String DATE_FORMAT_PARTTEN = "MM-dd kk:mm:ss";
private SharedPreferences sharedPref;
private float mLastY = -1; // save event y
private Scroller mScroller; // used for scroll back
private OnScrollListener mScrollListener; // user's scroll listener
Expand All @@ -39,15 +54,15 @@ public class XListView extends ListView implements OnScrollListener {
private RelativeLayout mHeaderViewContent;
private TextView mHeaderTimeView;
private int mHeaderViewHeight; // header view's height
private boolean mEnablePullRefresh = true;
private boolean mEnablePullRefresh = false;
private boolean mPullRefreshing = false; // is refreashing.

// -- footer view
private XListViewFooter mFooterView;
private boolean mEnablePullLoad;
private boolean mEnablePullLoad = false;
private boolean mPullLoading;
private boolean mIsFooterReady = false;

// total list items, used to detect is at the bottom of listview.
private int mTotalItemCount;

Expand All @@ -67,26 +82,24 @@ public class XListView extends ListView implements OnScrollListener {
* @param context
*/
public XListView(Context context) {
super(context);
initWithContext(context);
this(context, null);
}

public XListView(Context context, AttributeSet attrs) {
super(context, attrs);
initWithContext(context);
this(context, attrs, 0);
}

public XListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initWithContext(context);
initWithContext(context, attrs);
}

private void initWithContext(Context context) {
private void initWithContext(Context context, AttributeSet attrs) {
mScroller = new Scroller(context, new DecelerateInterpolator());
// XListView need the scroll event, and it will dispatch the event to
// user's listener (as a proxy).
super.setOnScrollListener(this);

sharedPref = context.getSharedPreferences(TAG, Context.MODE_PRIVATE);
// init header view
mHeaderView = new XListViewHeader(context);
mHeaderViewContent = (RelativeLayout) mHeaderView
Expand All @@ -108,6 +121,17 @@ public void onGlobalLayout() {
.removeGlobalOnLayoutListener(this);
}
});
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.XListView, 0, 0);
mEnablePullLoad = a.getBoolean(
R.styleable.XListView_pull_to_top_load_more, false);
mEnablePullRefresh = a.getBoolean(
R.styleable.XListView_pull_to_bottom_refresh, false);
}
setPullLoadEnable(mEnablePullLoad);
setPullRefreshEnable(mEnablePullRefresh);
setRefreshTime(sharedPref.getString("last_update_time", DateFormat.format(DATE_FORMAT_PARTTEN, SystemClock.currentThreadTimeMillis()).toString()));
}

@Override
Expand Down Expand Up @@ -183,8 +207,15 @@ public void stopLoadMore() {
*
* @param time
*/
public void setRefreshTime(String time) {
public void setRefreshTime(CharSequence time) {
if (time == null || "".equals(time)) {
String lastUpdateTime = DateFormat.format(DATE_FORMAT_PARTTEN, SystemClock.currentThreadTimeMillis()).toString();
mHeaderTimeView.setText(lastUpdateTime);
sharedPref.edit().putString("last_update_time", lastUpdateTime).commit();
return;
}
mHeaderTimeView.setText(time);
sharedPref.edit().putString("last_update_time", time.toString()).commit();
}

private void invokeOnScrolling() {
Expand All @@ -195,10 +226,10 @@ private void invokeOnScrolling() {
}

private void updateHeaderHeight(float delta) {
mHeaderView.setVisiableHeight((int) delta
+ mHeaderView.getVisiableHeight());
mHeaderView.setVisibleHeight((int) delta
+ mHeaderView.getVisibleHeight());
if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头
if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
if (mHeaderView.getVisibleHeight() > mHeaderViewHeight) {
mHeaderView.setState(XListViewHeader.STATE_READY);
} else {
mHeaderView.setState(XListViewHeader.STATE_NORMAL);
Expand All @@ -211,7 +242,7 @@ private void updateHeaderHeight(float delta) {
* reset header view's height.
*/
private void resetHeaderHeight() {
int height = mHeaderView.getVisiableHeight();
int height = mHeaderView.getVisibleHeight();
if (height == 0) // not visible.
return;
// refreshing and header isn't shown fully. do nothing.
Expand Down Expand Up @@ -242,7 +273,7 @@ private void updateFooterHeight(float delta) {
}
mFooterView.setBottomMargin(height);

// setSelection(mTotalItemCount - 1); // scroll to bottom
// setSelection(mTotalItemCount - 1); // scroll to bottom
}

private void resetFooterHeight() {
Expand Down Expand Up @@ -277,7 +308,7 @@ public boolean onTouchEvent(MotionEvent ev) {
final float deltaY = ev.getRawY() - mLastY;
mLastY = ev.getRawY();
if (getFirstVisiblePosition() == 0
&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {
&& (mHeaderView.getVisibleHeight() > 0 || deltaY > 0)) {
// the first item is showing, header has shown or pull down.
updateHeaderHeight(deltaY / OFFSET_RADIO);
invokeOnScrolling();
Expand All @@ -292,7 +323,7 @@ public boolean onTouchEvent(MotionEvent ev) {
if (getFirstVisiblePosition() == 0) {
// invoke refresh
if (mEnablePullRefresh
&& mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
&& mHeaderView.getVisibleHeight() > mHeaderViewHeight) {
mPullRefreshing = true;
mHeaderView.setState(XListViewHeader.STATE_REFRESHING);
if (mListViewListener != null) {
Expand All @@ -303,8 +334,8 @@ public boolean onTouchEvent(MotionEvent ev) {
} else if (getLastVisiblePosition() == mTotalItemCount - 1) {
// invoke load more.
if (mEnablePullLoad
&& mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA
&& !mPullLoading) {
&& mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA
&& !mPullLoading) {
startLoadMore();
}
resetFooterHeight();
Expand All @@ -318,7 +349,7 @@ public boolean onTouchEvent(MotionEvent ev) {
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
if (mScrollBack == SCROLLBACK_HEADER) {
mHeaderView.setVisiableHeight(mScroller.getCurrY());
mHeaderView.setVisibleHeight(mScroller.getCurrY());
} else {
mFooterView.setBottomMargin(mScroller.getCurrY());
}
Expand Down
Loading