Android下拉刷新组件—PullToRefresh

介绍

这里写图片描述
下拉刷新,几乎是每个 Android 应用都会需要的功能。 android-Ultra-Pull-To-Refresh (以下简称 UltraPTR )便是一个强大的 Andriod 下拉刷新框架。
主要特点:
(1).继承于 ViewGroup , Content 可以包含任何 View 。
(2).简洁完善的 Header 抽象,方便进行拓展,构建符合需求的头部。
PullToRefresh是一套实现非常好的下拉刷新库,它支持:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager

点击查看Github
源码分析

PullToRefreshListView使用

这里写图片描述

1.下载项目包,将library包导入即可,其他的包暂时不用
2.分析源码,看我们可以设置的有哪些

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="PullToRefresh">

        <!-- 设置刷新view的背景 -->
        <attr name="ptrRefreshableViewBackground" format="reference|color" />
        <!-- 设置头部view的背景 -->
        <attr name="ptrHeaderBackground" format="reference|color" />
        <!-- 设置头部/底部文字的颜色 -->
        <attr name="ptrHeaderTextColor" format="reference|color" />
        <!-- 设置头部/底部副标题的文字颜色 -->
        <attr name="ptrHeaderSubTextColor" format="reference|color" />
        <!-- 设置下拉刷新的模式,有多重方式可选。无刷新功能,从顶部刷新,从底部刷新,二者都有,只允许手动刷新 -->
        <attr name="ptrMode">
            <flag name="disabled" value="0x0" />
            <flag name="pullFromStart" value="0x1" />
            <flag name="pullFromEnd" value="0x2" />
            <flag name="both" value="0x3" />
            <flag name="manualOnly" value="0x4" />

            <!-- 这两个属性不推荐了,用上面的代替即可 -->
            <flag name="pullDownFromTop" value="0x1" />
            <flag name="pullUpFromBottom" value="0x2" />
        </attr>

        <!-- 是否显示指示箭头 -->
        <attr name="ptrShowIndicator" format="reference|boolean" />

        <!-- 指示箭头的图片 -->
        <attr name="ptrDrawable" format="reference" />

        <!-- 顶部指示箭头的图片,设置后会覆盖ptrDrawable中顶部的设置 -->
        <attr name="ptrDrawableStart" format="reference" />

        <!-- 底部指示箭头的图片,设置后会覆盖ptrDrawable中底部的设置 -->
        <attr name="ptrDrawableEnd" format="reference" />


        <attr name="ptrOverScroll" format="reference|boolean" />
        <!-- 设置文字的基本字体 -->
        <attr name="ptrHeaderTextAppearance" format="reference" />

        <!-- 设置副标题的基本字体 -->
        <attr name="ptrSubHeaderTextAppearance" format="reference" />

        <!-- 设置下拉时标识图的动画,默认为rotate -->
        <attr name="ptrAnimationStyle">
            <flag name="rotate" value="0x0" />
            <flag name="flip" value="0x1" />
        </attr>

        <!-- 设置刷新时是否允许滚动,一般为true -->
        <attr name="ptrScrollingWhileRefreshingEnabled" format="reference|boolean" />

        <!-- 允许在listview中添加头/尾视图 -->
        <attr name="ptrListViewExtrasEnabled" format="reference|boolean" />

        <!-- 当设置rotate时,可以用这个来设置刷新时旋转的图片 -->
        <attr name="ptrRotateDrawableWhilePulling" format="reference|boolean" />

        <!-- BELOW HERE ARE DEPRECEATED. DO NOT USE. -->
        <attr name="ptrAdapterViewBackground" format="reference|color" />
        <attr name="ptrDrawableTop" format="reference" />
        <attr name="ptrDrawableBottom" format="reference" />
    </declare-styleable>

</resources>

设置Mode

PullToRefreshListView mListView = (PullToRefreshListView) findViewById(R.id.list_view);  
mListView.setMode(Mode.BOTH);  

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

3.开始用它建立自己的工程

设置布局文件

就是插入PullToRefreshListView

<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="${relativePackage}.${activityClass}" 
    android:background="#000000">

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

    <com.handmark.pulltorefresh.library.PullToRefreshListView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pull_refresh_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#000000"
        android:divider="#19000000"
        android:dividerHeight="4dp"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:smoothScrollbar="true" 
        ptr:ptrAnimationStyle="rotate"
        ptr:ptrHeaderTextColor="#ffffff"
        ptr:ptrHeaderSubTextColor="#00ffff"
        ptr:ptrHeaderBackground="@null"
        ptr:ptrDrawable="@drawable/ic_launcher"/>

</RelativeLayout>

开始编写代码

1.找到这个控件,并且设置监听器

