Share to EffectHub.com

You can earn money or coins from your share:)

Tips: you can use Sparticle for uploading away3D effects.

Tips: you can download Sparticle for uploading effects.

Tips: The ActionScript editor is supporting Away3D, Starling, Dragonbones and Flex frameworks.

Tips: paste the web page URL then click button:)

EffectHub.com: Your Best Source for Gaming
Login    or

XlistView: A listview which can pull to refresh and load more (1)


/**

 * @file XListView.java

 * @package me.maxwin.view

 * @create 2013/5/13

 * @author youxiachai

 * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more.

 * Implement IXListViewListener, and see stopRefresh() / stopLoadMore().

 * 

 */


import android.content.Context;

import android.content.SharedPreferences;

import android.os.AsyncTask;

import android.preference.PreferenceManager;

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.AbsListView.OnScrollListener;

import android.widget.ListAdapter;

import android.widget.ListView;

import android.widget.RelativeLayout;

import android.widget.Scroller;

import android.widget.TextView;


public class XListView extends ListView implements OnScrollListener {

public static final long ONE_MINUTE = 60 * 1000;

public static final long ONE_HOUR = 60 * ONE_MINUTE;

public static final long ONE_DAY = 24 * ONE_HOUR;

public static final long ONE_MONTH = 30 * ONE_DAY;

public static final long ONE_YEAR = 12 * ONE_MONTH;

protected long lastUpdateTime;

protected float mLastY = -1; // save event y

protected Scroller mScroller; // used for scroll back

protected OnScrollListener mScrollListener; // user's scroll listener


// the interface to trigger refresh and load more.


protected IXListViewLoadMore mLoadMore;

protected IXListViewRefreshListener mOnRefresh;

private SharedPreferences preferences;

private String RefreshTimeTag="XListViewRefreshTime";

// -- header view

protected XListViewHeader mHeaderView;

// header view content, use it to calculate the Header's height. And hide it

// when disable pull refresh.

protected RelativeLayout mHeaderViewContent;

protected TextView mHeaderTimeView;

protected int mHeaderViewHeight; // header view's height

protected boolean mEnablePullRefresh = true;

protected boolean mPullRefreshing = false; // is refreashing.


// -- footer view

protected XListViewFooter mFooterView;

protected boolean mEnablePullLoad;

protected boolean mPullLoading;

protected boolean mIsFooterReady = false;


// total list items, used to detect is at the bottom of listview.

protected int mTotalItemCount;


// for mScroller, scroll back from header or footer.

protected int mScrollBack;

protected final static int SCROLLBACK_HEADER = 0;

protected final static int SCROLLBACK_FOOTER = 1;


protected final static int SCROLL_DURATION = 400; // scroll back duration

protected final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >=

// 50px

// at bottom,

// trigger

// load more.

protected final static float OFFSET_RADIO = 1.8f; // support iOS like pull

// feature.


/**

* @param context

*/

public XListView(Context context) {

super(context);

initWithContext(context);

}


public XListView(Context context, AttributeSet attrs) {

super(context, attrs);

initWithContext(context);

}


public XListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

initWithContext(context);

}


protected void initWithContext(Context context) {

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);

preferences = PreferenceManager.getDefaultSharedPreferences(context);

// init header view

mHeaderView = new XListViewHeader(context);

mHeaderViewContent = (RelativeLayout) mHeaderView

.findViewById(R.id.xlistview_header_content);

mHeaderTimeView = (TextView) mHeaderView

.findViewById(R.id.xlistview_header_time);

//mHeaderTimeView.setText(refreshUpdatedAtValue());

addHeaderView(mHeaderView);


// init footer view

mFooterView = new XListViewFooter(context);


// init header height

mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(

new OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

mHeaderViewHeight = mHeaderViewContent.getHeight();

getViewTreeObserver()

.removeGlobalOnLayoutListener(this);

}

});

disablePullLoad();

disablePullRefreash();

}


@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);

// make sure XListViewFooter is the last footer view, and only add once.

if (mIsFooterReady == false) {

// if not inflate screen ,footerview not add

if(getAdapter() != null){

if (getLastVisiblePosition() != (getAdapter().getCount() - 1)) {

mIsFooterReady = true;

addFooterView(mFooterView);

}

}

}

}


@Override

public void setAdapter(ListAdapter adapter) {

super.setAdapter(adapter);


}


/**

* enable or disable pull down refresh feature.

* @param enable

*/

public void setPullRefreshEnable(IXListViewRefreshListener refreshListener) {

mEnablePullRefresh = true;

mHeaderViewContent.setVisibility(View.VISIBLE);

this.mOnRefresh = refreshListener;


}


public void disablePullRefreash() {

mEnablePullRefresh = false;

// disable, hide the content

mHeaderViewContent.setVisibility(View.INVISIBLE);

}


