SwipeRefreshLayout setRefreshing() not showing indicator initially

社会主义新天地 提交于 2019-11-26 06:56:47

问题


I have a very simple layout but when I call setRefreshing(true) in onActivityCreated() of my fragment, it does not show initially.

It only shows when I do a pull to refresh. Any ideas why it isn\'t showing up initially?

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>

Fragment code:

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
    }
}

回答1:


Faced with same issue. My solution -

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



回答2:


See Volodymyr Baydalka's answer instead.

These are the old workarounds.

That used to work on earlier version of the android.support.v4, but from version 21.0.0 ongoing it doesn't work and still exists with android.support.v4:21.0.3 released at 10-12 December, 2014 and this is the reason.

SwipeRefreshLayout indicator does not appear when the setRefreshing(true) is called before the SwipeRefreshLayout.onMeasure()

Workaround:

calling setProgressViewOffset() on the SwipeRefreshLayout that invalidtes the circle view of the layout causing SwipeRefreshLayout.onMeasure() to be called immediately.

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

UPDATE Better Workaround

Because the actionbar could got thinner when orientation changes or you have set actionbar size manually. We set the offset in pixels from the top of this view at which the progress spinner should come to reset after a successful swipe gesture to the current actionbar size.

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 Nov 20 2014

If it's not very crucial to your app to show the SwipeRefreshLayout once the view is started. You can just post it to a time in the future by using handlers or any thing you want.

as an example.

handler.postDelayed(new Runnable() {

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

or as Volodymyr Baydalka's answer mentioned.

Here is the issue in the android issue tracker. Please upvote it to show them that we need it to be fixed.




回答3:


My solution is to override 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;
        }
    }
}



回答4:


mRefreshLayout.getViewTreeObserver()
                .addOnGlobalLayoutListener(
                        new ViewTreeObserver.OnGlobalLayoutListener() {
                            @Override
                            public void onGlobalLayout() {
                                mRefreshLayout
                                        .getViewTreeObserver()
                                        .removeGlobalOnLayoutListener(this);
                                mRefreshLayout.setRefreshing(true);
                            }
                        });



回答5:


With Android support library 24.2.0 the issue should have been solved! https://developer.android.com/topic/libraries/support-library/revisions.html#24-2-0-bugfixes




回答6:


Based on Volodymyr Baydalka's answer, this is just a small idea that will help you to keep code clean. It deserves a post I believe: you will be able to revert the behavior easily from posting to direct method call, once the bug is fixed.

Write a utility class like:

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);
            }
        });
    }
}

In your code substitute mSwipeContainer.setRefreshing(isRefreshing) by Utils.setRefreshing(mSwipeContainer, isRefreshing): now only one point in the code needs to be changed once the bug is fixed, the Utils class. The method can also be inlined then (and removed from Utils).

There will be usually no noticeable visual difference. Keep in mind though that the pending refresh could keep alive your old Activity instances, holding on the SwipeRefreshLayout in their view hierarchies. If that is a concern, tweak the method to use WeakReferences, but normally you don't block the UI thread anyway, and thus delay gc by a couple of milliseconds only.




回答7:


Also you can call this method before setRefreshing..

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

It workef for me.




回答8:


I used AppCompat Library com.android.support:appcompat-v7:21.0.3, using your same approach and it worked. So, you update the version of that library.

Advice: RelativeLayout doesn't support orientation, it's an attribute for 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>



回答9:


In addition to Volodymyr Baydalka use the following code as well:

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

Explanation I implemented the solution given by Volodymyr Baydalka (using fragments) but after the swipeReferesh started it never went away even on calling swipeContainer.setRefreshing(false); so had to implement the code given above which solved my problem. any more ideas why this happens are most welcome.

Regards,

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




回答10:


@niks.stack In response to his answer, I would show the progress wheel after onLayout() has been done. When I used it directly after onMeasure(), it wouldn't honor some of the offsets, but using it after onLayout() did.

@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;
    }
}



回答11:


My solution (without 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);



回答12:


Im using 'com.android.support:appcompat-v7:23.1.1'

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

previously I was using swipeRefreshLayout.setRefreshing(true); inside getData() method,so it wasn't working. I don't know why its not working inside method.

Although I used swipeRefreshLayout.setRefreshing(true); only once in my Fragment.




回答13:


Try this

mSwipeRefreshLayout.setNestedScrollingEnabled(true);




回答14:


Another workaround is to create a new control and deriver from SwipeRefreshLayout. Override the OnMeasure function and toggle the refresh again, if refresh is activated. I use this solution in a xamarin project and it works well. Here some sample C#-Code:

class MySwipeRefreshLayout : SwipeRefreshLayout
{
    /// <summary>
    /// used to indentify, if measure was called for the first time
    /// </summary>
    private bool m_MeasureCalled;

    public MvxSwipeRefreshLayout(Context context, IAttributeSet attrs)
        : base(context, attrs)
    {
    }

    public MvxSwipeRefreshLayout(Context context)
        : base(context)
    {
    }

    public override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!m_MeasureCalled)
        {
            //change refreshing only one time
            m_MeasureCalled = true;

            if (Refreshing)
            {
                Refreshing = false;
                Refreshing = true;
            }
        }
    }
}


来源:https://stackoverflow.com/questions/26858692/swiperefreshlayout-setrefreshing-not-showing-indicator-initially

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!