web-dev-qa-db-fra.com

SwipeRefreshLayout setRefreshing () ne pas afficher l'indicateur initialement

J'ai une mise en page très simple mais quand j'appelle setRefreshing(true) dans onActivityCreated() de mon fragment, il ne s'affiche pas initialement.

Il ne montre que lorsque je fais un pull pour actualiser. Des idées pourquoi il ne se présente pas initialement?

Fragment xml:

<Android.support.v4.widget.SwipeRefreshLayout
    Android:id="@+id/swipe_container"
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">

        <RelativeLayout
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:orientation="vertical">

        </RelativeLayout>


    </ScrollView>
</Android.support.v4.widget.SwipeRefreshLayout>

Code de fragment:

public static class LinkDetailsFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener {

    @InjectView(R.id.swipe_container)
    SwipeRefreshLayout mSwipeContainer;

    public static LinkDetailsFragment newInstance(String subreddit, String linkId) {
        Bundle args = new Bundle();
        args.putString(EXTRA_SUBREDDIT, subreddit);
        args.putString(EXTRA_LINK_ID, linkId);

        LinkDetailsFragment fragment = new LinkDetailsFragment();
        fragment.setArguments(args);

        return fragment;
    }

    public LinkDetailsFragment() {
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mSwipeContainer.setOnRefreshListener(this);
        mSwipeContainer.setColorScheme(Android.R.color.holo_blue_bright,
                Android.R.color.holo_green_light,
                Android.R.color.holo_orange_light,
                Android.R.color.holo_red_light);
        mSwipeContainer.setRefreshing(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View rootView = inflater.inflate(R.layout.fragment_link_details, container, false);
        ButterKnife.inject(this, rootView);
        return rootView;
    }

    @Override
    public void onRefresh() {
        // refresh
    }
}
140
thunderousNinja

Face au même problème. Ma solution -

mSwipeRefreshLayout.post(new Runnable() {
    @Override
    public void run() {
        mSwipeRefreshLayout.setRefreshing(true);
    }
});
303
Volodymyr Baydalka

Voir la réponse de Volodymyr Baydalka à la place.

Voici les anciennes solutions de contournement.

Cela fonctionnait auparavant sur la version précédente du Android.support.v4, mais à partir de la version 21.0.0 en cours, il ne fonctionne pas et existe toujours avec Android.support.v4:21.0.3 publié le 10-12. Décembre 2014 et c'est la raison.

L'indicateur SwipeRefreshLayout n'apparaît pas lorsque la setRefreshing(true) est appelée avant la SwipeRefreshLayout.onMeasure()

Solution de contournement:

appelez setProgressViewOffset() sur SwipeRefreshLayout qui invalide la vue circulaire de la présentation, ce qui provoque l'appel immédiat de SwipeRefreshLayout.onMeasure().

mSwipeRefreshLayout.setProgressViewOffset(false, 0,
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));
mSwipeRefreshLayout.setRefreshing(true);

MISE À JOUR Meilleure solution de contournement

Parce que la barre d’action pourrait devenir plus fine lorsque l’orientation change ou que vous avez défini manuellement la taille de la barre d’action. Nous définissons le décalage en pixels à partir du haut de cette vue, auquel la flèche de progression doit revenir après un mouvement de balayage réussi pour atteindre la taille de la barre d’action actuelle.

TypedValue typed_value = new TypedValue();
getActivity().getTheme().resolveAttribute(Android.support.v7.appcompat.R.attr.actionBarSize, typed_value, true);
mSwipeRefreshLayout.setProgressViewOffset(false, 0, getResources().getDimensionPixelSize(typed_value.resourceId));

UPDATE du 20 novembre 2014

S'il n'est pas très important pour votre application d'afficher SwipeRefreshLayout une fois la vue démarrée. Vous pouvez simplement le poster à une heure future en utilisant des gestionnaires ou tout ce que vous voulez.

par exemple.

handler.postDelayed(new Runnable() {

    @Override
    public void run() {
        mSwipeRefreshLayout.setRefreshing(true);
    }
}, 1000);

ou comme mentionné dans la réponse de Volodymyr Baydalka.

Voici le numéro dans le traqueur de problèmes Android. S'il vous plaît, invitez-le pour leur montrer que nous devons le réparer.

100
Ahmed Hegazy

Ma solution est de remplacer SwipeRefreshLayout:

public class MySwipeRefreshLayout extends SwipeRefreshLayout {

    private boolean mMeasured = false;
    private boolean mPreMeasureRefreshing = false;

    public MySwipeRefreshLayout(final Context context) {
        super(context);
    }

    public MySwipeRefreshLayout(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!mMeasured) {
            mMeasured = true;
            setRefreshing(mPreMeasureRefreshing);
        }
    }

    @Override
    public void setRefreshing(final boolean refreshing) {
        if (mMeasured) {
            super.setRefreshing(refreshing);
        } else {
            mPreMeasureRefreshing = refreshing;
        }
    }
}
46
niks.stack
mRefreshLayout.getViewTreeObserver()
                .addOnGlobalLayoutListener(
                        new ViewTreeObserver.OnGlobalLayoutListener() {
                            @Override
                            public void onGlobalLayout() {
                                mRefreshLayout
                                        .getViewTreeObserver()
                                        .removeGlobalOnLayoutListener(this);
                                mRefreshLayout.setRefreshing(true);
                            }
                        });
20
baoyz

Avec Android bibliothèque de support 24.2.0, le problème aurait dû être résolu! https://developer.Android.com/topic/libraries/support-library/revisions.html#24-2-0-bugfixes