/**

* enable or disable pull up load more feature.

* @param enable

*/

public void setPullLoadEnable(IXListViewLoadMore loadMoreListener) {

mEnablePullLoad = true;

this.mLoadMore = loadMoreListener;

mPullLoading = false;

mFooterView.show();

mFooterView.setState(XListViewFooter.STATE_NORMAL);

// both "pull up" and "click" will invoke load more.

mFooterView.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

startLoadMore();

}

});


}


public void disablePullLoad() {

mEnablePullLoad = false;

mFooterView.hide();

mFooterView.setOnClickListener(null);

}


/**

* stop refresh, reset header view.

*/

public void stopRefresh() {

if (mPullRefreshing == true) {

mPullRefreshing = false;

preferences.edit()

.putLong(RefreshTimeTag, System.currentTimeMillis()).commit();

mHeaderTimeView.setText(refreshUpdatedAtValue());

resetHeaderHeight();

}

}

/**

* Get the time gap between now and last refresh time

* @return time string

*/

private String refreshUpdatedAtValue() {

lastUpdateTime = preferences.getLong(RefreshTimeTag, -1);

long currentTime = System.currentTimeMillis();

long timePassed = currentTime - lastUpdateTime;

long timeIntoFormat;

String updateAtValue;

if (lastUpdateTime == -1) {

updateAtValue = getResources().getString(R.string.not_updated_yet);

} else if (timePassed < 0) {

updateAtValue = getResources().getString(R.string.time_error);

} else if (timePassed < ONE_MINUTE) {

updateAtValue = getResources().getString(R.string.updated_just_now);

} else if (timePassed < ONE_HOUR) {

timeIntoFormat = timePassed / ONE_MINUTE;

updateAtValue = timeIntoFormat + "MINS";

} else if (timePassed < ONE_DAY) {

timeIntoFormat = timePassed / ONE_HOUR;

updateAtValue = timeIntoFormat + "HOURS";

} else if (timePassed < ONE_MONTH) {

timeIntoFormat = timePassed / ONE_DAY;

updateAtValue = timeIntoFormat + "DAYS";

} else if (timePassed < ONE_YEAR) {

timeIntoFormat = timePassed / ONE_MONTH;

updateAtValue = timeIntoFormat + "MONTHS";

} else {

timeIntoFormat = timePassed / ONE_YEAR;

updateAtValue = timeIntoFormat + "YEARS";

}

return updateAtValue;

}


/**

* stop load more, reset footer view.

*/

public void stopLoadMore() {

if (mPullLoading == true) {

mPullLoading = false;

mFooterView.setState(XListViewFooter.STATE_NORMAL);

}

}


/**

* set last refresh time

* @param time

*/

public void setRefreshTime(String time) {

}


protected void invokeOnScrolling() {

if (mScrollListener instanceof IXScrollListener) {

IXScrollListener l = (IXScrollListener) mScrollListener;

l.onXScrolling(this);

}

}


protected void updateHeaderHeight(float delta) {

mHeaderView.setVisiableHeight((int) delta

+ mHeaderView.getVisiableHeight());

if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头

if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {

mHeaderView.setState(XListViewHeader.STATE_READY);

} else {

mHeaderView.setState(XListViewHeader.STATE_NORMAL);

}

}

setSelection(0); // scroll to top each time

}


/**

* reset header view's height.

*/

protected void resetHeaderHeight() {

int height = mHeaderView.getVisiableHeight();

if (height == 0) // not visible.

return;

// refreshing and header isn't shown fully. do nothing.

if (mPullRefreshing && height <= mHeaderViewHeight) {

return;

}

int finalHeight = 0; // default: scroll back to dismiss header.

// is refreshing, just scroll back to show all the header.

if (mPullRefreshing && height > mHeaderViewHeight) {

finalHeight = mHeaderViewHeight;

}

Log.d("xlistview", "resetHeaderHeight-->" + (finalHeight - height));

mScrollBack = SCROLLBACK_HEADER;

mScroller.startScroll(0, height, 0, finalHeight - height,

SCROLL_DURATION);

// trigger computeScroll

invalidate();

}


protected void resetHeaderHeight(int disy) {

int height = mHeaderView.getVisiableHeight();

if (height == 0) // not visible.

return;

// refreshing and header isn't shown fully. do nothing.

if (mPullRefreshing && height <= mHeaderViewHeight) {

return;

}

int finalHeight = 0; // default: scroll back to dismiss header.

// is refreshing, just scroll back to show all the header.

if (mPullRefreshing && height > mHeaderViewHeight) {

finalHeight = mHeaderViewHeight;

}

mScrollBack = SCROLLBACK_HEADER;

Log.d("xlistview", "resetHeaderHeight-->" + (finalHeight - height));

mScroller.startScroll(0, height, 0, finalHeight - height + 100,

SCROLL_DURATION);

// trigger computeScroll

invalidate();

}


