如何实现Android Pull-to-Refresh


433

在诸如Twitter(官方应用程序)之类的Android应用程序中,遇到ListView时,可以将其拉下(发布后会反弹)以刷新内容。

我想知道您认为最好的方法是什么?

我可能想到的一些可能性:

  1. ListView顶部的项目-但是,我不认为滚动到带有ListView动画的项目位置1(基于0)并不容易。
  2. ListView之外的另一个视图-但是在拉拽ListView时,我需要注意将其向下移动,而且我不确定是否可以检测到对ListView的拖动是否仍然真正滚动了ListView上的项目。

有什么建议吗?

PS我想知道官方Twitter应用程序源代码何时发布。已经提到它将被发布,但是六个月过去了,从那以后我们还没有听说过它。


是否可以在动态创建的TableLayout中实现此功能。请帮助.....
阿伦·巴多尔

github.com/fruitranger/PulltorefreshListView是我的另一个实现。流畅的多点触控支持。
姚昌伟

6
相关阅读:“拉来刷新”:在Android上的反UI模式是一篇文章认为这种UI 不是一件应该在Android上使用,并引发了关于其适当的讨论很多。
blahdiblah

29
有人应该让Google知道,因为最新版的Android版Gmail使用了这种“反模式”。
尼克

4
拉动刷新是(并且已经有一段时间了)iOS和Android中的一种标准采用模式,这很自然,因此此反模式讨论已过时。用户将期望看到它并且表现得如此。
Martin Marconcini 2014年

Answers:


311

最终,Google发布了正式版的Pull-to-refresh库!

SwipeRefreshLayout在支持库中称为,文档在这里

  1. 添加SwipeRefreshLayout为视图的父级,将其视为刷新布局的拉动。(以我ListView为例,可以是任何View类似的东西LinearLayoutScrollView等等。)

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.v4.widget.SwipeRefreshLayout>
  2. 将听众添加到您的班级

    protected void onCreate(Bundle savedInstanceState) {
        final SwipeRefreshLayout pullToRefresh = findViewById(R.id.pullToRefresh);
        pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshData(); // your code
                pullToRefresh.setRefreshing(false);
            }
        });
    }

您也可以pullToRefresh.setRefreshing(true/false);根据需要致电。

更新

Android支持库已被弃用,并已由AndroidX取代。可以在这里找到新库的链接。

另外,您需要向项目添加以下依赖项:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

要么

您可以转到Refactor >> Migrate to AndroidX,Android Studio将为您处理依赖项。


3
我可以在SwipeRefreshLayout上使用ProgressBar代替配色方案吗?
pablobaldez 2014年

54
144月1日 -这不是个玩笑
aeracode


80

我已经尝试实现拉动刷新组件,虽然还远未完成,但是演示了可能的实现,https://github.com/johannilsson/android-pulltorefresh

主要逻辑是在PullToRefreshListView扩展中实现的ListView在内部,它使用smoothScrollBy(API级别8)控制标题视图的滚动。现在,该小部件已更新为支持1.5及更高版本,不过请阅读自述文件以获取1.5支持。

在您的布局中,您只需像这样添加它。

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

3
嗨,约翰,我已经下载了您的示例代码。它适用于android 2.2设备,但不适用于2.1设备。我认为是因为它使用仅在2.2或更高版本中可用的smoothScrollBy方法正确吗?您是否有想法将此效果实现到2.1或更早版本中?谢谢

是的,这是正确的,正如我在API Level 8(2.2)中引入的smoothScrollBy答案中所述。我还没有找到将其实现为其他版本的正确方法,但是它猜测应该可以移植smoothScrollBy的实现,但是我认为讨论应该在项目现场进行,而不是在堆栈溢出时进行?
Johan Berg Nilsson

id是@ + id / android:list而不是@android:id / list是故意的吗,它看起来很奇怪?该项目在我这边引发了通货膨胀错误,我目前正在检查……
Mathias Conradt

12
这是我发现的用于刷新的最佳库。github.com/chrisbanes/Android-PullToRefresh。它与ListViews,GridViews和Webviews一起使用。还实现了上拉刷新模式。
rOrlig

1
在处理Intellij Idea时如何将项目添加到库文件夹中?有谁能够帮助我?
MustafaGüven2013年

55

我还为Android实现了一个健壮,开源,易于使用和高度可定制的PullToRefresh库。您可以按照项目页面文档中的说明,用PullToRefreshListView替换ListView。

