如何实现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
为例,它可以是任何View
如LinearLayout
、ScrollView
等)
<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
视图的分支,该视图具有新的有趣实现,例如 PullTorRefreshWebView
或 PullToRefreshGridView
,或者可以在列表底部添加 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。
主逻辑在扩展ListView
的PullToRefreshListView
中实现。 在内部,它使用该小部件现已更新,支持 1.5 及更高版本,但请阅读 README 以获取 1.5 支持。smoothScrollBy
(API 级别 8)控制标题视图的滚动。
在您的布局中,您只需像这样添加它。
<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的主要内容,如果未能解决你的问题,请参考以下文章