protected void updateFooterHeight(float delta) {

int height = mFooterView.getBottomMargin() + (int) delta;

if (mEnablePullLoad && !mPullLoading) {

if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load

// more.

mFooterView.setState(XListViewFooter.STATE_READY);

} else {

mFooterView.setState(XListViewFooter.STATE_NORMAL);

}

}

mFooterView.setBottomMargin(height);


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

}


protected void resetFooterHeight() {

int bottomMargin = mFooterView.getBottomMargin();

if (bottomMargin > 0) {

mScrollBack = SCROLLBACK_FOOTER;

mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,

SCROLL_DURATION);

invalidate();

}

}


protected void startLoadMore() {

if (mEnablePullLoad

&& mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA

&& !mPullLoading) {

mPullLoading = true;

mFooterView.setState(XListViewFooter.STATE_LOADING);

if (mLoadMore != null) {

AsynLoadMoreTask asynLoadMoreTask =new AsynLoadMoreTask();

asynLoadMoreTask.execute();

}

}

}

//Async Task for loading more data;

private class AsynLoadMoreTask extends AsyncTask<Void,Void,Void>

{


@Override

protected Void doInBackground(Void... params) {

mLoadMore.onLoadMore();

return null;

}

@Override

protected void onPostExecute(Void result) {

stopLoadMore();

super.onPostExecute(result);

}

}


@Override

public boolean onTouchEvent(MotionEvent ev) {

if (mLastY == -1) {

mLastY = ev.getRawY();

}


switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

mLastY = ev.getRawY();

break;

case MotionEvent.ACTION_MOVE:

final float deltaY = ev.getRawY() - mLastY;

mLastY = ev.getRawY();

//Log.d("xlistview", "xlistView-height");

if (getFirstVisiblePosition() == 0

&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)

&& !mPullRefreshing) {

// the first item is showing, header has shown or pull down.

if(mEnablePullRefresh){

updateHeaderHeight(deltaY / OFFSET_RADIO);

invokeOnScrolling();

}

} else if (getLastVisiblePosition() == mTotalItemCount - 1

&& (mFooterView.getBottomMargin() > 0 || deltaY < 0)

&& !mPullLoading) {

// last item, already pulled up or want to pull up.

if(mEnablePullLoad){

updateFooterHeight(-deltaY / OFFSET_RADIO);

}

}

break;

default:

mLastY = -1; // reset

if (getFirstVisiblePosition() == 0) {

// invoke refresh

startOnRefresh();

resetHeaderHeight();

} else if (getLastVisiblePosition() == mTotalItemCount - 1) {

// invoke load more.

startLoadMore();

resetFooterHeight();

}

break;

}

return super.onTouchEvent(ev);

}


protected void startOnRefresh() {

if (mEnablePullRefresh

&& mHeaderView.getVisiableHeight() > mHeaderViewHeight

&& !mPullRefreshing) {

mPullRefreshing = true;

mHeaderView.setState(XListViewHeader.STATE_REFRESHING);

if (mOnRefresh != null) {

AsyncRefreshTask asyncRefreshTask =new AsyncRefreshTask();

asyncRefreshTask.execute();

}

}

}

//AsyncTask for refresh Data

private class AsyncRefreshTask extends  AsyncTask<Void, Void, Void>

{

@Override

protected Void doInBackground(Void... params) {

mOnRefresh.onRefresh();

return null;

}

@Override

protected void onPostExecute(Void result) {

stopRefresh();

super.onPostExecute(result);

}

}


@Override

public void computeScroll() {

if (mScroller.computeScrollOffset()) {

if (mScrollBack == SCROLLBACK_HEADER) {

mHeaderView.setVisiableHeight(mScroller.getCurrY());

} else {

mFooterView.setBottomMargin(mScroller.getCurrY());

}

postInvalidate();

invokeOnScrolling();

}

super.computeScroll();

}


@Override

public void setOnScrollListener(OnScrollListener l) {

mScrollListener = l;

}


@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

if (mScrollListener != null) {

mScrollListener.onScrollStateChanged(view, scrollState);

}

}


@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// send to user's listener

mTotalItemCount = totalItemCount;

if (mScrollListener != null) {

mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,

totalItemCount);

}

}


}


...

You must Sign up as a member of Effecthub to view the content.

6578 views    6 comments

You must Sign up as a member of Effecthub to join the conversation.

bestshoeshine 2022-05-19

great

Anthony Selers 2019-11-26

Sorry, but what is it for? I do not understand.

erukajuminten 2019-08-05

wow

Join Effecthub.com


Or Login with Your Email Address:

Or Sign Up with Your Email Address:
This field must contain a valid email
Password should be at least 1 character