PullToRefresh Demo 浅析:ListView

ListView该项目是一个很简单的demo,介绍了一些PullToRefresh的常规设置。

首先关注一下布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<!--     The PullToRefreshListView replaces a standard ListView widget. -->

    <com.handmark.pulltorefresh.library.PullToRefreshListView
        android:id="@+id/pull_refresh_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#00000000"
        android:divider="#19000000"
        android:dividerHeight="4dp"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:smoothScrollbar="true" />

</LinearLayout>

从布局文件中可以看出:想要实现该开源项目的一些功能,首先要导入其相应的控件。


mPullRefreshListView = (PullToRefreshListView) findViewById(R.id.pull_refresh_list);

        // Set a listener to be invoked when the list should be refreshed.
        mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
            @Override
            public void onRefresh(PullToRefreshBase<ListView> refreshView) {
                String label = DateUtils.formatDateTime(getApplicationContext(), System.currentTimeMillis(),
                        DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);

                // Update the LastUpdatedLabel
                refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);

                // Do work to refresh the list here.
                new GetDataTask().execute();
            }
        });

        // Add an end-of-list listener
        mPullRefreshListView.setOnLastItemVisibleListener(new OnLastItemVisibleListener() {

            @Override
            public void onLastItemVisible() {
                Toast.makeText(PullToRefreshListActivity.this, "End of List!", Toast.LENGTH_SHORT).show();
            }
        });

首先获取PullToRefreshListView控件,之后设置该空间相应的监听器,对于PullToRefresh项目来说,必须要配置相应的一个或多个监听器。而配置的监听器种类主要还是根据刷新的类型来决定的。比如该Demo中包含有三种模式:

  • Mode.BOTH:同时支持上拉下拉
  • Mode.PULL_FROM_START:只支持下拉Pulling Down
  • Mode.PULL_FROM_END:只支持上拉Pulling Up

如果Mode设置成Mode.BOTH,需要设置刷新Listener为OnRefreshListener2,并实现onPullDownToRefresh()、onPullUpToRefresh()两个方法。
如果Mode设置成Mode.PULL_FROM_START或Mode.PULL_FROM_END,需要设置刷新Listener为OnRefreshListener,同时实现onRefresh()方法。当然也可以设置为OnRefreshListener2,但是Mode.PULL_FROM_START的时候只调用onPullDownToRefresh()方法,Mode.PULL_FROM的时候只调用onPullUpToRefresh()方法.

new GetDataTask().execute();
private class GetDataTask extends AsyncTask<Void, Void, String[]> {

        @Override
        protected String[] doInBackground(Void... params) {
            // Simulates a background job.
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
            }
            return mStrings;
        }

        @Override
        protected void onPostExecute(String[] result) {
            mListItems.addFirst("Added after refresh...");
            mAdapter.notifyDataSetChanged();

            // Call onRefreshComplete when the list has been refreshed.
            mPullRefreshListView.onRefreshComplete();

            super.onPostExecute(result);
        }
    }

它继承了AsyncTask<Void, Void, String[]> 这个类:

参考:http://blog.sina.com.cn/s/blog_6513b5cf0101ceqn.html

AsyncTask可以使得使用UI线程变的更容易更适当,它可以在后台运行一些操作然后在UI上展现,不用操作具体的线程和handlers,一个 asynchronous task包括三种基本类型(调用参数,进度和结果),和四个步骤(调用开始,在后台运行,处理进度,结束),并且大多数时候覆盖onPostExecute(Result)方法。

使用方法描述:

1、Asynchronous Task必须是作为一个子类来使用,
2、task实例必须在UI线程创建
3、execute(Params...)必须在UI线程调用
4、不要手工调用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)。
5、task只可以execute一次,执行多次就报异常

三种基本类型的说明:

Params, 传给task的参数的类型,没有为Void。
Progress, 表示进度单位的类型,同上。
Result, 返回类型,同上。

四个步骤的说明:

onPreExecute():在task被执行之后,立刻调用

doInBackground(Params...):onPreExecute执行完毕后,执行该方法,参数传到了这个方法中,执行完毕后必须返回一个值,还可以使用 publishProgress(Progress...) 发布进度到onProgressUpdate(Progress...),便于更新进度

onProgressUpdate(Progress...):publishProgress(Progress...)被调用后,就执行该方法,显示进度信息。通常是显示一个进度条,或在text域里显示日志信息。

onPostExecute(Result)当doInBackground(Params...)执行完毕后即执行该方法


结合示例