这里面用到了一个日期的工具类,其实就是设置上次下拉的时间的。此外在下拉后会触发一个异步任务

package com.kale.ptrlistviewtest;

import java.util.Arrays;
import java.util.LinkedList;

import android.app.Activity;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnLastItemVisibleListener;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import com.handmark.pulltorefresh.library.extras.SoundPullEventListener;

public class MainActivity extends Activity {

    //一个可以下拉刷新的listView对象
    private PullToRefreshListView mPullRefreshListView;
    //普通的listview对象
    private ListView actualListView;
    //添加一个链表数组,来存放string数组,这样就可以动态增加string数组中的内容了
    private LinkedList<String> mListItems;
    //给listview添加一个普通的适配器
    private ArrayAdapter<String> mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        //一打开应用就自动刷新,下面语句可以写到刷新按钮里面
        mPullRefreshListView.setRefreshing(true);
        //new GetDataTask(mPullRefreshListView, mAdapter, mListItems).execute();
        //mPullRefreshListView.setRefreshing(false);

    }

    private void initView() {
        initPTRListView();
        initListView();
    }

    /**
     * 设置下拉刷新的listview的动作
     */
    private void initPTRListView() {
        mPullRefreshListView = (PullToRefreshListView) findViewById(R.id.pull_refresh_list);
        //设置拉动监听器
        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);

                // 更新显示的label
                refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);
                // 开始执行异步任务,传入适配器来进行数据改变
                new GetDataTask(mPullRefreshListView, mAdapter,mListItems).execute();
            }
        });

        // 添加滑动到底部的监听器
        mPullRefreshListView.setOnLastItemVisibleListener(new OnLastItemVisibleListener() {

            @Override
            public void onLastItemVisible() {
                Toast.makeText(getApplication(), "已经到底了", Toast.LENGTH_SHORT).show();
            }
        });

        //mPullRefreshListView.isScrollingWhileRefreshingEnabled();//看刷新时是否允许滑动
        //在刷新时允许继续滑动
        mPullRefreshListView.setScrollingWhileRefreshingEnabled(true);
        //mPullRefreshListView.getMode();//得到模式
        //上下都可以刷新的模式。这里有两个选择:Mode.PULL_FROM_START,Mode.BOTH,PULL_FROM_END
        mPullRefreshListView.setMode(Mode.BOTH);

        /**
         * 设置反馈音效
         */
        SoundPullEventListener<ListView> soundListener = new SoundPullEventListener<ListView>(this);
        soundListener.addSoundEvent(State.PULL_TO_REFRESH, R.raw.pull_event);
        soundListener.addSoundEvent(State.RESET, R.raw.reset_sound);
        soundListener.addSoundEvent(State.REFRESHING, R.raw.refreshing_sound);
        mPullRefreshListView.setOnPullEventListener(soundListener);
    }

    /**
     * 设置listview的适配器
     */
    private void initListView() {
        //通过getRefreshableView()来得到一个listview对象
        actualListView = mPullRefreshListView.getRefreshableView();

        String []data = new String[] {"android","ios","wp","java","c++","c#"};
        mListItems = new LinkedList<String>();
        //把string数组中的string添加到链表中
        mListItems.addAll(Arrays.asList(data));

        mAdapter = new ArrayAdapter<>(getApplicationContext(), 
                android.R.layout.simple_list_item_1, mListItems);
        actualListView.setAdapter(mAdapter);
    }
}

3.写一个异步任务,来模仿从网络加载数据

这里要注意的是,加载完后要出发刷新完成和通知适配器改变的方法

public class GetDataTask extends AsyncTask<Void, Void, Void>{

    private PullToRefreshListView mPullRefreshListView;
    private ArrayAdapter<String> mAdapter;
    private LinkedList<String> mListItems;

    public GetDataTask(PullToRefreshListView listView,
            ArrayAdapter<String> adapter,LinkedList<String> listItems) {
        // TODO 自动生成的构造函数存根
        mPullRefreshListView = listView;
        mAdapter = adapter;
        mListItems = listItems;
    }

    @Override
    protected Void doInBackground(Void... params) {
        //模拟请求
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO 自动生成的方法存根
        super.onPostExecute(result);
        //得到当前的模式
        Mode mode = mPullRefreshListView.getCurrentMode();
        if(mode == Mode.PULL_FROM_START) {
            mListItems.addFirst("这是刷新出来的数据");
        }
        else {
            mListItems.addLast("这是刷新出来的数据");
        }
        // 通知数据改变了
        mAdapter.notifyDataSetChanged();
        // 加载完成后停止刷新
        mPullRefreshListView.onRefreshComplete();

    }
}

PullToRefreshGridView使用方法

