SwipeRefreshLayout setRefreshing ()이 처음에 표시기를 표시하지 않음


144

나는 아주 간단한 레이아웃을 가지고 있지만 내가 전화 할 때 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
    }
}

어떤 버전을 사용하십니까?
Ahmed Hegazy

"com.android.support:appcompat-v7:21.0.0"컴파일
thunderousNinja

이 버전에서이 문제가 계속 발생했음을 확인합니다. 이전 버전에는 아무런 문제가 없습니다. 내가 얻는다면 해결책을 게시 할 것입니다.
Ahmed Hegazy

나 이전 버전을 해보자
thunderousNinja

또한 v20에서 작동하지 않습니다. 어떤 버전으로 작동합니까?
thunderousNinja

답변:


307

같은 문제에 직면했다. 내 솔루션-

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

1
잘 작동하지만 왜 우리가 mSwipeRefreshLayout.setRefreshing (true) 대신에 이것을 해야하는지 모르겠습니다.
Cocorico


1
사용자가 비행기 모드 인 경우 refreshLayout은 이미 네트워크 요청을 시작하고 응답을받은 후 자체 스레드에서 새로 고침을 시작합니다 (이 경우 실패). refreshLayout을 중지하기 위해 처리 할 때 아직 시작되지 않았으므로 작동하지 않습니다! 다시 말해, refreshLayout은 응답을받은 후 새로 고침을 시작합니다. 행운을 빕니다
Samer

1
내가 기억하는 것처럼 "게시물"은 동기화되어 추가 순서대로 실행됩니다. 따라서 다른 게시물을 추가하여 중지 할 수 있습니다.
Volodymyr Baydalka

2
아마도 구현에서 가장 단순 해 보이지만 좋지 않습니다. 아래의 @ niks.stack 솔루션 은 그것을 사용하는 코드를 변경할 필요가 없으므로 더 좋습니다. 따라서이 버그가 지원 lib에서 수정되면 lib SwipeRefreshLayout
Marcin Orlowski의

100

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원인이 레이아웃의 원보기를 invalidtes이가 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의 답변이 언급했듯이.

여기입니다 문제 안드로이드 이슈 트래커한다. 수정이 필요하다는 것을 보여주기 위해 투표하십시오.


당신은 많은 테스트를 했습니까 delay time? 에 사용 500하고 Galaxy S4있습니다. 다른 장치에서 문제가 될지 확실하지 않습니다.
theblang

나는 지연 시간에 많은 테스트를하지 않았다, 그러나 나는 생각 500켜기를 테스트 한 괜찮아요을 할 것입니다 emulator단지가되고 싶어 .I safe1000밀리 초
아흐메드 헤 가지

3
지연 게시 할 필요가 없습니다. 당신은 게시 할 수 있습니다. 지체없이 게시한다는 것은 "지금하고있는 작업을 마치면이 작업을 수행"을 의미합니다. 현재하고있는 일은 UI를 측정하고 배치하는 것입니다.
Oren

47

내 해결책은 다음을 무시하는 것입니다 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;
        }
    }
}

3
솔루션의 장점은 뷰 오프셋을 그대로 유지하는 것입니다! 이런 식으로 google.com/design/spec/patterns/…에 지정된 디자인 패턴을 계속 준수합니다 . 감사!
Igor de Lorenzi

이것이 어떻게 작동하는지 설명해 주시겠습니까? 작동하지만 내부 작업을 제대로 얻지 못합니다. 내가 사소한 것을 놓치고 있습니까?
Sree

setRefreshing은 onMeasure 호출 후에 만 ​​작동하므로 로컬 새로 고침 플래그를 저장하고 첫 번째 onMeasure 호출에 적용
nikita.zhelonkin

5
이 솔루션은 SwipeRefreshLayout을 호출하는 코드가 합병증없이 원하는대로 정확하게 될 수 있기 때문에이 솔루션을 좋아합니다. 기본적으로 SwipeRefreshLayout의 버그가 수정되었습니다. SwipeRefreshLayout은 실제로이 방법으로 구현해야합니다.
DataGraham

이 답변은 그렇게 간단하지는 않지만 많은 지원 라이브러리 버전 (제 경우에는 23.1.1)을 통해 문제를 잘 해결합니다. 티켓에 따르면이 문제는 23.2에서 수정되지 않았습니다. code.google.com/p/android/issues/detail?id=77712
Robert

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

3
이 답변은 해킹이 아닌 유일한 답변이므로 수락해야합니다.
Heinrich

1
작은 것 : .removeGlobalOnLayoutListener는 .removeOnGlobalLayoutListener 여야합니다
mkuech

1
@mkeuch는 타겟팅하는 API에 따라 다릅니다. API16에서 타겟팅하는 경우 API 버전 확인을 수행하고 두 가지를 모두 사용해야합니다.
Marko

나는 이것이 사용 된 이유가 더 분명하기 때문에 가장 많이 찬성 된 답변보다 조금 더 좋아합니다.
Marcel Bro

나는 나 자신을 바로 잡아야한다.이 해결책이 항상 나를 위해 일하는 것은 아니다. 경우에 따라 setRefreshing(false)래핑 된 통화 onGlobalLayoutListener()는로드 표시기 를 해제 하지 않습니다.
Marcel Bro


4

를 기반으로 볼로디미르 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를 몇 밀리 초만 지연시킵니다.


2

setRefreshing 전에이 메소드를 호출 할 수도 있습니다.

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

그것은 나를 위해 작동합니다.


1

나는 com.android.support:appcompat-v7:21.0.3동일한 접근법을 사용하여 AppCompat Library 를 사용했으며 효과가있었습니다. 따라서 해당 라이브러리의 버전을 업데이트하십시오.

조언 : 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>

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'


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

onMeasure 후 좋은 콜백을 찾고있었습니다! Thnx. 초기 실행시 오프셋이 해제되었다는 사실을 귀찮게하고있었습니다.
xdbas

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

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);내 조각에서 한 번만 사용했지만 .



-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;
            }
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.