如何实现Android Pull-to-Refresh

Posted

技术标签:

【中文标题】如何实现Android Pull-to-Refresh【英文标题】:How to implement Android Pull-to-Refresh 【发布时间】:2011-06-02 18:42:56 【问题描述】:

在 Twitter(官方应用)等 android 应用中,当遇到 ListView 时,可以将其拉下(释放时会弹回)以刷新内容。

我想知道在您看来,实现它的最佳方式是什么?

我能想到的一些可能性:

    ListView 顶部的一个项目 - 但是我认为通过 ListView 上的动画滚动回项目位置 1(基于 0)并不是一件容易的事。 ListView 之外的另一个视图 - 但我需要注意在拉动时将 ListView 位置向下移动,我不确定我们是否可以检测到对 ListView 的拖动触摸是否仍然真的滚动项目列表视图。

有什么建议吗?

附:我想知道官方 Twitter 应用程序源代码什么时候发布。据说会发布,但是6个月过去了,从那以后我们就再也没听说过。

【问题讨论】:

这个功能是否可以在动态创建的TableLayout中实现。请帮忙..... github.com/fruitranger/PulltorefreshListView 是我的另一个实现。流畅的多点触控支持。 相关:“Pull-to-refresh”: an anti UI pattern on Android 是一篇文章,它认为这个 UI应该在 Android 上使用,并引发了很多关于其适用性的讨论。 有人应该让 Google 知道,因为最新版本的 Android 版 Gmail 使用了这种“反模式”。 Pull to refresh 是(并且已经有一段时间了)ios 和 Android 中采用的标准模式,而且非常自然,因此这种反模式讨论已经过时。用户会期望看到它并表现得如此。 【参考方案1】:

谷歌终于发布了正式版的pull-to-refresh库!

在支持库里面叫SwipeRefreshLayout,文档是here

    添加SwipeRefreshLayout 作为视图的父视图,这将被视为刷新布局的拉动。 (我以ListView 为例,它可以是任何ViewLinearLayoutScrollView 等)

     <android.support.v4.widget.SwipeRefreshLayout
         android:id="@+id/pullToRefresh"
         android:layout_
         android:layout_>
         <ListView
             android:id="@+id/listView"
             android:layout_
             android:layout_/>
     </android.support.v4.widget.SwipeRefreshLayout>
    

    为你的类添加一个监听器

     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 取代。可以在here找到新库的链接。

另外,您需要在您的项目中添加以下依赖项:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

你可以去Refactor>>迁移到AndroidX,Android Studio会帮你处理依赖。

【讨论】:

我可以在 SwipeRefreshLayout 上使用 ProgressBar 代替配色方案吗? 2014 年 4 月 1 日 - 这不是开玩笑 示例代码guides.codepath.com/android/Implementing-Pull-to-Refresh-Guide【参考方案2】:

那些希望为 RecyclerView 实现拉取刷新功能的人可以按照我的简单教程 How to implement Pull To Refresh for RecyclerView in Android。

要导入的库

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'

XML 代码

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipe_layout"
    android:layout_
    android:layout_>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_
        android:layout_/>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

活动 JAVA 代码

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends AppCompatActivity 

private SwipeRefreshLayout swipeRefreshLayout;

...

@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
       
        ...
        swipeRefreshLayout = findViewById(R.id.swipe_layout);
        initializeRefreshListener();


    void initializeRefreshListener() 

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 
            @Override
            public void onRefresh() 
                // This method gets called when user pull for refresh,
                // You can make your API call here,
                // We are using adding a delay for the moment
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() 
                    @Override
                    public void run() 
                        if(swipeRefreshLayout.isRefreshing()) 
                            swipeRefreshLayout.setRefreshing(false);
                        
                    
                , 3000);
            
        );
    

【讨论】:

【参考方案3】:

我们首先要知道什么是 android 中的 Pull to refresh layout 。我们可以在 android 中调用 pull 来刷新为 swipe-to-refresh。当您从上到下滑动屏幕时,它会根据 setOnRefreshListener 执行一些操作。

这里是tutorial,演示了如何实现android pull to refresh。我希望这会有所帮助。

【讨论】:

【参考方案4】:

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

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

最好的是在 Android 4.1 中完美运行(普通的PullToRefresh 不起作用)

【讨论】:

自述文件顶部的大注释表明:该项目不再维护。无论如何,这个库是我迄今为止见过的最好的库!干得好! 不再维护并不意味着它不好。仍然使用它来满足我所有的刷新需求:)【参考方案5】:

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

android.support.v4.widget.SwipeRefreshLayout;

一旦导入,您就可以将布局定义如下:

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_
        android:layout_>
    <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_
        android:layout_
        android:background="@color/button_material_light"
        >

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

我假设您使用回收站视图而不是列表视图。但是,listview 仍然有效,因此您只需将 recyclerview 替换为 listview 并更新 java 代码(Fragment)中的引用。

在您的活动片段中,您首先实现接口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/… 中所述,“不要在滑动手势触发刷新时调用它” 干得好!谢谢。【参考方案6】:

要实现android Pull-to-Refresh,试试这段代码,

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_
        android:layout_>

    <ListView
        android:id="@+id/lv"
        android:layout_
        android:layout_ >
    </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);

 

【讨论】:

谢谢。它真的帮助了我【参考方案7】:

非常有趣的Pull-to-RefreshYalantis。 适用于 iOS 的 Gif,但您可以查看 :)

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

【讨论】:

【参考方案8】:

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

    下载最新的 Lollipop SDK 和 Extras/Android 支持库 将项目的构建目标设置为 Android 5.0(否则支持包可能会出现资源错误) 将您的 libs/android-support-v4.jar 更新到第 21 个版本 使用android.support.v4.widget.SwipeRefreshLayout 加上android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

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

对于 ListView,我建议在 cmets 中阅读有关 canChildScrollUp() 的信息;)

【讨论】:

加一个只是为了提到 canChildScrollUp()。非常重要!【参考方案9】:

我认为最好的库是:https://github.com/chrisbanes/Android-PullToRefresh。

适用于:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager

【讨论】:

【参考方案10】:

没有人提到像 Google Now 或 Gmail 应用程序那样显示在操作栏顶部的新型“拉动刷新”。

有一个库ActionBar-PullToRefresh 的工作原理完全相同。

【讨论】:

【参考方案11】:

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

“为什么设计师/开发人员不应该以 iOS 应用程序的方式实现下拉刷新的一个很好的指标是,Google 和他们的团队从不在 Android 上使用下拉刷新,而在 iOS 中使用它。”

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

【讨论】:

我知道这已经有一年多了,但 Gmail 应用确实使用下拉刷新。但是在 UI 方面并不完全相同,列表不会向下滚动,而是在屏幕顶部显示一个新视图。【参考方案12】:

我有一个非常简单的方法来做到这一点,但现在确定它是万无一失的方法 有我的代码 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 的 Activity 上实现 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");
    

它对我有用:)

【讨论】:

【参考方案13】:

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

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

【讨论】:

我尝试了这里列出的所有实现,而您的实现是最好的,就简单/纯/平滑的拉动刷新实现而言(没有像 Johan 那样的点击刷新怪异)。谢谢! 这可以代替标准的 ListView 与 ListActivity、ListFragment 等一起使用吗? 是的,只需为 PullToRefreshListView 提供正确的 id。在 XML 中:android:id="@android:id/list" 这真是太棒了!谷歌把我带到了这里,通过这些例子,你的看起来最容易实现。太棒了,谢谢你先生! 非常明智的设计组件,漂亮而简单。这绝对应该是公认的答案。【参考方案14】:

我在这里写了一个拉动刷新组件:https://github.com/guillep/PullToRefresh 如果列表没有项目,它会起作用,并且我已经在 >=1.6 android 手机上对其进行了测试。

感谢任何建议或改进:)

【讨论】:

【参考方案15】:

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

主逻辑在扩展ListViewPullToRefreshListView 中实现。 在内部,它使用smoothScrollBy(API 级别 8)控制标题视图的滚动。该小部件现已更新,支持 1.5 及更高版本,但请阅读 README 以获取 1.5 支持。

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

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

【讨论】:

嗨约翰,我已经下载了你的示例代码。它适用于 android 2.2 设备,但不适用于 2.1 设备。我认为因为它使用了仅在 2.2 或更高版本中可用的 smoothScrollBy 方法,对吗?你有什么想法将这个效果实现到 2.1 或更早版本中吗?谢谢 是的,正如我在smoothScrollBy 在 API 级别 8 (2.2) 中引入的答案中所说的那样是正确的。我还没有想出一个合适的方法来为其他版本实现它,但它猜测应该可以移植 smoothScrollBy 的实现,但我想讨论应该保留在项目站点而不是堆栈溢出?跨度> id 是@+id/android:list 而不是@android:id/list 是不是故意的,看起来很奇怪?该项目在我这边引发了通货膨胀错误,我目前正在检查... 这是我发现的最好的拉刷新库..github.com/chrisbanes/Android-PullToRefresh。它适用于 ListViews、GridViews 和 Webviews。还实现了上拉刷新模式。 如何在使用 Intellij Idea 时将项目添加到库文件夹中?有人可以帮帮我吗?【参考方案16】:

如果您不希望您的程序看起来像一个强制安装到 Android 中的 iPhone 程序,那么就着眼于更原生的外观和感觉并做一些类似于 Gingerbread 的事情:

【讨论】:

@Rob:我的意思是当你过度拉动时列表顶部有橙色阴影,而不是像 iPhone 上那样让列表反弹。这意味着评论(不是回答),但 cmets 不能有图像。 啊,对不起,好主意。我还没有玩过姜饼,所以还没有看到效果。仍在等待谷歌将其推出到 nexus 中。 我有姜饼,当列表是静态的时,橙色发光效果很好。但是下拉刷新是刷新动态列表的一个很好的 UI 机制。虽然它在 iOS 世界中很流行,但它是一种在 Android 生态系统中并不奇怪的 UI 技巧。我强烈建议您在官方 Twitter 应用程序中查看。 :) 这里的原生行为是表明您已到达列表的末尾。接受这一点并执行刷新同样是非本地的,因为您没有做平台所做的事情。这意味着您更有可能让用户感到惊讶。我当然不会因为我到达列表的末尾而期望也不想刷新。下拉刷新更加直观和清晰。由于原生 twitter 应用程序使用它,我认为可以公平地说这是一个很多人都熟悉的 UI 概念。

以上是关于如何实现Android Pull-to-Refresh的主要内容,如果未能解决你的问题,请参考以下文章

Android上如何实现自动登陆功能?

android下滑动返回上一个页面如何实现

android 如何实现隐藏按钮

android中的checkBox如何实现单选

在android开发中如何实现多张图片的循环显示

Android如何实现Android发送短信