思路:

1.写布局文件,放入可以下拉刷新的控件

2.找到下拉刷新的控件,设置监听器,并且在刷新方法中开启一个异步任务来操作

3.通过这个下拉刷新控件的getRefreshableView()方法来得到GridView对象,按照正常的操作来设置适配器

4.在异步任务中通过LinkedList来给头部或者是尾部添加新的数据

实现:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

<!-- The PullToRefreshGridView replaces a standard GridView widget. -->
    <com.handmark.pulltorefresh.library.PullToRefreshGridView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pull_refresh_grid"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent"
        android:numColumns="auto_fit"
        android:verticalSpacing="1dp"
        android:horizontalSpacing="1dp"
        android:columnWidth="100dp"
        android:stretchMode="columnWidth"
        android:gravity="fill"
        ptr:ptrMode="both"
        ptr:ptrDrawable="@drawable/ic_launcher" />

</LinearLayout>

2.找到这个可以下拉刷新的控件,并且设置监听器

这里的监听器和上篇文章讲的不同,是双向的。所以很方便监听滑动操作!
这里也可以设置适配器中无数据时显示的内容,调用的方法是:setEmptyView()

public class MainActivity extends Activity {

    //链表数组对象,用来方便添加string对象
    private LinkedList<String> mListItems;
    //用来下拉刷新的控件
    private PullToRefreshGridView mPullRefreshGridView;
    //真正用到的控件,它被隐含到PullToRefreshGridView中,所以需要找出来才能使用
    private GridView mGridView;
    //定义GridView的适配器
    private ArrayAdapter<String> mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {
        // TODO 自动生成的方法存根
        initPTRGrideView();
        initGrideView();
    }

    /**
     *设置下拉刷新的view,设置双向监听器 
     */
    private void initPTRGrideView() {
        // 得到下拉刷新的GridView
        mPullRefreshGridView = (PullToRefreshGridView) findViewById(R.id.pull_refresh_grid);
        // 设置监听器,这个监听器是可以监听双向滑动的,这样可以触发不同的事件
        mPullRefreshGridView.setOnRefreshListener(new OnRefreshListener2<GridView>() {

            @Override
            public void onPullDownToRefresh(PullToRefreshBase<GridView> refreshView) {
                Toast.makeText(getApplicationContext(), "下拉", Toast.LENGTH_SHORT).show();
                new GetDataTask(mPullRefreshGridView, mAdapter, mListItems).execute();
            }

            @Override
            public void onPullUpToRefresh(PullToRefreshBase<GridView> refreshView) {
                Toast.makeText(getApplicationContext(), "上拉", Toast.LENGTH_SHORT).show();
                new GetDataTask(mPullRefreshGridView, mAdapter, mListItems).execute();
            }

        });
    }

    /**
     * 设置GridView,首先找到它,然后设置适配器
     */
    private void initGrideView() {
        mGridView = mPullRefreshGridView.getRefreshableView();
        //定义String数组,然后把它放到LinkedList中,之后只要在异步任务中用LinkedList就可以添加开头和结尾的数据了
        String []data = new String[] {"android","ios","wp","java","c++","c#"};
        mListItems = new LinkedList<String>();
        mListItems.addAll(Arrays.asList(data));

        //当适配器中没有数据的时候显示的东西,这里因为我给适配器中填充了string数组,所以不会显示“这里很空,下拉刷新试试”
        TextView tv = new TextView(this);
        tv.setGravity(Gravity.CENTER);
        tv.setText("这里很空,下拉刷新试试");
        //当界面为空的时候显示的视图
        mPullRefreshGridView.setEmptyView(tv);

        //设置适配器
        mAdapter = new ArrayAdapter<String>(this, 
                android.R.layout.simple_list_item_1, mListItems);
        mGridView.setAdapter(mAdapter);
    }


}
public class GetDataTask extends AsyncTask<Void, Void, Void>{

    private PullToRefreshGridView mPullRefreshGridView;
    private ArrayAdapter<String> mAdapter;
    private LinkedList<String> mListItems;


    public GetDataTask(PullToRefreshGridView gridView,
            ArrayAdapter<String> adapter,LinkedList<String> listItems) {
        // TODO 自动生成的构造函数存根
        mPullRefreshGridView = gridView;
        mAdapter = adapter;
        mListItems = listItems;
    }

    @Override
    protected Void doInBackground(Void... params) {
        //模拟请求,舒眠2秒钟
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO 自动生成的方法存根
        super.onPostExecute(result);

        //得到当前的模式,来判断数据应该加载到哪个位置
        Mode mode = mPullRefreshGridView.getCurrentMode();
        if(mode == Mode.PULL_FROM_START) {
            mListItems.addFirst("这是刷新出来的数据");
        }
        else {
            mListItems.addLast("这是刷新出来的数据");
        }
        // 通知数据改变了
        mAdapter.notifyDataSetChanged();
        // 加载完成后停止刷新
        mPullRefreshGridView.onRefreshComplete();

    }
}