https://github.com/erikwt/PullToRefresh-ListView


我尝试了此处列出的所有实现,就简单/纯净/平滑的拉动刷新实现(没有像Johan一样轻拍刷新怪异)而言,您的方法是最好的。谢谢!
盖迪2012年

1
这可以代替标准ListView来与ListActivity,ListFragment等一起使用吗?
davidcesarino

是的,只需为PullToRefreshListView提供正确的ID。在XML中:android:id =“ @ android:id / list”
Erik

1
这绝对很棒!google将我带到这里,通过示例,您看起来最容易实现。太好了,谢谢您,先生!
Evan R.

设计合理的组件,美观而简单。这绝对应该是公认的答案。
亚当

42

我认为最简单的方法是由android支持库提供的:

android.support.v4.widget.SwipeRefreshLayout;

导入后,即可按以下方式定义布局:

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    <android.support.v7.widget.RecyclerView
        xmlns:recycler_view="http://schemas.android.com/apk/res-auto"
        android:id="@android:id/list"
        android:theme="@style/Theme.AppCompat.Light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/button_material_light"
        >

    </android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>

我假设您使用回收站视图而不是listview。但是,listview仍然有效,因此您只需要用listview替换recyclerview并更新Java代码(片段)中的引用即可。

在您的活动片段中,您首先实现接口SwipeRefreshLayout.OnRefreshListener

public class MySwipeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
private SwipeRefreshLayout swipeRefreshLayout;

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item, container, false);
        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh);
        swipeRefreshLayout.setOnRefreshListener(this);
}


 @Override
  public void onRefresh(){
     swipeRefreshLayout.setRefreshing(true);
     refreshList();
  }
  refreshList(){
    //do processing to get new data and set your listview's adapter, maybe  reinitialise the loaders you may be using or so
   //when your data has finished loading, cset the refresh state of the view to false
   swipeRefreshLayout.setRefreshing(false);

   }
}

希望对大家有帮助


效果很好。但是,关于一件事情setRefreshing:如developer.android.com/reference/android/support/v4/widget/…中
gabriel14

做得好!谢谢。
technik

22

在此链接中,您可以找到著名PullToRefresh视图的分支,该分支具有新的有趣的实现,例如PullTorRefreshWebViewPullToRefreshGridView或可以PullToRefresh在列表的底部添加a 。

https://github.com/chrisbanes/Android-PullToRefresh

最好的是,它可以在Android 4.1中完美运行(正常PullToRefresh情况下不起作用)


3
自述文件顶部的一个大注释表示:该项目不再受维护。无论如何,这个lib是迄今为止我所见过的最好的lib!做得好!
米尔顿

3
仅仅因为不再维护它,并不意味着它不好。仍然使用它来满足我的所有刷新需求:)
Muz

18

我有一个非常简单的方法来做到这一点,但现在确定它的万无一失方法是我的代码PullDownListView.java

package com.myproject.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

/**
 * @author Pushpan
 * @date Nov 27, 2012
 **/
public class PullDownListView extends ListView implements OnScrollListener {

    private ListViewTouchEventListener mTouchListener;
    private boolean pulledDown;

    public PullDownListView(Context context) {
        super(context);
        init();
    }

    public PullDownListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PullDownListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        setOnScrollListener(this);
    }

    private float lastY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            lastY = ev.getRawY();
        } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            float newY = ev.getRawY();
            setPulledDown((newY - lastY) > 0);
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (isPulledDown()) {
                        if (mTouchListener != null) {
                            mTouchListener.onListViewPulledDown();
                            setPulledDown(false);
                        }
                    }
                }
            }, 400);
            lastY = newY;
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            lastY = 0;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        setPulledDown(false);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    public interface ListViewTouchEventListener {
        public void onListViewPulledDown();
    }

    public void setListViewTouchListener(
            ListViewTouchEventListener touchListener) {
        this.mTouchListener = touchListener;
    }

    public ListViewTouchEventListener getListViewTouchListener() {
        return mTouchListener;
    }

    public boolean isPulledDown() {
        return pulledDown;
    }

    public void setPulledDown(boolean pulledDown) {
        this.pulledDown = pulledDown;
    }
}

您只需要在要使用此ListView并设置侦听器的活动上实现ListViewTouchEventListener