14
Andrei Buneyeu

Basé sur réponse de Volodymyr Baydalka , il ne s'agit que d'une petite idée qui vous aidera à garder le code propre. Cela mérite une publication, je crois: vous pourrez facilement inverser le comportement de publication en appel de méthode direct, une fois le bogue corrigé.

Écrivez une classe utilitaire comme:

public class Utils
{
    private Utils()
    {
    }

    public static void setRefreshing(final SwipeRefreshLayout swipeRefreshLayout, final boolean isRefreshing)
    {
        // From Guava, or write your own checking code
        checkNonNullArg(swipeRefreshLayout);
        swipeRefreshLayout.post(new Runnable()
        {
            @Override
            public void run()
            {
                swipeRefreshLayout.setRefreshing(isRefreshing);
            }
        });
    }
}

Dans votre code, remplacez mSwipeContainer.setRefreshing(isRefreshing) par Utils.setRefreshing(mSwipeContainer, isRefreshing): un seul point dans le code doit être modifié une fois le bogue corrigé, la classe Utils. La méthode peut également être alors insérée (et retirée de Utils).

Il n'y aura généralement aucune différence visuelle notable. Gardez toutefois à l'esprit que l'actualisation en attente peut garder en vie vos anciennes instances Activity, en conservant les SwipeRefreshLayout dans leurs hiérarchies de vues. Si cela vous pose problème, modifiez la méthode pour qu'elle utilise WeakReferences, mais normalement, vous ne bloquez pas le thread d'interface utilisateur et ne retardez donc gc que de quelques millisecondes.

4
Gil Vegliach

Vous pouvez aussi appeler cette méthode avant setRefreshing.

    swipeRefreshLayout.measure(View.MEASURED_SIZE_MASK,View.MEASURED_HEIGHT_STATE_SHIFT);
swipeRefreshLayout.setRefreshing(true);

Ça marche pour moi.

2
Leonardo G. Roese

@ niks.stack En réponse à sa réponse, je montrerais la molette de progression après le onLayout(). Lorsque je l'utilisais directement après onMeasure(), il ne tenait pas compte de certains décalages, mais son utilisation après onLayout() le faisait.

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if (!mLaidOut) {
        mLaidOut = true;
        setRefreshing(mPreLayoutRefreshing);
    }
}

@Override
public void setRefreshing(boolean refreshing) {
    if (mLaidOut) {
        super.setRefreshing(refreshing);
    } else {
        mPreLayoutRefreshing = refreshing;
    }
}
1
mco

En plus de Volodymyr Baydalka, utilisez également le code suivant:

swipeContainer.post(new Runnable() {
        @Override
        public void run() {
            swipeContainer.setRefreshing(false);
        }
    });

Explication J'ai implémenté la solution donnée par Volodymyr Baydalka (en utilisant des fragments), mais après le début du swipeReferesh, il ne s'est jamais éteint même en appelant swipeContainer.setRefreshing(false);. toutes les idées pour lesquelles cela se produit sont les bienvenues.

Cordialement,

'com.Android.support:appcompat-v7:22.2.1'

1
Juni

J'ai utilisé AppCompat Library com.Android.support:appcompat-v7:21.0.3, en utilisant votre même approche et cela a fonctionné. Donc, vous mettez à jour la version de cette bibliothèque.

Conseil: RelativeLayout ne supporte pas l'orientation, c'est un attribut pour LinearLayout.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                                                 Bundle savedInstanceState) {       
  ViewGroup view = (ViewGroup) inflater.inflate(R.layout.license_fragment, 
           container, false);ButterKnife.inject(this, view);
    // Setting up Pull to Refresh
    swipeToRefreshLayout.setOnRefreshListener(this);
    // Indicator colors for refresh
    swipeToRefreshLayout.setColorSchemeResources(R.color.green, 
                R.color.light_green);
}

Layout XML:

<Android.support.v4.widget.SwipeRefreshLayout>

<ScrollView
                    Android:layout_width="match_parent"
                    Android:layout_height="match_parent"
                    Android:paddingBottom="@dimen/activity_margin_vertical"
                    Android:paddingTop="@dimen/activity_margin_vertical">

    <!-- Content -->
</ScrollView>

</Android.support.v4.widget.SwipeRefreshLayout>
1
Jesús Castro

J'utilise 'com.Android.support:appcompat-v7:23.1.1'

swipeRefreshLayout.post(new Runnable() {
        @Override
        public void run() {
            swipeRefreshLayout.setRefreshing(true);
            getData();
        }
    });

auparavant, j'utilisais la méthode swipeRefreshLayout.setRefreshing(true); dans la méthode getData(). Elle ne fonctionnait donc pas. Je ne sais pas pourquoi sa méthode ne fonctionne pas à l'intérieur.

Bien que j’ai utilisé swipeRefreshLayout.setRefreshing(true); une seule fois dans mon fragment.

0
Chinmay

Ma solution (sans support v7) -

TypedValue typed_value = new TypedValue();
getTheme().resolveAttribute(Android.R.attr.actionBarSize, typed_value, true);
swipeLayout.setProgressViewOffset(false, 0, getResources().getDimensionPixelSize(typed_value.resourceId));

if(!swipeLayout.isEnabled())
     swipeLayout.setEnabled(true);
swipeLayout.setRefreshing(true);
0
Artrmz

Essaye ça

mSwipeRefreshLayout.setNestedScrollingEnabled (true);

0
Ashwin H