PullToRefreshScrollView 使用

和ScrollView不同的是,这里不用放一个linearLayout来做内容的容器,直接放入要显示的东西就行。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

 pulltorefresh.library.PullToRefreshScrollView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pull_refresh_scrollview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        ptr:ptrAnimationStyle="flip"
        ptr:ptrMode="both" >

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="8dp"
            android:text="@string/filler_text"
            android:textSize="16sp" />
    </com.handmark.pulltorefresh.library.PullToRefreshScrollView>

</LinearLayout>

2.找到控件并进行设置

public final class PullToRefreshScrollViewActivity extends Activity {

    PullToRefreshScrollView mPullRefreshScrollView;
    ScrollView mScrollView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ptr_scrollview);
        //找到控件
        mPullRefreshScrollView = (PullToRefreshScrollView) findViewById(R.id.pull_refresh_scrollview);

        //设置监听器,监听器中执行异步任务
        mPullRefreshScrollView.setOnRefreshListener(new OnRefreshListener<ScrollView>() {

            @Override
            public void onRefresh(PullToRefreshBase<ScrollView> refreshView) {
                new GetDataTask().execute();
            }
        });

        mScrollView = mPullRefreshScrollView.getRefreshableView();
    }

    private class GetDataTask extends AsyncTask<Void, Void, String[]> {

        @Override
        protected String[] doInBackground(Void... params) {

            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
            }
            return null;
        }

        @Override
        protected void onPostExecute(String[] result) {

            //注意:执行完后通知控件刷新完成
            mPullRefreshScrollView.onRefreshComplete();

            super.onPostExecute(result);
        }
    }

}

下面是横向的ScrollView

1.布局文件,就是几个textview

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- The PullToRefreshScrollView replaces a standard PullToRefreshScrollView widget. -->

    <com.handmark.pulltorefresh.library.PullToRefreshHorizontalScrollView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pull_refresh_horizontalscrollview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        ptr:ptrAnimationStyle="flip"
        ptr:ptrMode="both" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:orientation="horizontal" >

            <TextView
                style="@style/HorizScrollViewItem"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:background="#ff99cc00" />

            <TextView
                style="@style/HorizScrollViewItem"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:background="#ffff4444" />

            <TextView
                style="@style/HorizScrollViewItem"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:background="#ff33b5e5" />

            <TextView
                style="@style/HorizScrollViewItem"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:background="#ffcc0000" />

        </LinearLayout>

    </com.handmark.pulltorefresh.library.PullToRefreshHorizontalScrollView>

</LinearLayout>

2.activity中的代码,和上面基本一样

public final class PullToRefreshHorizontalScrollViewActivity extends Activity {

    PullToRefreshHorizontalScrollView mPullRefreshScrollView;
    HorizontalScrollView mScrollView;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ptr_horizontalscrollview);

mPullRefreshScrollView = (PullToRefreshHorizontalScrollView)findViewById(R.id.pull_refresh_horizontalscrollview);
        mPullRefreshScrollView.setOnRefreshListener(new OnRefreshListener<HorizontalScrollView>() {

            @Override
            public void onRefresh(PullToRefreshBase<HorizontalScrollView> refreshView) {
                new GetDataTask().execute();
            }
        });

        mScrollView = mPullRefreshScrollView.getRefreshableView();
    }


    private class GetDataTask extends AsyncTask<Void, Void, String[]> {

        @Override
        protected String[] doInBackground(Void... params) {

            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
            }
            return null;
        }

        @Override
        protected void onPostExecute(String[] result) {

            mPullRefreshScrollView.onRefreshComplete();

            super.onPostExecute(result);
        }
    }
}

这里我们来注意下这部分

 mPullRefreshScrollView = (PullToRefreshHorizontalScrollView) findViewById(R.id.pull_refresh_horizontalscrollview);
        mPullRefreshScrollView.setOnRefreshListener(new OnRefreshListener<HorizontalScrollView>() {

            @Override
            public void onRefresh(PullToRefreshBase<HorizontalScrollView> refreshView) {
                new GetDataTask().execute();
            }
        });

    mPullRefreshScrollView.setOnRefreshListener(new OnRefreshListener<ScrollView>() {

        @Override
        public void onRefresh(PullToRefreshBase<ScrollView> refreshView) {
            new GetDataTask().execute();
        }
    });

ViewPager使用方法

点击查看参考博客

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值