我在PullDownListViewActivity中实现了它

package com.myproject.activities;

import android.app.Activity;
import android.os.Bundle;

/**
 * @author Pushpan
 *
 */
public class PullDownListViewActivity extends Activity implements ListViewTouchEventListener {

    private PullDownListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        listView = new PullDownListView(this);
        setContentView(listView);
        listView.setListViewTouchListener(this);

        //setItems in listview
    }

    public void onListViewPulledDown(){
        Log.("PullDownListViewActivity", "ListView pulled down");
    }
}

这个对我有用 :)


18

要实现android Pull-to-Refresh,请尝试以下代码,

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

</android.support.v4.widget.SwipeRefreshLayout>

活动课:

ListView lv = (ListView) findViewById(R.id.lv);
SwipeRefreshLayout pullToRefresh = (SwipeRefreshLayout) findViewById(R.id.pullToRefresh);


lv.setAdapter(mAdapter);

pullToRefresh.setOnRefreshListener(new OnRefreshListener() {

        @Override
        public void onRefresh() {
            // TODO Auto-generated method stub

            refreshContent();

        }
    });



private void refreshContent(){ 

     new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                pullToRefresh.setRefreshing(false);
            }
        }, 5000);

 }

1
Thanks.it确实对我有所帮助
Arpan Sharma


7

请注意,在Android和WP上实施时,有一些UX问题需要解决。

“为什么设计师/开发人员不应该以iOS应用程序的样式实现“按需刷新”的一个很好的指标是,当Google和他们的团队在iOS中使用按需刷新时,他们及其团队从未在Android上使用“按需刷新”。

https://plus.google.com/109453683460749241197/posts/eqYxXR8L4eb


3
我知道这已经使用了一年多,但Gmail应用程序确实使用了“按需刷新”功能。但是,就UI而言,它并不完全相同,列表不会向下滚动,而是在屏幕顶部显示一个新视图。
ashishduh 2013年

4

如果您不希望您的程序看起来像强制安装在Android中的iPhone程序,请寻求更原始的外观,并执行类似于Gingerbread的操作:

替代文字


2
@Rob:我的意思是,当您拉动时,列表上方会显示橙色阴影,而不是像iPhone那样使列表弹回。这意味着作为评论(不是答案),但是评论不能包含图像。
Lie Ryan

啊,对不起,好主意。我还没有玩过姜饼,所以没有看到效果。仍在等待谷歌将其推向联系。
抢夺

9
我有姜饼,当列表静态时,橙色发光效果很好。但是pull-down-refresh是一种很棒的UI机制,可以刷新动态列表。尽管它在iOS世界中很普遍,但这是一个UI技巧,在Android生态系统中不会感到厌烦。我强烈建议您在官方Twitter应用程序中进行检查。:)
Thierry-Dimitri Roy

这里的本机行为是表明您已经到达列表的末尾。采取此操作并执行刷新完全是非本地的,因为您没有执行平台的操作。这意味着您更有可能使用户感到惊讶。我当然不希望也不希望刷新只是因为我到达了列表的末尾。下拉刷新更加直观明了。而且,随着本机Twitter应用程序的使用,我认为可以说很多人熟悉的UI概念是公平的。
steprobe,2012年



1

要获取最新的Lollipop Pull-To Refresh:

  1. 下载最新的Lollipop SDK和Extras / Android支持库
  2. 将Project的Build Target设置为Android 5.0(否则支持包的资源可能有错误)
  3. 将您的libs / android-support-v4.jar更新到21st版本
  4. 使用android.support.v4.widget.SwipeRefreshLayout加号android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

详细的指南可以在这里找到:http : //antonioleiva.com/swiperefreshlayout/

另外,我建议canChildScrollUp()在评论中阅读有关ListView的内容;)


再加上一个仅提及canChildScrollUp()的代码。很重要!
Petro

1

非常有趣的拉来刷新Yalantis。Gif for iOS,但您可以检查一下:)

<com.yalantis.pulltorefresh.library.PullToRefreshView
android:id="@+id/pull_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
    android:id="@+id/list_view"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />


0

我们首先应该知道什么是Pull来刷新android中的布局。我们可以调用pull在Android中刷新为刷卡刷新。当您从上到下滑动屏幕时,它将基于setOnRefreshListener进行一些操作。

这是演示如何实现android pull刷新的教程。我希望这有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.