doInBackground方法顾名思义(在后台运行时)产生了延时,并返回了操作之后的数据。

onPostExecute方法用于处理并提交doInBackground方法返回的数据,类似于刷新的功能。

@Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case MENU_MANUAL_REFRESH:
                new GetDataTask().execute();
                mPullRefreshListView.setRefreshing(false);
                break;
            case MENU_DISABLE_SCROLL:
                mPullRefreshListView.setScrollingWhileRefreshingEnabled(!mPullRefreshListView
                        .isScrollingWhileRefreshingEnabled());//更新的时候是否允许拖动
                break;
            case MENU_SET_MODE:
                mPullRefreshListView.setMode(mPullRefreshListView.getMode() == Mode.BOTH ? Mode.PULL_FROM_START
                        : Mode.BOTH);//设置是否滑动的模式
                break;
            case MENU_DEMO:
                mPullRefreshListView.demo();
                break;
        }

在menu中设置了四个选项,这四个选项放在了actionbar中。他们分别代表不同的效果.

demo方法:

@Override
    public final boolean demo() {
        if (mMode.showHeaderLoadingLayout() && isReadyForPullStart()) {
            smoothScrollToAndBack(-getHeaderSize() * 2);
            return true;
        } else if (mMode.showFooterLoadingLayout() && isReadyForPullEnd()) {
            smoothScrollToAndBack(getFooterSize() * 2);
            return true;
        }

        return false;
    }

smoothScrollToAndBack:输入参数y代表下拉的距离

private final void smoothScrollToAndBack(int y) {
        smoothScrollTo(y, SMOOTH_SCROLL_DURATION_MS, 0, new OnSmoothScrollFinishedListener() {

            @Override
            public void onSmoothScrollFinished() {
                smoothScrollTo(0, SMOOTH_SCROLL_DURATION_MS, DEMO_SCROLL_INTERVAL, null);
            }
        });//模拟人手的滑动,停留的时间可以自己设定
    }

smoothScrollTo方法:

private final void smoothScrollTo(int newScrollValue, long duration, long delayMillis,
            OnSmoothScrollFinishedListener listener) {
        if (null != mCurrentSmoothScrollRunnable) {
            mCurrentSmoothScrollRunnable.stop();
        }

        final int oldScrollValue;
        switch (getPullToRefreshScrollDirection()) {
            case HORIZONTAL:
                oldScrollValue = getScrollX();
                break;
            case VERTICAL:
            default:
                oldScrollValue = getScrollY();
                break;
        }

        if (oldScrollValue != newScrollValue) {
            if (null == mScrollAnimationInterpolator) {
                // Default interpolator is a Decelerate Interpolator
                mScrollAnimationInterpolator = new DecelerateInterpolator();
            }
            mCurrentSmoothScrollRunnable = new SmoothScrollRunnable(oldScrollValue, newScrollValue, duration, listener);//这里才是动作真正开始执行的时候,新开线程去执行。

            if (delayMillis > 0) {
                postDelayed(mCurrentSmoothScrollRunnable, delayMillis);
            } else {
                post(mCurrentSmoothScrollRunnable);
            }
        }
    }

SmoothScrollRunnable类继承了runnable,所以会新开一条线程来执行。

@Override
        public void run() {

            /**
             * Only set mStartTime if this is the first time we're starting,
             * else actually calculate the Y delta
             */
            if (mStartTime == -1) {
                mStartTime = System.currentTimeMillis();
            } else {

                /**
                 * We do do all calculations in long to reduce software float
                 * calculations. We use 1000 as it gives us good accuracy and
                 * small rounding errors
                 */
                long normalizedTime = (1000 * (System.currentTimeMillis() - mStartTime)) / mDuration;
                normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);

                final int deltaY = Math.round((mScrollFromY - mScrollToY)
                        * mInterpolator.getInterpolation(normalizedTime / 1000f));
                mCurrentY = mScrollFromY - deltaY;
                setHeaderScroll(mCurrentY);
            }

            // If we're not at the target Y, keep going...
            if (mContinueRunning && mScrollToY != mCurrentY) {
                ViewCompat.postOnAnimation(PullToRefreshBase.this, this);//执行线程
            } else {
                if (null != mListener) {
                    mListener.onSmoothScrollFinished();
                }
            }
        }

        public void stop() {
            mContinueRunning = false;
            removeCallbacks(this);
        }
    }

    static interface OnSmoothScrollFinishedListener {
        void onSmoothScrollFinished();
    }
posted @ 2015-08-19 21:15  黑泡man  阅读(155)  评论(0编辑  收藏  举报