146

我有一个非常简单的布局,但是当我调用我setRefreshing(true)onActivityCreated()片段时,它最初没有显示。

它仅在我拉动刷新时显示。任何想法为什么它最初没有出现?

片段 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>

片段代码:

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

14 回答 14

310

面临同样的问题。我的解决方案 -

mSwipeRefreshLayout.post(new Runnable() {
    @Override
    public void run() {
        mSwipeRefreshLayout.setRefreshing(true);
    }
});
于 2014-11-13T14:18:46.997 回答
102

请参阅 Volodymyr Baydalka 的答案。

这些是旧的解决方法。

这曾经适用于早期版本的android.support.v4,但从版本 21.0.0 开始,它不起作用并且在2014 年 12 月 10 日至 12 日android.support.v4:21.0.3发布时仍然存在,这就是原因。

setRefreshing(true)SwipeRefreshLayout 指示器在调用之前不出现SwipeRefreshLayout.onMeasure()

解决方法:

调用setProgressViewOffset()会使SwipeRefreshLayout布局的圆形视图无效,导致SwipeRefreshLayout.onMeasure()立即被调用。

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

更新更好的解决方法

因为当方向改变或您手动设置操作栏大小时,操作栏可能会变薄。我们设置了该视图顶部的偏移量(以像素为单位),在成功滑动手势后进度微调器应重置为当前操作栏大小。

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

2014 年 11 月 20 日更新

如果视图启动后显示 SwipeRefreshLayout 对您的应用来说不是很重要。您可以使用处理程序或任何您想要的东西将其发布到未来的某个时间。

举个例子。

handler.postDelayed(new Runnable() {

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

或如 Volodymyr Baydalka 的回答所述。

这是android问题跟踪器中的问题请投票向他们表明我们需要修复它。

于 2014-11-11T08:53:37.873 回答
48

我的解决方案是覆盖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;
        }
    }
}
于 2015-02-24T09:46:46.463 回答
20
mRefreshLayout.getViewTreeObserver()
                .addOnGlobalLayoutListener(
                        new ViewTreeObserver.OnGlobalLayoutListener() {
                            @Override
                            public void onGlobalLayout() {
                                mRefreshLayout
                                        .getViewTreeObserver()
                                        .removeGlobalOnLayoutListener(this);
                                mRefreshLayout.setRefreshing(true);
                            }
                        });
于 2015-01-27T06:18:10.420 回答
14

使用 Android 支持库 24.2.0 应该已经解决了这个问题! https://developer.android.com/topic/libraries/support-library/revisions.html#24-2-0-bugfixes

于 2016-08-18T09:36:44.560 回答
4

根据Volodymyr Baydalka 的回答,这只是一个小想法,可以帮助您保持代码清洁。我相信它值得一篇文章:一旦修复了错误,您将能够轻松地将行为从发布恢复为直接方法调用。

编写一个实用程序类,如:

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

在您的代码替换mSwipeContainer.setRefreshing(isRefreshing)Utils.setRefreshing(mSwipeContainer, isRefreshing):现在,一旦修复了错误,只需更改代码中的一点,即Utils类。然后该方法也可以内联(并从 中删除Utils)。

通常不会有明显的视觉差异。请记住,挂起的刷新可以使您的旧Activity实例保持活动状态,并保留SwipeRefreshLayout在他们的视图层次结构中。如果这是一个问题,请调整方法以使用WeakReferences,但通常您不会阻塞 UI 线程,因此只会将 gc 延迟几毫秒。

于 2015-01-29T14:40:56.427 回答
2

您也可以在 setRefreshing 之前调用此方法。

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

它对我有用。

于 2016-02-05T14:24:25.737 回答
1

我使用了 AppCompat Library com.android.support:appcompat-v7:21.0.3,使用了相同的方法并且它有效。因此,您更新了该库的版本。

建议:RelativeLayout不支持方向,它是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);
}

布局 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>
于 2015-02-17T00:41:16.243 回答
1

除了 Volodymyr Baydalka 之外,还可以使用以下代码:

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

解释 我实现了 Volodymyr Baydalka 给出的解决方案(使用片段),但是在 swipeReferesh 开始之后,即使在调用时它也从未消失,swipeContainer.setRefreshing(false); 因此必须实现上面给出的代码来解决我的问题。任何更多的想法为什么会发生是最受欢迎的。

问候,

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

于 2015-11-01T07:11:02.290 回答
1

@niks.stack 作为对他的回答,我会在onLayout()完成后显示进度轮。当我在之后直接使用它时onMeasure(),它不会尊重某些偏移量,但在之后使用它onLayout()

@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;
    }
}
于 2016-02-28T03:54:38.710 回答
0

我的解决方案(不支持 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);
于 2015-01-06T16:23:55.403 回答
0

我正在使用“com.android.support:appcompat-v7:23.1.1”

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

以前我使用的是swipeRefreshLayout.setRefreshing(true);内部getData()方法,所以它不起作用。我不知道为什么它在内部方法中不起作用。

尽管我swipeRefreshLayout.setRefreshing(true);在 Fragment 中只使用过一次。

于 2016-01-15T15:30:56.617 回答
0

试试这个

mSwipeRefreshLayout.setNestedScrollingEnabled(true);

于 2018-03-21T08:54:11.843 回答
-1

另一种解决方法是从 SwipeRefreshLayout 创建一个新控件和派生程序。如果激活了刷新,则覆盖 OnMeasure 函数并再次切换刷新。我在一个 xamarin 项目中使用了这个解决方案,它运行良好。这里有一些示例 C# 代码:

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;
            }
        }
    }
}
于 2015-01-16T10:46:17.337 回答