Reputation: 2592
I find most of the material is about discussing adding "pull to refresh" in the area below AppBarLayout, such as SwipeRefreshLayout, I wonder how to do this in the AppBarLayout, which means:
When pull down, the pull-to-refresh indicator appeaars in the AppBarLayout.
how to implement this? Thanks
=================UPDATE===================
I finally worked it out on my own way. Here is the video link recording the simple UI.
The key point is I rewrite the appbarlayout-spring-behavior from github. It's really helpeful. Simply put, I rewrited the AppBarLayoutSpringBehavior, adding a Pull-To-Refresh-Callback when draging, and add some logic to displaying the pull-to-refresh animation prevent simplely animating back to original state. After sometime, then I tell the behavior to animate back.
Though the rewriten code seems ugly, but it seems feasible. I will refactor my code to make it clean and modular
Upvotes: 12
Views: 3907
Reputation: 51
I have wrote one nestrefresh repo which you can add pull refresh for the header same to AppBarLayout. You can add pull to refresh for child in ViewPager or pull to load more. You can use ChildCoordinatorLayout in my repo to wrap AppBarLayout if you want to use AppBarLayout only. But when scroll AppBarLayout can not refresh because of AppBarLayout has not send scroll event to parent. So you can try RefreshBarLayout in the repo.
Upvotes: 2
Reputation: 2592
I finally worked it out on my own way. Here is the video link recording the simple UI.
The key point is I rewrite the appbarlayout-spring-behavior from github. It's really helpeful. Simply put, I rewrited the AppBarLayoutSpringBehavior, adding a Pull-To-Refresh-Callback when draging, and add some logic to displaying the pull-to-refresh animation prevent simplely animating back to original state. After sometime, then I tell the behavior to animate back.
Though the rewriten code seems ugly, but it seems feasible. I will refactor my code to make it clean and modular
Upvotes: 1
Reputation: 121
EDIT Added the ProgressBar inside the AppBarLayout.
You need to wrap the ReyclerView with a SwipeRefreshLayout like you said and also add a ProgressBar into a custom ToolBar:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.myapplication.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_weight="1"
android:gravity="start|center"
android:text="@string/app_name"
android:textColor="@android:color/white" />
<ProgressBar
android:id="@+id/a_main_progress"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:visibility="invisible" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/a_main_swipe"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/a_main_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>
You will also need to set the listener in your MainActivity:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private SwipeRefreshLayout swipeRefreshLayout;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.a_main_swipe);
progressBar = (ProgressBar) findViewById(R.id.a_main_progress);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
progressBar.setVisibility(View.VISIBLE);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// Simulates a long running task (updating data)
swipeRefreshLayout.setRefreshing(false);
progressBar.setVisibility(View.INVISIBLE);
}
}, 2000);
}
});
MainAdapter mainAdapter = new MainAdapter(Arrays.asList("Hello", "World", "Bye"));
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.a_main_recycler);
recyclerView.setAdapter(mainAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
}
}
This is a simple adapter code if you needed it too:
MainAdapter.java
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
private List<String> strings;
public MainAdapter(List<String> strings) {
this.strings = strings;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(strings.get(position));
}
@Override
public int getItemCount() {
return strings != null ? strings.size() : 0;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
}
public void bind(String s) {
textView.setText(s);
}
}
}
This is the updated Result:
Upvotes: 1
Reputation: 1233
You can try a view hierarchy like this
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/appBar"/>
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
</RelativeLayout>
In your Java class, you can use your SwipeRefreshLayout like this
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
swipeRefreshLayout.setProgressViewOffset(false, 0, (int) (swipeRefreshLayout.getPaddingTop() * 1.5));
swipeRefreshLayout.setOnRefreshListener(() -> {
swipeRefreshLayout.setRefreshing(true);
// long process here
new Handler().postDelayed(() -> runOnUiThread(() -> swipeRefreshLayout.setRefreshing(false)), 2000);
});
Upvotes: 0