SwipeRefreshLayout(Android的下拉刷新组件)
public class SwipeRefreshLayout
extends ViewGroup implements NestedScrollingParent, NestedScrollingChild
只要用户可以通过垂直滑动手势刷新视图的内容,就应该使用SwipeRefreshLayout。 实例化此视图的活动应该添加一个OnRefreshListener,以便在刷新刷新手势完成时通知它。 SwipeRefreshLayout将在每次手势再次完成时通知侦听器; 监听者负责正确确定何时实际启动其内容的刷新。 如果听众确定不应该刷新,则必须调用setRefreshing(false)来取消刷新的任何可视指示。 如果活动希望仅显示进度动画,则应调用setRefreshing(true)。 要禁用手势和进度动画,请在视图上调用setEnabled(false)。
该布局应该是由于手势而被刷新的视图的父级,并且只能支持一个直接的孩子。 此视图也将作为手势的目标,并将被强制匹配此布局中提供的宽度和高度。 SwipeRefreshLayout不提供辅助功能事件; 相反,必须提供菜单项以允许在使用该手势的任何地方刷新内容。
SwipeRefreshLayout类中两个重要的接口:
- interface SwipeRefreshLayout.OnChildScrollUpCallback
- 希望覆盖canChildScrollUp()方法行为的类应该实现此接口。
- interface SwipeRefreshLayout.OnRefreshListener
- 希望在滑动手势正确触发刷新时收到通知的类应实现此接口。
SwipeRefreshLayout类中的常用方法:
#
- void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener)
- 将侦听器设置为在通过滑动手势触发刷新时收到通知。
判断刷新状态
- boolean isRefreshing()
- 判断刷新状态
通知窗口小部件刷新状态已更改。
- void setRefreshing(boolean refreshing)
- 通知窗口小部件刷新状态已更改。
设置刷新时进度动画的颜色
- void setColorScheme(int… colors)
- API方法22.0.0中已弃用此方法。使用setColorSchemeResources(int)
- void setColorSchemeColors(int… colors)
- 设置进度动画中使用的颜色。
- void setColorSchemeResources(int… colorResIds)
- 从颜色资源设置进度动画中使用的颜色资源。
设置刷新时进度旋转光盘的背景颜色
- void setProgressBackgroundColor(int colorRes)
- API方法22.0.0中已弃用此方法。使用setProgressBackgroundColorSchemeResource(int)
- void setProgressBackgroundColorSchemeColor(int color)
- 设置进度旋转光盘的背景颜色。
- void setProgressBackgroundColorSchemeResource(int colorRes)
- 设置进度旋转光盘的背景颜色。
设置刷新指示器的位置
- void setProgressViewEndTarget(boolean scale, int end)
- 刷新指示器静止位置始终位于更新内容的顶部附近。
- void setProgressViewOffset(boolean scale, int start, int end)
- 刷新指示符起始和休息位置总是位于更新内容的顶部附近。
关于SwipeRefreshLayout的详细介绍官方API
SwipeRefreshLayout与ListFragment的结合使用实例:
public class CustomSwipeRefreshFragment extends ListFragment {
private static final int LIST_ITEM_COUNT = 20;
private SwipeRefreshLayout mSwipeRefreshLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Create the list fragment's content view by calling the super method
View listFragmentView=super.onCreateView(inflater, container, savedInstanceState);
// Now create a SwipeRefreshLayout to wrap the fragment's content view
mSwipeRefreshLayout=new ListFragmentSwipeRefreshLayout(container.getContext());
// Add the list fragment's content view to the SwipeRefreshLayout, making sure that it fills
// the SwipeRefreshLayout
mSwipeRefreshLayout.addView(listFragmentView,ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
// Make sure that the SwipeRefreshLayout will fill the fragment
mSwipeRefreshLayout.setLayoutParams(
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
/**
* Create an ArrayAdapter to contain the data for the ListView. Each item in the ListView
* uses the system-defined simple_list_item_1 layout that contains one TextView.
*/
ListAdapter adapter = new ArrayAdapter<>(
getActivity(),
android.R.layout.simple_list_item_1,
android.R.id.text1,
Cheeses.randomList(LIST_ITEM_COUNT));
// Set the adapter between the ListView and its backing data.
setListAdapter(adapter);
//设置下拉刷新监听器
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
initiateRefresh();
}
});
return mSwipeRefreshLayout;
}
/**
* 调用DummyBackgroundTask().execute()方法开始在后台刷新数据
* 通过将刷新过程抽象为单一方法,该应用程序允许SwipeGestureLayout onRefresh()方法和“刷新”操作项目刷新内容。
*/
private void initiateRefresh() {
new DummyBackgroundTask().execute();
}
/**
* 当AsyncTask完成时,它调用onRefreshComplete(),更新ListAdapter中的数据,并关闭进度条。
* @param result
*/
private void onRefreshComplete(List<String> result) {
// Remove all items from the ListAdapter, and then replace them with the new items
ArrayAdapter<String> adapter = (ArrayAdapter<String>) getListAdapter();
adapter.clear();
for (String cheese : result) {
adapter.add(cheese);
}
Toast.makeText(getActivity(), "刷新成功", Toast.LENGTH_SHORT).show();
// 停止刷新指示
mSwipeRefreshLayout.setRefreshing(false);
}
/**
* 在ListFragment中使用SwipeRefreshLayout的子类。
* 原因是因为SwipeRefreshLayout只支持一个单独的子View,它希望是一个触发刷新的子View。
* 在我们的例子中,布局的子View是ListFragment#onCreateView(LayoutInflater,ViewGroup,Bundle)返回的内容视图,
* 它是ViewGroup。 要启用ListView对“swipe-to-refresh”支持,我们需要覆盖默认行为,并在手势可能时正确发出信号。
* 这是通过重写#canChildScrollUp()方法来完成的。
*/
private class ListFragmentSwipeRefreshLayout extends SwipeRefreshLayout {
public ListFragmentSwipeRefreshLayout(Context context) {
super(context);
}
/**
* 如上所述,当可以进行“swipe-to-refresh”时,我们需要重写此方法以正确发出信号。
* @return true if the {@link android.widget.ListView} is visible and can scroll up.
*/
@Override
public boolean canChildScrollUp() {
final ListView listView=getListView();
if (listView.getVisibility()==VISIBLE){
return canListViewScrollUp(listView);
}else {
return true;
}
}
}
/**
* 异步线程刷新数据
*/
private class DummyBackgroundTask extends AsyncTask<Void, Void, List<String>> {
static final int TASK_DURATION = 3 * 1000; // 3 seconds
@Override
protected List<String> doInBackground(Void... params) {
// Sleep for a small amount of time to simulate a background-task
try {
Thread.sleep(TASK_DURATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Return a new random list of cheeses
return Cheeses.randomList(LIST_ITEM_COUNT);
}
@Override
protected void onPostExecute(List<String> result) {
super.onPostExecute(result);
// Tell the Fragment that the refresh has completed
onRefreshComplete(result);
}
}
// BEGIN_INCLUDE (check_list_can_scroll)
/**
* 检查{@link ListView}是否可以从当前位置向上滚动的实用方法。
* 处理平台版本差异,在需要时提供向后兼容的功能。
*/
private static boolean canListViewScrollUp(ListView listView) {
if (android.os.Build.VERSION.SDK_INT >= 14) {
// For ICS and above we can call canScrollVertically() to determine this
return ViewCompat.canScrollVertically(listView, -1);
} else {
// Pre-ICS we need to manually check the first visible item and the child view's top
// value
return listView.getChildCount() > 0 &&
(listView.getFirstVisiblePosition() > 0
|| listView.getChildAt(0).getTop() < listView.getPaddingTop());
}
}
// END_INCLUDE (check_list_can_scroll)
}
在布局中使用SwipeRefreshLayout
布局
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/
</android.support.v4.widget.SwipeRefreshLayout>
Activity
public class MainActivity extends AppCompatActivity {
private SwipeRefreshLayout mSwipeRefreshLayout;
private ListView mListView;
private int LIST_ITEM_COUNT=20;
private ArrayAdapter mAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_layout);
mListView = (ListView) findViewById(R.id.lv_next);
mAdapter = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
android.R.id.text1,
Cheeses.randomList(LIST_ITEM_COUNT));
mListView.setAdapter(mAdapter);
mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light,
android.R.color.holo_red_light,android.R.color.holo_orange_light,
android.R.color.holo_green_light);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
initiateRefresh();
}
});
}
private void initiateRefresh() {
new DummyBackgroundTask().execute();
}
private void onRefreshComplete(List<String> result) {
// Remove all items from the ListAdapter, and then replace them with the new items
mAdapter.clear();
for (String cheese : result) {
mAdapter.add(cheese);
}
Toast.makeText(this, "刷新成功", Toast.LENGTH_SHORT).show();
// Stop the refreshing indicator
mSwipeRefreshLayout.setRefreshing(false);
}
/**
* 异步线程刷新数据
*/
private class DummyBackgroundTask extends AsyncTask<Void, Void, List<String>> {
static final int TASK_DURATION = 3 * 1000; // 3 seconds
@Override
protected List<String> doInBackground(Void... params) {
// Sleep for a small amount of time to simulate a background-task
try {
Thread.sleep(TASK_DURATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Return a new random list of cheeses
return Cheeses.randomList(LIST_ITEM_COUNT);
}
@Override
protected void onPostExecute(List<String> result) {
super.onPostExecute(result);
// Tell the Fragment that the refresh has completed
onRefreshComplete(result);
}
}
}