怎樣實現SwipeRefreshLayout的自動刷新?類似知乎安卓版一打開頁面就自動刷新載入的效果。
看了幾個回答,都沒有回答到點子上,走了彎路.
先解釋下為什麼setRefreshing沒有作用
public void setRefreshing(boolean refreshing) { if (refreshing mRefreshing != refreshing) {// scale and show
mRefreshing = refreshing; int endTarget = 0; if (!mUsingCustomStart) { endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop); } else { endTarget = (int) mSpinnerFinalOffset; } setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop, true /* requires update */);mNotify = false;
startScaleUpAnimation(mRefreshListener); } else { setRefreshing(refreshing, false /* notify */); } } 在onCreate里或onCreateView里調用setRefreshing,這個時候關鍵變數mOriginalOffsetTop並沒有獲取正確的值。下拉效果動畫過程中沒有顯示到正確的坐標,我們看看這個值是什麼時候獲取的,上代碼 @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (mTarget == null) {
ensureTarget(); } if (mTarget == null) { return; } mTarget.measure(MeasureSpec.makeMeasureSpec( getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mCircleHeight, MeasureSpec.EXACTLY)); if (!mUsingCustomStart !mOriginalOffsetCalculated) { mOriginalOffsetCalculated = true;mCurrentTargetOffsetTop = mOriginalOffsetTop = -mCircleView.getMeasuredHeight(); } mCircleViewIndex = -1; // Get the index of the circleview. for (int index = 0; index &< getChildCount(); index++) {if (getChildAt(index) == mCircleView) {
mCircleViewIndex = index; break; } } } 如代碼所見,是在onMeasure里獲取的,根據CircleView的高度來賦值的。所以要解決的方法是讓mOriginalOffsetTop能在setRefreshing前正確賦值。比較笨的方法是在onCreate里或onCreateView手動賦值,不推薦。
正確做法是在onMeasure觸發後再調用setRefreshing。代碼如下:root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override public void onGlobalLayout() { root.getViewTreeObserver().removeGlobalOnLayoutListener(this); mRefreshLayout.setRefreshing(true); loadData(true); } }); 其它的下拉刷新庫也有類似問題,關鍵變數需要在onMeasure里獲取。也無法顯示到正確的位置。類似其它自定義控制項需要在控制項沒有度量好,先調用涉及到相關變數的方法,都可以類似解決。回家寫 mark
2015-9-7 20:40 更新
首先想要在界面一載入的時候出現更新效果,直接調用setRfreshing(true)是出不來效果的,這個問題我以前也遇到過,必須調用 SwipeRefreshLayout.post(new Runable(){ @Override public void run() { SwipeRefreshLayout.setRefreshing(true); }});關閉的時候也使用
SwipeRefreshLayout.post(new Runable(){@Override
public void run() { SwipeRefreshLayout.setRefreshing(false); }});但是如果你認為這樣就會走onRefresh方法,那你就大錯特錯了,setRefreshing(true)是不會觸發onRefresh的,必須要手動調用一次所以在界面onCreate裡面想要立刻載入就需要這樣SwipeRefreshLayout.post(new Runable(){
@Override public void run() {SwipeRefreshLayout.setRefreshing(true);
}});onRefresh();2015-9-7 21:55 更新初始化:OnRefreshListener listener = new OnRefreshListener(){
public void onRefresh(){
//TODO
}
};
SwipeRefreshLayout mSRLayout = (SwipeRefreshLayout) findviewbyId(R.id.layout);
mSRLayout.setOnRefreshListener(listener);
onCreate中:
mSRLayout.post(new Runable(){
@Override
public void run() {
SwipeRefreshLayout.setRefreshing(true);
}
});
listener.onRefresh()
謝邀。本來在onCreate裡面調用SwipeRefreshLayout.setRefreshing(ture,true)即可,但是,這個Api是私有的。所以只能用反射或者手動調SwipeRefreshLayout.setRefreshing(true)+RefreshLayout.OnRefreshListener.onRefresh方法。反射代碼如下:
public static void setRefreshing(SwipeRefreshLayout refreshLayout,boolean refreshing, boolean notify){
Class& extends SwipeRefreshLayout&> refreshLayoutClass = refreshLayout.getClass();
if (refreshLayoutClass != null) {
try {
Method setRefreshing = refreshLayoutClass.getDeclaredMethod("setRefreshing", boolean.class, boolean.class);
setRefreshing.setAccessible(true);
setRefreshing.invoke(refreshLayout, refreshing, notify);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
然後調用setRefreshing(mRefreshLayout,true,true)即可。
反射請在Proguard裡面屏蔽掉setRefreshing,代碼如下 -keepclassmembers android.support.v4.widget.SwipeRefreshLayout{
private void setRefreshing(boolean,boolean);
}
以上兩種方法注意進行延時(應該算是一個bug吧https://code.google.com/p/android/issues/detail?id=77712),參考 @賈藝馳 提供的方式 怎樣實現SwipeRefreshLayout的自動刷新?類似知乎安卓版一打開頁面就自動刷新載入的效果。 - 賈藝馳的回答。
知乎會自動緩存第一頁HTTP數據,每次打開時會把緩存先展示出來,然後再去介面請求數據,同時設置SwipeRefreshLayout的自動刷新,數據到了,把緩存替換掉,同時設置SwipeRefreshLayout.setRefreshing(false)。SwipeRefreshLayout 不刷新的主要原因是onCreate中控制項還沒有初始化,直接使用,這個等同於Handler的,他會在View初始化完成後調用Runable的東西
swipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(true);
}
});
SwipeRefreshLayout.setRefreshing(true);
我在handler中調用這個方法無效,然後在子線程調用就崩了。何解啊?
能問一下,為什麼在刷新的回調中,請求網路數據,會引起界面的重繪呢?
我以前寫過的程序是這樣實現的,就是在onCreate函數末尾放入這句
new Handler().postDelayed(new Runnable() {
if(!offline()) {
mRefreshIndicator.setRefreshing(true);
}
}, 500); //延遲500ms執行
也可以試著這麼做一下,就是重載Activity的onWindowFocusChanged(boolean hasFocus)方法。不過我沒試過,我覺得應該也可以。
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus) {
if(!offline()) {
mRefreshIndicator.setRefreshing(true);
}
}
}
直接調用onRefresh();就可以了
推薦閱讀:
※初使用 Android Studio ,體驗是不是很不好?
※學習軟體編程應該從哪裡學起?
※網易雲音樂 Android 客戶端底部的播放欄是怎麼做到在各個頁面存在的?
※Swift(相關構架) vs Xamarin, 那個會成為真正的廣泛接受的跨平台開發構架?
※如何理解android mvp模式中的interactor?