Created
May 11, 2013 09:13
-
-
Save JimiSmith/5559394 to your computer and use it in GitHub Desktop.
A short example of how to use Chris Banes' Android-PullToRefresh Library with my PinnedHeaderListView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:orientation="vertical" | |
android:layout_width="fill_parent" | |
android:layout_height="fill_parent"> | |
<com.handmark.pulltorefresh.library.PullToRefreshPinnedHeaderListView | |
android:id="@+id/pinnedListView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/white" /> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package za.co.immedia.pinnedheaderlistviewexample; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import com.handmark.pulltorefresh.library.PullToRefreshPinnedHeaderListView; | |
public class MainActivity extends Activity { | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
PullToRefreshPinnedHeaderListView listView = (PullToRefreshPinnedHeaderListView) findViewById(R.id.pinnedListView); | |
TestSectionedAdapter sectionedAdapter = new TestSectionedAdapter(); | |
listView.setAdapter(sectionedAdapter); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
* Copyright 2011, 2012 Chris Banes. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*******************************************************************************/ | |
package com.handmark.pulltorefresh.library; | |
import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Canvas; | |
import android.os.Build.VERSION; | |
import android.os.Build.VERSION_CODES; | |
import android.util.AttributeSet; | |
import android.view.Gravity; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.FrameLayout; | |
import android.widget.ListAdapter; | |
import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor; | |
import com.handmark.pulltorefresh.library.internal.LoadingLayout; | |
import za.co.immedia.pinnedheaderlistview.PinnedHeaderListView; | |
public class PullToRefreshPinnedHeaderListView extends PullToRefreshAdapterViewBase<PinnedHeaderListView> { | |
private LoadingLayout mHeaderLoadingView; | |
private LoadingLayout mFooterLoadingView; | |
private FrameLayout mLvFooterLoadingFrame; | |
private boolean mListViewExtrasEnabled; | |
public PullToRefreshPinnedHeaderListView(Context context) { | |
super(context); | |
} | |
public PullToRefreshPinnedHeaderListView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public PullToRefreshPinnedHeaderListView(Context context, Mode mode) { | |
super(context, mode); | |
} | |
public PullToRefreshPinnedHeaderListView(Context context, Mode mode, AnimationStyle style) { | |
super(context, mode, style); | |
} | |
@Override | |
public final Orientation getPullToRefreshScrollDirection() { | |
return Orientation.VERTICAL; | |
} | |
@Override | |
protected void onRefreshing(final boolean doScroll) { | |
/** | |
* If we're not showing the Refreshing view, or the list is empty, the | |
* the header/footer views won't show so we use the normal method. | |
*/ | |
ListAdapter adapter = mRefreshableView.getAdapter(); | |
if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) { | |
super.onRefreshing(doScroll); | |
return; | |
} | |
super.onRefreshing(false); | |
final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView; | |
final int selection, scrollToY; | |
switch (getCurrentMode()) { | |
case MANUAL_REFRESH_ONLY: | |
case PULL_FROM_END: | |
origLoadingView = getFooterLayout(); | |
listViewLoadingView = mFooterLoadingView; | |
oppositeListViewLoadingView = mHeaderLoadingView; | |
selection = mRefreshableView.getCount() - 1; | |
scrollToY = getScrollY() - getFooterSize(); | |
break; | |
case PULL_FROM_START: | |
default: | |
origLoadingView = getHeaderLayout(); | |
listViewLoadingView = mHeaderLoadingView; | |
oppositeListViewLoadingView = mFooterLoadingView; | |
selection = 0; | |
scrollToY = getScrollY() + getHeaderSize(); | |
break; | |
} | |
// Hide our original Loading View | |
origLoadingView.reset(); | |
origLoadingView.hideAllViews(); | |
// Make sure the opposite end is hidden too | |
oppositeListViewLoadingView.setVisibility(View.GONE); | |
// Show the ListView Loading View and set it to refresh. | |
listViewLoadingView.setVisibility(View.VISIBLE); | |
listViewLoadingView.refreshing(); | |
if (doScroll) { | |
// We need to disable the automatic visibility changes for now | |
disableLoadingLayoutVisibilityChanges(); | |
// We scroll slightly so that the ListView's header/footer is at the | |
// same Y position as our normal header/footer | |
setHeaderScroll(scrollToY); | |
// Make sure the ListView is scrolled to show the loading | |
// header/footer | |
mRefreshableView.setSelection(selection); | |
// Smooth scroll as normal | |
smoothScrollTo(0); | |
} | |
} | |
@Override | |
protected void onReset() { | |
/** | |
* If the extras are not enabled, just call up to super and return. | |
*/ | |
if (!mListViewExtrasEnabled) { | |
super.onReset(); | |
return; | |
} | |
final LoadingLayout originalLoadingLayout, listViewLoadingLayout; | |
final int scrollToHeight, selection; | |
final boolean scrollLvToEdge; | |
switch (getCurrentMode()) { | |
case MANUAL_REFRESH_ONLY: | |
case PULL_FROM_END: | |
originalLoadingLayout = getFooterLayout(); | |
listViewLoadingLayout = mFooterLoadingView; | |
selection = mRefreshableView.getCount() - 1; | |
scrollToHeight = getFooterSize(); | |
scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1; | |
break; | |
case PULL_FROM_START: | |
default: | |
originalLoadingLayout = getHeaderLayout(); | |
listViewLoadingLayout = mHeaderLoadingView; | |
scrollToHeight = -getHeaderSize(); | |
selection = 0; | |
scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1; | |
break; | |
} | |
// If the ListView header loading layout is showing, then we need to | |
// flip so that the original one is showing instead | |
if (listViewLoadingLayout.getVisibility() == View.VISIBLE) { | |
// Set our Original View to Visible | |
originalLoadingLayout.showInvisibleViews(); | |
// Hide the ListView Header/Footer | |
listViewLoadingLayout.setVisibility(View.GONE); | |
/** | |
* Scroll so the View is at the same Y as the ListView | |
* header/footer, but only scroll if: we've pulled to refresh, it's | |
* positioned correctly | |
*/ | |
if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) { | |
mRefreshableView.setSelection(selection); | |
setHeaderScroll(scrollToHeight); | |
} | |
} | |
// Finally, call up to super | |
super.onReset(); | |
} | |
@Override | |
protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) { | |
LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd); | |
if (mListViewExtrasEnabled) { | |
final Mode mode = getMode(); | |
if (includeStart && mode.showHeaderLoadingLayout()) { | |
proxy.addLayout(mHeaderLoadingView); | |
} | |
if (includeEnd && mode.showFooterLoadingLayout()) { | |
proxy.addLayout(mFooterLoadingView); | |
} | |
} | |
return proxy; | |
} | |
protected PinnedHeaderListView createListView(Context context, AttributeSet attrs) { | |
final PinnedHeaderListView lv; | |
if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { | |
lv = new InternalListViewSDK9(context, attrs); | |
} else { | |
lv = new InternalListView(context, attrs); | |
} | |
return lv; | |
} | |
@Override | |
protected PinnedHeaderListView createRefreshableView(Context context, AttributeSet attrs) { | |
PinnedHeaderListView lv = createListView(context, attrs); | |
// Set it to this so it can be used in ListActivity/ListFragment | |
lv.setId(android.R.id.list); | |
return lv; | |
} | |
@Override | |
protected void handleStyledAttributes(TypedArray a) { | |
super.handleStyledAttributes(a); | |
mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true); | |
if (mListViewExtrasEnabled) { | |
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, | |
FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); | |
// Create Loading Views ready for use later | |
FrameLayout frame = new FrameLayout(getContext()); | |
mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a); | |
mHeaderLoadingView.setVisibility(View.GONE); | |
frame.addView(mHeaderLoadingView, lp); | |
mRefreshableView.addHeaderView(frame, null, false); | |
mLvFooterLoadingFrame = new FrameLayout(getContext()); | |
mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a); | |
mFooterLoadingView.setVisibility(View.GONE); | |
mLvFooterLoadingFrame.addView(mFooterLoadingView, lp); | |
/** | |
* If the value for Scrolling While Refreshing hasn't been | |
* explicitly set via XML, enable Scrolling While Refreshing. | |
*/ | |
if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) { | |
setScrollingWhileRefreshingEnabled(true); | |
} | |
} | |
} | |
@TargetApi(9) | |
final class InternalListViewSDK9 extends InternalListView { | |
public InternalListViewSDK9(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
@Override | |
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, | |
int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { | |
final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, | |
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); | |
// Does all of the hard work... | |
OverscrollHelper.overScrollBy(PullToRefreshPinnedHeaderListView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent); | |
return returnValue; | |
} | |
} | |
protected class InternalListView extends PinnedHeaderListView implements EmptyViewMethodAccessor { | |
private boolean mAddedLvFooter = false; | |
public InternalListView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
@Override | |
protected void dispatchDraw(Canvas canvas) { | |
/** | |
* This is a bit hacky, but Samsung's ListView has got a bug in it | |
* when using Header/Footer Views and the list is empty. This masks | |
* the issue so that it doesn't cause an FC. See Issue #66. | |
*/ | |
try { | |
super.dispatchDraw(canvas); | |
} catch (IndexOutOfBoundsException e) { | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public boolean dispatchTouchEvent(MotionEvent ev) { | |
/** | |
* This is a bit hacky, but Samsung's ListView has got a bug in it | |
* when using Header/Footer Views and the list is empty. This masks | |
* the issue so that it doesn't cause an FC. See Issue #66. | |
*/ | |
try { | |
return super.dispatchTouchEvent(ev); | |
} catch (IndexOutOfBoundsException e) { | |
e.printStackTrace(); | |
return false; | |
} | |
} | |
@Override | |
public void setAdapter(ListAdapter adapter) { | |
// Add the Footer View at the last possible moment | |
if (null != mLvFooterLoadingFrame && !mAddedLvFooter) { | |
addFooterView(mLvFooterLoadingFrame, null, false); | |
mAddedLvFooter = true; | |
} | |
super.setAdapter(adapter); | |
} | |
@Override | |
public void setEmptyView(View emptyView) { | |
PullToRefreshPinnedHeaderListView.this.setEmptyView(emptyView); | |
} | |
@Override | |
public void setEmptyViewInternal(View emptyView) { | |
super.setEmptyView(emptyView); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment