MISE À JOUR: Je pensais que cela fonctionnait correctement. Mais après quelques problèmes de test existe toujours * sniff *
Ensuite, j'ai fait une version plus simple pour voir ce qui se passait exactement et j'ai appris que le fragment rafraîchissant qui aurait dû être détaché est toujours là. Ou exactement, la vue de l'ancien fragment est restée là, en haut de le fragment le plus récent. Étant donné que l'arrière-plan de RecyclerView de mon application d'origine n'est pas transparent, il s'est avéré ce que j'ai dit auparavant.
FIN DE MISE À JOUR
J'ai un MainActivity
avec une disposition comme celle-ci:
<Android.support.v4.widget.DrawerLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools" Android:id="@+id/drawer_layout"
Android:layout_width="match_parent" Android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout Android:id="@+id/container" Android:layout_width="match_parent"
Android:layout_height="match_parent" />
<!-- Android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
Android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment Android:id="@+id/navigation_drawer"
Android:layout_width="@dimen/navigation_drawer_width" Android:layout_height="match_parent"
Android:layout_gravity="start" tools:layout="@layout/fragment_navigation_drawer" />
</Android.support.v4.widget.DrawerLayout>
Le fragment ContentView
que j'utilise pour remplir @id/container
Est configuré comme:
<Android.support.v4.widget.SwipeRefreshLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/contentView"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/Tweet_list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/grey_300"/>
</Android.support.v4.widget.SwipeRefreshLayout>
Et voici onCreateView()
de ContentView
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View inflatedView = inflater.inflate(R.layout.fragment_content, container, false);
mRecyclerView = (RecyclerView) inflatedView.findViewById(R.id.Tweet_list);
mRecyclerView.setHasFixedSize(false);
mLinearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mTweetList = new ArrayList<Tweet>;
mAdapter = new TweetAdapter(mTweetList);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mSwipeRefreshLayout = (SwipeRefreshLayout) inflatedView.findViewById(R.id.contentView);
mSwipeRefreshLayout.setOnRefreshListener(
...
);
return inflatedView;
}
Puis dans MainActivity
je change le contenu à afficher en changeant différents ContentView
. Tout semble bon sauf une chose: lorsque je change de ContentView
fragments PENDANT l'actualisation par le tiroir de navigation, le contenu se bloque. Mais en réalité, tout fonctionne comme d'habitude, sauf que vous ne pouvez pas le voir.
Eh bien ... Après quelques difficultés, j'ai finalement résolu ce problème par moi-même, d'une manière délicate ...
J'ai juste besoin de les ajouter dans onPause()
:
@Override
public void onPause() {
super.onPause();
...
if (mSwipeRefreshLayout!=null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
}
Ce problème semble toujours se produire dans appcompat 22.1.1. Envelopper le SwipeRefreshLayout dans un FrameLayout a résolu cela pour moi
<FrameLayout 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/contentView"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/Tweet_list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/grey_300" />
</Android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
En plus de la réponse @ zlm2012, j'ai remarqué que ce problème a été reproduit sous la bibliothèque de support 21.0.0, mais semble être corrigé en ce moment à 21.0.3
La solution fonctionne, mais je pense qu'il vaut mieux simplement mettre ces lignes dans sa propre fonction, comme:
public void terminateRefreshing() {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
et appeler lors du changement de fragment.
Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);
if(prevFrag instanceof SwipeRefreshFragment) {
((SwipeRefreshFragment)prevFrag).terminateRefreshing();
}
fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();
Ça marche! Supprimez simplement la transition de votre remplacement de fragment, dans mon cas, j'ai supprimé ce qui suit de mon code:
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
Ensemble clickable="true"
dans la disposition parent supérieure ... Cela peut résoudre le problème.
Pour le moment, vous pouvez éviter le problème en:
public class FixedRefreshLayout extends SwipeRefreshLayout {
private static final String TAG = "RefreshTag";
private boolean selfCancelled = false;
public FixedRefreshLayout(Context context) {
super(context);
}
public FixedRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected Parcelable onSaveInstanceState()
{
if(isRefreshing()) {
clearAnimation();
setRefreshing(false);
selfCancelled = true;
Log.d(TAG, "For hide refreshing");
}
return super.onSaveInstanceState();
}
@Override
public void setRefreshing(boolean refreshing) {
super.setRefreshing(refreshing);
selfCancelled = false;
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(hasWindowFocus && selfCancelled) {
setRefreshing(true);
Log.d(TAG, "Force show refreshing");
}
}
}
Cela a l'avantage supplémentaire de reprendre l'animation si vous décidez de ne pas changer le fragment (provenant d'un menu). Il est également lié à l'animation interne pour vous assurer que l'animation rafraîchissante ne revient pas si l'actualisation du réseau est déjà terminée.
Arrêtez SwipeRefresh chaque fois qu'un élément du menu de navigation est cliqué. Ça a marché.
private void selectItem(int position) {
mSwipeRefreshLayout.setRefreshing(false);
/*
Other part of the function
*/
}