Code example for Scroller

Methods: computeScrollOffset, getCurrX, getCurrY, startScroll

0
		invalidate();
	} 
 
	@Override 
	public void computeScroll() { 
		if (mScroller.computeScrollOffset()) {
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		} else if (mNextScreen != INVALID_SCREEN) {
			mCurrentScreen = Math.max(0,
					Math.min(mNextScreen, getChildCount() - 1));
			mNextScreen = INVALID_SCREEN;
			postViewSwitched(mLastScrollDirection);
		} 
	} 
 
	/** 
	 * Scroll to the {@link View} in the view buffer specified by the index. 
	 *  
	 * @param indexInBuffer 
	 *            Index of the view in the view buffer. 
	 */ 
	private void setVisibleView(int indexInBuffer, boolean uiThread) {
		mCurrentScreen = Math.max(0,
				Math.min(indexInBuffer, getChildCount() - 1));
		int dx = (mCurrentScreen * getWidth()) - mScroller.getCurrX();
		mScroller.startScroll(mScroller.getCurrX(), mScroller.getCurrY(), dx,
				0, 0); 
		if(dx == 0)
			onScrollChanged(mScroller.getCurrX() + dx, mScroller.getCurrY(), mScroller.getCurrX() + dx, mScroller.getCurrY());
		if (uiThread)
			invalidate();
		else 
			postInvalidate();
	} 
 
	/** 
	 * Set the listener that will receive notifications every time the {code 
	 * ViewFlow} scrolls. 
	 *  
	 * @param l 
	 *            the scroll listener 
	 */ 
	public void setOnViewSwitchListener(ViewSwitchListener l) {
		mViewSwitchListener = l;
	} 
 
	@Override 
	public Adapter getAdapter() {
		return mAdapter;
	} 
 
	@Override 
	public void setAdapter(Adapter adapter) {
		setAdapter(adapter, 0);
	} 
	 
	public void setAdapter(Adapter adapter, int initialPosition) {
		if (mAdapter != null) {
			mAdapter.unregisterDataSetObserver(mDataSetObserver);
		} 
 
		mAdapter = adapter;
 
		if (mAdapter != null) {
			mDataSetObserver = new AdapterDataSetObserver();
			mAdapter.registerDataSetObserver(mDataSetObserver);
 
		} 
		if (mAdapter == null || mAdapter.getCount() == 0)
			return; 
		 
		setSelection(initialPosition);		
	} 
	 
	@Override 
	public View getSelectedView() {
		return (mCurrentBufferIndex < mLoadedViews.size() ? mLoadedViews
				.get(mCurrentBufferIndex) : null);
	} 
 
    @Override 
    public int getSelectedItemPosition() { 
        return mCurrentAdapterIndex;
    } 
 
	/** 
	 * Set the FlowIndicator 
	 *  
	 * @param flowIndicator 
	 */ 
	public void setFlowIndicator(FlowIndicator flowIndicator) {
		mIndicator = flowIndicator;
		mIndicator.setViewFlow(this);
	} 
 
	@Override 
	public void setSelection(int position) {
		mNextScreen = INVALID_SCREEN;
		mScroller.forceFinished(true);
		if (mAdapter == null)
			return; 
		 
		position = Math.max(position, 0);
		position =  Math.min(position, mAdapter.getCount()-1);
 
		ArrayList<View> recycleViews = new ArrayList<View>();
		View recycleView;
		while (!mLoadedViews.isEmpty()) {
			recycleViews.add(recycleView = mLoadedViews.remove());
			detachViewFromParent(recycleView);
		} 
 
		View currentView = makeAndAddView(position, true,
				(recycleViews.isEmpty() ? null : recycleViews.remove(0)));
		mLoadedViews.addLast(currentView);
		 
		for(int offset = 1; mSideBuffer - offset >= 0; offset++) {
			int leftIndex = position - offset;
			int rightIndex = position + offset;
			if(leftIndex >= 0)
				mLoadedViews.addFirst(makeAndAddView(leftIndex, false,
						(recycleViews.isEmpty() ? null : recycleViews.remove(0))));
			if(rightIndex < mAdapter.getCount())
				mLoadedViews.addLast(makeAndAddView(rightIndex, true,
						(recycleViews.isEmpty() ? null : recycleViews.remove(0))));
		} 
 
		mCurrentBufferIndex = mLoadedViews.indexOf(currentView);
		mCurrentAdapterIndex = position;
 
		for (View view : recycleViews) {
			removeDetachedView(view, false);
		} 
		requestLayout();
		setVisibleView(mCurrentBufferIndex, false);
		if (mIndicator != null) {
			mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex),
					mCurrentAdapterIndex);
		} 
		if (mViewSwitchListener != null) {
			mViewSwitchListener
					.onSwitched(mLoadedViews.get(mCurrentBufferIndex),
							mCurrentAdapterIndex);
		} 
	} 
 
	private void resetFocus() { 
		logBuffer(); 
		mLoadedViews.clear();
		removeAllViewsInLayout();
 
		for (int i = Math.max(0, mCurrentAdapterIndex - mSideBuffer); i < Math
				.min(mAdapter.getCount(), mCurrentAdapterIndex + mSideBuffer
						+ 1); i++) {
			mLoadedViews.addLast(makeAndAddView(i, true, null));
			if (i == mCurrentAdapterIndex)
				mCurrentBufferIndex = mLoadedViews.size() - 1;
		} 
		logBuffer(); 
		requestLayout();
	} 
 
	private void postViewSwitched(int direction) {
		if (direction == 0)
			return; 
 
		if (direction > 0) { // to the right
			mCurrentAdapterIndex++;
			mCurrentBufferIndex++;
 
			View recycleView = null;
 
			// Remove view outside buffer range 
			if (mCurrentAdapterIndex > mSideBuffer) {
				recycleView = mLoadedViews.removeFirst();
				detachViewFromParent(recycleView);
				// removeView(recycleView); 
				mCurrentBufferIndex--;
			} 
 
			// Add new view to buffer 
			int newBufferIndex = mCurrentAdapterIndex + mSideBuffer;
			if (newBufferIndex < mAdapter.getCount())
				mLoadedViews.addLast(makeAndAddView(newBufferIndex, true,
						recycleView));
 
		} else { // to the left 
			mCurrentAdapterIndex--;
			mCurrentBufferIndex--;
			View recycleView = null;
 
			// Remove view outside buffer range 
			if (mAdapter.getCount() - 1 - mCurrentAdapterIndex > mSideBuffer) {
				recycleView = mLoadedViews.removeLast();
				detachViewFromParent(recycleView);
			} 
 
			// Add new view to buffer 
			int newBufferIndex = mCurrentAdapterIndex - mSideBuffer;
			if (newBufferIndex > -1) {
				mLoadedViews.addFirst(makeAndAddView(newBufferIndex, false,
						recycleView));
				mCurrentBufferIndex++;
			} 
 
		} 
 
		requestLayout();
		setVisibleView(mCurrentBufferIndex, true);
		if (mIndicator != null) {
			mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex),
					mCurrentAdapterIndex);
		} 
		if (mViewSwitchListener != null) {
			mViewSwitchListener
					.onSwitched(mLoadedViews.get(mCurrentBufferIndex),
							mCurrentAdapterIndex);
		} 
		logBuffer(); 
	} 
 
	private View setupChild(View child, boolean addToEnd, boolean recycle) {
		ViewGroup.LayoutParams p = (ViewGroup.LayoutParams) child
				.getLayoutParams();
		if (p == null) {
			p = new AbsListView.LayoutParams(
					ViewGroup.LayoutParams.FILL_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT, 0);
		} 
		if (recycle)
			attachViewToParent(child, (addToEnd ? -1 : 0), p);
		else 
			addViewInLayout(child, (addToEnd ? -1 : 0), p, true);
		return child;
	} 
 
	private View makeAndAddView(int position, boolean addToEnd, View convertView) {
		View view = mAdapter.getView(position, convertView, this);
		return setupChild(view, addToEnd, convertView != null);
	} 
 
	class AdapterDataSetObserver extends DataSetObserver {
 
		@Override 
		public void onChanged() { 
			View v = getChildAt(mCurrentBufferIndex);
			if (v != null) {
				for (int index = 0; index < mAdapter.getCount(); index++) {
					if (v.equals(mAdapter.getItem(index))) {
						mCurrentAdapterIndex = index;
						break; 
					} 
				} 
			} 
			resetFocus(); 
		} 
 
		@Override 
		public void onInvalidated() { 
			// Not yet implemented! 
		} 
 
	} 
 
	private void logBuffer() { 
 
		Log.d("viewflow", "Size of mLoadedViews: " + mLoadedViews.size() +
				"X: " + mScroller.getCurrX() + ", Y: " + mScroller.getCurrY());
		Log.d("viewflow", "IndexInAdapter: " + mCurrentAdapterIndex
				+ ", IndexInBuffer: " + mCurrentBufferIndex);
	} 
}