Material Design用户界面指南中非常棒的一个设计是Swipe to Refresh UI pattern。实际上你可能已经看到或者用过这种效果了。在很多热门的app中都有这种效果,比facebok、 Google Newsstand, Trello, Gmail等等。
类似于如下效果(下面会教你进度条如何设置多色):
Swipe to Refresh UI非常适合于基于adapter的控件(如RecyclerView and ListView),一般它们都需要支持用户的刷新请求。关于Swipe to Refresh的实现,在KitKat版本中就有了SwipeRefreshLayout,Lollipop中对SwipeRefreshLayout做了改进,v4包含了SwipeRefreshLayout控件,我们只需做一些设置就可以了。为了方便读者,我把demo放在了github 上 下载地址。
我们是在一个包含最新版本Support库的Android Studio项目中实现Swipe to Refresh,我们要做的第一件事就是将support library添加进build.gradle
:
compile'com.android.support:support-v4:21.0.+'
在新建工程向导的时候自动创建了
res/layouts/activity_main.xml
文件,我们将一个ListView添加进SwipeRefreshLayout控件
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/activity_main_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView
android:id="@+id/activity_main_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</ListView>
</android.support.v4.widget.SwipeRefreshLayout>
注意ListView被包含在了SwipeRefreshLayout的里面。每次我们滑动ListView到SwipeRefreshLayout边缘的时候,SwipeRefreshLayout都会显示一个正在加载的图标,同时触发一个onRefresh事件。onRefresh是我们为自己list刷新数据添加的一个回调方法。
设置adapter
布局我们已经搞定,现在为列表添加数据,我们用一个简单的adapter来显示数据,数据来自于res/strings.xml
文件:
<string-array name="cat_names">
<item>George</item>
<item>Zubin</item>
<item>Carlos</item>
<item>Frank</item>
<item>Charles</item>
<item>Simon</item>
<item>Fezra</item>
<item>Henry</item>
<item>Schuster</item>
</string-array>
设置adapter:
class MainActivity extends Activity {
ListView mListView;
SwipeRefreshLayout mSwipeRefreshLayout;
Adapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acivity_main);
SwipeRefreshLayout mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.activity_main_swipe_refresh_layout);
mListView = findViewById(R.id.activity_main_list_view);
mListView.setAdapter(newArrayAdapter<String>(){
String[] fakeTweets = getResources().getStringArray(R.array.fake_tweets);
mAdapter = newArrayAdapter<String>(this, android.R.layout.simple_list_item_1, fakeTweets)
listView.setAdapter(mAdapter);
});
}
}
处理数据刷新
adapter已经设置,现在我们添加下拉刷新事件。我们会免费获得一个动画效果的加载图标,我们只需要决定ListView该做什么,这取决于SwipeRefreshLayout的OnRefreshListener 接口是如何实现的。我们用getNewCatNames模拟从webservice 中得到新数据。
@Override
public void onCreate(Bundle savedInstanceState) {
...
listView.setAdapter();
mSwipeRefreshLayout.setOnRefreshListener(newSwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshContent();
...
}
// fake a network operation's delayed response
// this is just for demonstration, not real code!
private void refreshContent(){
newHandler().postDelayed(newRunnable() {
@Override
public void run() {
mAdapter = newArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, getNewCatNames());
mListView.setAdapter(mAdapter);
mSwipeRefreshLayout.setRefreshing(false);
});
}
// get new cat names.
// Normally this would be a call to a webservice using async task,
// or a database operation
private List<String> getNewCatNames() {
List<String> newCatNames = newArrayList<String>();
for(int i = 0; i < mCatNames.size(); i++) {
int randomCatNameIndex = newRandom().nextInt(mCatNames.size() - 1);
newCatNames.add(mCatNames.get(randomCatNameIndex));
}
returnnewCatNames;
}
注意上面的代码中refreshContent()
方法最后一行代码setRefreshing(false);
setRefreshing
的作用是设置刷新加载效果的icon是否继续显示,这里使用handler做了个延时,模拟实际加载数据需要的时间,当handler的post开始执行的时候setRefreshing(false)
表示加载结束,停止播放加载动画。
自定义
你可以自定义SwipeRefreshLayout的外观。setColorSchemeResources()
可以改变加载图标的颜色。
先在资源文件中定义几个颜色值:
<resources>
<color name="orange">#FF9900</color>
<color name="green">#009900</color>
<color name="blue">#000099</color>
</resources>
然后调用setColorSchemeResources(R.color.orange, R.color.green, R.color.blue);
SwipeRefreshLayout旋转的时候将会在这三种颜色间切换。
就如你所看到的Swipe to Refresh简化了用户请求更新数据的操作,关于SwipeRefreshLayout的更多api请查看官方文档。
注:本篇文章提供的demo编译的时候虽然用的是21版本的appcompat,但是运行还是需要在5.0的设备上,因为demo的Material主题和颜色appcompat无能为力。当然你可以如下更改一下主题,这样在4.x版本上也能运行:
demo本来的主题:
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme"parent="android:ThemeOverlay.Material.Light">
<!-- Customize your theme here. -->
<item name="android:colorPrimary">@android:color/holo_blue_dark</item>
</style>
</resources>
改成:
<resources>
<!-- Base application theme. -->
<style name="AppTheme"parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
</style>
</resources>
本文翻译,英文出处:Implementing Swipe to Refresh, an Android Material Design UI Pattern