SwipeRefreshLayout setRefreshing() не показывает индикатор первоначально

У меня очень простой макет, но когда я вызываю 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
    }
}

Ответ 1

Столкнулся с той же проблемой. Мое решение -

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

Ответ 2

Вместо этого ответьте на запрос Владимира Байдалки.

Это старые обходные пути.

Это использовалось для более ранней версии android.support.v4, но из версии 21.0.0 она не работает и все еще существует с android.support.v4:21.0.3, выпущенной в 10-12 декабря 2014 года и это причина.

Индикатор SwipeRefreshLayout не появляется, когда setRefreshing(true) вызывается перед SwipeRefreshLayout.onMeasure()

Обход проблемы:

вызывая setProgressViewOffset() на SwipeRefreshLayout, который отменяет кругное представление макета, вызывающее немедленное вызов SwipeRefreshLayout.onMeasure().

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

ОБНОВЛЕНИЕ Улучшение обходного пути

Потому что панель действий может стать тоньше при изменении ориентации или вручную задать размер панели действий. Мы устанавливаем смещение в пикселях от вершины этого представления, при котором счетчик прогресса должен прибыть в reset после успешного жестового перехода к текущему размеру панели действий.

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

ОБНОВЛЕНИЕ 20 ноября 2014 года

Если вам не очень важно, чтобы ваше приложение отображало SwipeRefreshLayout после запуска представления. Вы можете просто опубликовать его в любое время в будущем, используя обработчики или любую вещь, которую вы хотите.

в качестве примера.

handler.postDelayed(new Runnable() {

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

или как упоминалось в ответе Владимира Байдалки.

Вот issue в трекере по проблеме проблем с Android. Пожалуйста, поддержите его, чтобы показать им, что нам нужно, чтобы это было исправлено.

Ответ 3

Мое решение - переопределить 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);
                            }
                        });

Ответ 6

Основываясь на ответе Владимира Байдалки, это всего лишь небольшая идея, которая поможет вам сохранить код чистым. Он заслуживает того, что я верю: вы сможете легко отменить поведение при отправке на прямой вызов метода после исправления ошибки.

Напишите класс утилиты, например:

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 в своих иерархиях представлений. Если это вызывает беспокойство, настройте метод на использование WeakReference s, но обычно вы не блокируете поток пользовательского интерфейса в любом случае и, таким образом, задерживаете gc только на пару миллисекунд.

Ответ 7

Также вы можете вызвать этот метод до setRefreshing..

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

Это работает для меня.

Ответ 8

Я использовал 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>

Ответ 9

В дополнение к Владимиру Байдалке также используйте следующий код:

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

Объяснение Я реализовал решение, данное Владимиром Байдалкой (используя фрагменты), но после того, как swipeReferesh запустил его, он никогда не исчезал даже при вызове swipeContainer.setRefreshing(false); поэтому пришлось реализовать приведенный выше код, который решил мою проблему. больше идей, почему это происходит, приветствуются.

Привет,

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

Ответ 10

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

Ответ 11

Мое решение (без поддержки 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();
        }
    });

ранее я использовал swipeRefreshLayout.setRefreshing(true); внутри getData(), поэтому он не работал. Я не знаю, почему его не работает внутри метода.

Хотя я использовал swipeRefreshLayout.setRefreshing(true); только один раз в своем фрагменте.

Ответ 13

Другим обходным решением является создание нового элемента управления и создание из SwipeRefreshLayout. Переопределите функцию OnMeasure и снова включите обновление, если обновление активировано. Я использую это решение в проекте xamarin, и он работает хорошо. Здесь пример С# -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;
            }
        }
    }
}