ViewPager.java revision a56d6faa9df608aaa2907864669800abb68acec7
1d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/* 2d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project 3d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 4d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * you may not use this file except in compliance with the License. 6d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * You may obtain a copy of the License at 7d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 8d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 10d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 11d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * See the License for the specific language governing permissions and 14d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * limitations under the License. 15d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 16d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpackage android.support.v4.view; 18d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.content.Context; 208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray; 218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver; 22560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas; 23481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect; 24329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable; 255de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build; 2625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.os.Bundle; 27d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel; 28d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable; 2969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock; 305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat; 315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks; 3225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 33560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat; 34d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet; 35d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log; 362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder; 378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity; 382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent; 39d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent; 402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants; 41d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker; 42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View; 43d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration; 44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup; 45218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent; 46481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent; 471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator; 48d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller; 49d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 50d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList; 5166c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections; 5266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator; 53d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 54d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/** 55d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right 565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data. You supply an implementation of a 575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows. 585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * 595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and 605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development. The API will likely change in later updates of 615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code 625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p> 637dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 647dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, 657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page. 667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager, 677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases. These are 687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter}, 697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter}, 707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and 717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these 727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface 737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them. 747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction 767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs. You can find other examples of using 777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java 807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * complete} 81d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 82ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup { 833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private static final String TAG = "ViewPager"; 84d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean DEBUG = false; 85d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean USE_CACHE = false; 87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8829a6184d74279156a9297dc67398712fb047fdc0Adam Powell private static final int DEFAULT_OFFSCREEN_PAGES = 1; 891cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final int MAX_SETTLE_DURATION = 600; // ms 90035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private static final int MIN_DISTANCE_FOR_FLING = 25; // dips 9129a6184d74279156a9297dc67398712fb047fdc0Adam Powell 928f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private static final int DEFAULT_GUTTER_SIZE = 16; // dips 938f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private static final int[] LAYOUT_ATTRS = new int[] { 958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell android.R.attr.layout_gravity 968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell }; 978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 98d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn static class ItemInfo { 99ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Object object; 100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1014c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn boolean scrolling; 102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor; 103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ 10766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham @Override 10866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham public int compare(ItemInfo lhs, ItemInfo rhs) { 10966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham return lhs.position - rhs.position; 110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell }; 11266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 1131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final Interpolator sInterpolator = new Interpolator() { 1141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell public float getInterpolation(float t) { 1151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell t -= 1.0f; 116035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return t * t * t * t * t + 1.0f; 1171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 1181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell }; 1191cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); 121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private final ItemInfo mTempItem = new ItemInfo(); 122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 123ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private PagerAdapter mAdapter; 1243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private int mCurItem; // Index of currently displayed page. 125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mRestoredCurItem = -1; 126ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private Parcelable mRestoredAdapterState = null; 1275c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn private ClassLoader mRestoredClassLoader = null; 128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private Scroller mScroller; 1298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private PagerObserver mObserver; 130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 131329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private int mPageMargin; 132329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private Drawable mMarginDrawable; 1338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mTopPageBounds; 1348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mBottomPageBounds; 135329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Offsets of the first and last items, if known. 137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Set during population, used to determine if we are at the beginning 138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // or end of the pager data set during touch scrolling. 139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mFirstOffset = -Float.MAX_VALUE; 140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mLastOffset = Float.MAX_VALUE; 141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildWidthMeasureSpec; 143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildHeightMeasureSpec; 144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mInLayout; 145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mScrollingCacheEnabled; 147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mPopulatePending; 1494c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn private boolean mScrolling; 15029a6184d74279156a9297dc67398712fb047fdc0Adam Powell private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; 151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsBeingDragged; 153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsUnableToDrag; 1548f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean mIgnoreGutter; 1558f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mDefaultGutterSize; 1568f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mGutterSize; 157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mTouchSlop; 158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mInitialMotionX; 159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Position of the last motion event. 161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionX; 163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionY; 164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ID of the active pointer. This is used to retain consistency during 166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * drags/flings if multiple pointers are used. 167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mActivePointerId = INVALID_POINTER; 169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Sentinel value for no current active pointer. 171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Used by {@link #mActivePointerId}. 172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final int INVALID_POINTER = -1; 174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 175d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Determines speed during touch scrolling 177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private VelocityTracker mVelocityTracker; 179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMinimumVelocity; 180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMaximumVelocity; 181035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int mFlingDistance; 182b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private int mCloseEnough; 183b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell 184b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // If the pager is at least this close to its final position, complete the scroll 185b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // on touch down and let the user interact with the content inside instead of 186b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // "catching" the flinging pager. 187b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private static final int CLOSE_ENOUGH = 2; // dp 188d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private boolean mFakeDragging; 19069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private long mFakeDragBeginTime; 19169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 192560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mLeftEdge; 193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mRightEdge; 194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 19597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell private boolean mFirstLayout = true; 196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private boolean mNeedCalculatePageOffsets = false; 1978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private boolean mCalledSuper; 1988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mDecorChildCount; 19997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 2003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private OnPageChangeListener mOnPageChangeListener; 2018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnPageChangeListener mInternalPageChangeListener; 2028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnAdapterChangeListener mAdapterChangeListener; 2033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 20547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in an idle, settled state. The current page 20647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * is fully in view and no animation is in progress. 20747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 20847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_IDLE = 0; 20947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 21147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is currently being dragged by the user. 21247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 21347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_DRAGGING = 1; 21447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 21647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in the process of settling to a final position. 21747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 21847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_SETTLING = 2; 21947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 22047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private int mScrollState = SCROLL_STATE_IDLE; 22147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 22247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 2233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Callback interface for responding to changing state of the selected page. 2243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public interface OnPageChangeListener { 22647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 2273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * This method will be invoked when the current page is scrolled, either as part 2293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 2303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the first page currently being displayed. 2323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 2333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 2343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffsetPixels Value in pixels indicating the offset from position. 2353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); 2373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 23947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * This method will be invoked when a new page becomes selected. Animation is not 24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * necessarily complete. 2413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the new selected page. 2433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position); 24547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 24647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 24747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Called when the scroll state changes. Useful for discovering when the user 24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * begins dragging, when the pager is automatically settling to the current page, 24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * or when it is fully stopped/idle. 25047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * 25147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @param state The new scroll state. 25247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_IDLE 25347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_DRAGGING 25447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_SETTLING 25547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 25647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state); 2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Simple implementation of the {@link OnPageChangeListener} interface with stub 2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * implementations of each method. Extend this if you do not intend to override 2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * every method of {@link OnPageChangeListener}. 2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public static class SimpleOnPageChangeListener implements OnPageChangeListener { 2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 2673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position) { 2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 27447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell @Override 27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state) { 27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // This space for rent 27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 2793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 2828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Used internally to monitor when adapters are switched. 2838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 2848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell interface OnAdapterChangeListener { 2858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); 2868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2881ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell /** 2891ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * Used internally to tag special types of child views that should be added as 2901ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * pager decorations by default. 2911ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell */ 2921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell interface Decor {} 2931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell 294ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context) { 295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context); 29647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 299ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context, AttributeSet attrs) { 300d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context, attrs); 30147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 302d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 30447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell void initViewPager() { 305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setWillNotDraw(false); 3062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 3072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setFocusable(true); 308560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final Context context = getContext(); 3091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller = new Scroller(context, sInterpolator); 3101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 314560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge = new EdgeEffectCompat(context); 315560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge = new EdgeEffectCompat(context); 3161cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 317035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float density = context.getResources().getDisplayMetrics().density; 318035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); 319b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mCloseEnough = (int) (CLOSE_ENOUGH * density); 3208f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); 32125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 32225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); 32325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 32425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (ViewCompat.getImportantForAccessibility(this) 32525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 32625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setImportantForAccessibility(this, 32725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 32825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 329d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 33147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void setScrollState(int newState) { 33247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mScrollState == newState) { 33347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell return; 33447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 33547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 33647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mScrollState = newState; 33747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mOnPageChangeListener != null) { 33847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageScrollStateChanged(newState); 33947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 34047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 34147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 3428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a PagerAdapter that will supply views for this pager as needed. 3448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 3458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param adapter Adapter to use 3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 347ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public void setAdapter(PagerAdapter adapter) { 3483661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter != null) { 3498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.unregisterDataSetObserver(mObserver); 3500d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.startUpdate(this); 3510d6d2990ddacd3f419879149137f09a30c061436Minh Pham for (int i = 0; i < mItems.size(); i++) { 3520d6d2990ddacd3f419879149137f09a30c061436Minh Pham final ItemInfo ii = mItems.get(i); 3530d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.destroyItem(this, ii.position, ii.object); 3540d6d2990ddacd3f419879149137f09a30c061436Minh Pham } 3550d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.finishUpdate(this); 3560d6d2990ddacd3f419879149137f09a30c061436Minh Pham mItems.clear(); 357a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeNonDecorViews(); 3580d6d2990ddacd3f419879149137f09a30c061436Minh Pham mCurItem = 0; 359871a68b5daafd810623d680207652f87eb2d11ccMinh Pham scrollTo(0, 0); 3603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 3628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final PagerAdapter oldAdapter = mAdapter; 363d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mAdapter = adapter; 364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 3663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mObserver == null) { 3678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mObserver = new PagerObserver(); 3683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.registerDataSetObserver(mObserver); 370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 37191eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell mFirstLayout = true; 372d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mRestoredCurItem >= 0) { 3735c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 374d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mRestoredCurItem, false, true); 375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = -1; 376ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = null; 3775c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = null; 378d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 381d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 3828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 3838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mAdapterChangeListener != null && oldAdapter != adapter) { 3848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 3858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 386d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 388a7aea206661d601755bfac4165092d9130cba2bcAdam Powell private void removeNonDecorViews() { 389a7aea206661d601755bfac4165092d9130cba2bcAdam Powell for (int i = 0; i < getChildCount(); i++) { 390a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final View child = getChildAt(i); 391a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 392a7aea206661d601755bfac4165092d9130cba2bcAdam Powell if (!lp.isDecor) { 393a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeViewAt(i); 394a7aea206661d601755bfac4165092d9130cba2bcAdam Powell i--; 395a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 396a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 397a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 398a7aea206661d601755bfac4165092d9130cba2bcAdam Powell 3998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Retrieve the current adapter supplying pages. 4018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The currently registered PagerAdapter 4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 404ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public PagerAdapter getAdapter() { 405d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mAdapter; 406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 407d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell void setOnAdapterChangeListener(OnAdapterChangeListener listener) { 4098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener = listener; 4108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 4118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 41297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 41397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. If the ViewPager has already been through its first 41491eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * layout with its current adapter there will be a smooth animated transition between 41591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * the current item and the specified item. 41697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 41797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 41897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void setCurrentItem(int item) { 420d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 42197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, !mFirstLayout, false); 42297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell } 42397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 42497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 42597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. 42697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 42797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 42897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately 42997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 43097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell public void setCurrentItem(int item, boolean smoothScroll) { 43197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mPopulatePending = false; 43297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, smoothScroll, false); 433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 435bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki public int getCurrentItem() { 436bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki return mCurItem; 437bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki } 438bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki 439d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { 4401cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(item, smoothScroll, always, 0); 4411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 4421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 4431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { 444d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null || mAdapter.getCount() <= 0) { 445d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 446d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 447d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 448d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!always && mCurItem == item && mItems.size() != 0) { 449d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 450d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (item < 0) { 453d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = 0; 454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else if (item >= mAdapter.getCount()) { 455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = mAdapter.getCount() - 1; 456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 45729a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 45829a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { 4594c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // We are doing a jump by more than one page. To avoid 4604c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // glitches, we want to keep all current pages in the view 4614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // until the scroll ends. 4624c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 4634c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mItems.get(i).scrolling = true; 4644c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 4654c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 46647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final boolean dispatchSelected = mCurItem != item; 467a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(item); 468a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo curInfo = infoForPosition(item); 46931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell int destX = 0; 47031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (curInfo != null) { 47131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int width = getWidth(); 47231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell destX = (int) (width * Math.max(mFirstOffset, 47331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell Math.min(curInfo.offset, mLastOffset))); 47431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 475d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (smoothScroll) { 4761cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(destX, 0, velocity); 47747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 47847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageSelected(item); 47947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 4808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 483d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 48447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 4853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener.onPageSelected(item); 4863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 49047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 491329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell scrollTo(destX, 0); 492d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 493d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 5023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 5033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 505d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 5068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 5078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 5108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 5128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 5138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 5148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 5158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 5168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 5178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 51829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 51929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 52029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 52129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 52229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 52329a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 52429a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 52529a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 52629a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell 52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 52929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 53029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 53129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 53229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 53329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 53429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 53529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 53629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 53729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 53829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 53929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 54029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 54129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 54229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 54329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 54429a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 54529a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 54629a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 54729a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 54829a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 54929a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 55029a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55129a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 55229a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 55329a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 55429a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55529a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55629a6184d74279156a9297dc67398712fb047fdc0Adam Powell 55729a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 558329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 559329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 560329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 561329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 562329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 563329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 564329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 565329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 566329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 567329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 568329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 569329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 570329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 571329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 572329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 573329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 574329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 575329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 576329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 577329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 578329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 579329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 581329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 582329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 583329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 584329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 585329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 586329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 587329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 588329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 589329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 590329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 591329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 592329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 593329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 594329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 595329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 596329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 597329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 598329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 599329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 600329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 601329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 602329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 603329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 604329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 605329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 606329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 607329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 608329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 609329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 610329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 611329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 612329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 613329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 614329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 615329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 616329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 617329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 618329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 6191cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 6201cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 6211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 6221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 6231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 6241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 6251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 6261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 6271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 629329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 632cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 633cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 6361cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 6371cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6381cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6391cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 6401cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 6411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 6421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 6431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 6441cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 6451cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 6461cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 647d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 648d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 649d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 650d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 651d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 652d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 653d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 6543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 6553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 6563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 65747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 65831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 6593040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 6603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 6613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 6623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 6644c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mScrolling = true; 66547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 6661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 667035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int width = getWidth(); 668035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 669035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 670035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 671035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 6721cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 673035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 6741cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 6751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 676035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 6771cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 678a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 679a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 680035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 6811cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 6831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 685b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 686d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 688a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 689d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 6915c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 692a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 693a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 694d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 698a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 7013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 7023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 7033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7041a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 7051a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell mItems.size() < mAdapter.getCount(); 7061e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 7073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7089508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 7093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 7103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 7113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 7123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 7143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 7153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 7183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 7193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 7209508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7219508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 7229508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 7239508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 7249508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7259508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 7273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 7303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 7313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); 7321a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 7333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 7353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 7383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 7393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 7403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 7413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 7443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7489508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 7499508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 7509508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7519508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 75266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 75366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 754a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 765d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 7663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 7673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 770d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 771a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 772a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 773a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 774a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 775a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 776a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 777a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 778a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 779a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 780a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 7903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 794ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 795ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 796ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 797ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 798ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 799ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 800ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 8015c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 80329a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 80429a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 8054c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 80629a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 808a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 809a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 810a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 811a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 812a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 813a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 814a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 816a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 83031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final float leftWidthNeeded = 2.f - curItem.widthFactor; 831a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 83231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 836a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 837a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 8524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 853d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 854d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight >= 2.f && pos > endPos) { 861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 879a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 880d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 883d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8854c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 8864c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 8874c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 8884c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 889d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 891d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 8932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 8945c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 8952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 896a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Check width measurement of current pages. Update LayoutParams as needed. 897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 907a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 908a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 909a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 9102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 9112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 912218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 9132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 9142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 9152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 9162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 9172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 9182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(FOCUS_FORWARD)) { 9192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 9202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 925d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 927a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 9386bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 939a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 948a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 967a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 98331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 98431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 1002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 100331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 100431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 100531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 1006a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 10137dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 10147dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 10157dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 10167dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 10177dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 10187dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1019d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1021ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 10225c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10245c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1027d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 10325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1033d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1035d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1036d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1037d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1041d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10425c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 10435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 10445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 10465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 10475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10495c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 10505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 10515c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10525c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 10535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 10545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1055d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 10565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 10575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1058ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 10595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 10605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 10615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1062d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1066d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1067d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1068d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1069d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1070677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1071677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1072677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1073d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1074d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1075d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1076d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1077d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1078d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1079d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1080d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1081d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1082d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1083d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1084d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1085d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1086d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 10875c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1088d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1089d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1090d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1091ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 10925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1093d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 10978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 10981ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 10991ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 11001ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 11011ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 11021ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 11048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 11058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 11068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1117d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1125ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1132218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1133218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1134218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1135218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1136218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1137218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1138218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1139218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1140218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1141218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1142218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1154ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1155ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 115697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1157ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1158ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1159ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // For simple implementation, or internal size is always 0. 1162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11698f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int measuredWidth = getMeasuredWidth(); 11708f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int maxGutterSize = measuredWidth / 10; 11718f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); 11728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 11748f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); 11758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 11768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 11788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 11798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 11808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 11818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1182862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 11838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 11848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 11858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 11868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 11888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 11898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 11908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 11918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 11928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 11938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 11948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 11968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 11978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 11988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 11998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1207a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1209a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1210a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1211a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1212a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1213a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1214a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 12178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 12188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 12208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 12218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 12228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 12238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1237862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1238d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1239d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1240d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1241d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 12428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 12438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1246a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1248a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 12498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1250d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1251d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1252d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1253d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1254d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1255d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1259053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1260329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1261329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1262329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1263329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1264329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 12655f6568e7e269783e2668527461878cadfbe65215Adam Powell final int widthWithMargin = width + margin; 126691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 1267a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int xpos = getScrollX(); 12685f6568e7e269783e2668527461878cadfbe65215Adam Powell final int oldWidthWithMargin = oldWidth + oldMargin; 12695f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 12705f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1271a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 12725f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1273329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1274329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1275329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1276a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 12775f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 12785f6568e7e269783e2668527461878cadfbe65215Adam Powell (int) (targetInfo.offset * widthWithMargin), 0, newDuration); 1279329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1280329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1281a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 128231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int scrollPos = 12835f6568e7e269783e2668527461878cadfbe65215Adam Powell (int) ((ii != null ? Math.min(ii.offset, mLastOffset) : 0) * widthWithMargin); 1284329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 1285329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell completeScroll(); 1286053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 12879bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1291d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1292d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1293d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1294d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 13018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 13028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 13038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 13048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 13058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1308a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1309a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1310d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 13118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 13128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 13138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 13158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 13348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 13378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 13418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 13438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 13458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 13468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 13478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 13498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 13508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 13518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1354abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1355abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1356abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1357a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1358a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1359a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1360a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1361a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1362a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1363a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1364a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1365a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1366a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1367a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1368a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1369a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int loff = (int) (width * ii.offset); 1370a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1371a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1372a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1373a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1374a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1375a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1376a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1377a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) ((width - paddingLeft - paddingRight) * lp.widthFactor), 1378a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1379a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1380a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1381a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1382a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1383a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 13848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 13858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1387abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1388abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1389abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 13908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 13938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 139697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1397d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1401a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1402a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1403a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 14063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1407a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 14094783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 14104783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 14114783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 14124783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1413d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1416b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 14194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 14204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 142147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 1422d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 14244783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 14254783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 14264783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 14274783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 14284783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 14294783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 14304783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 14314783095cc69fa85e484132337526c94d42d41c43Adam Powell } 14324783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 14334783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1434a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1435a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1436a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1437a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1438a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1439a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1440a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1441a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 14428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1444a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14494783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 14508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 14948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 14978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 15078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 15098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 15108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 151447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void completeScroll() { 1515cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham boolean needPopulate = mScrolling; 1516cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 15174c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 15184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1519d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 152747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_IDLE); 15284c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 15303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mScrolling = false; 15314c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 15324c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 15334c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 15344c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 15354c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 15364c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15374c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 15394c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn populate(); 1540d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1541d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1542d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 15438f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean isGutterDrag(float x, float dx) { 15448f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); 15458f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell } 15468f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1547d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1548d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1549d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1550d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1551d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1555d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1556d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1557d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1558d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1560d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1561d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1562d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 15643ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 15653ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 15663ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 15673ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1569d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1570d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1571d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1573d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1574d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1575d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1576d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1577d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1578d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1579d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1580d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1584d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1585d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1586d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1587d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1588d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1589d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1590d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1591d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1595d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1596d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1597d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1598d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1599d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1600d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1601d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 160347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 160447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 160647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 1607d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1608bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 16098f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && 16108f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell canScroll(this, false, (int) dx, (int) x, (int) y)) { 1611bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 1612bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mInitialMotionX = mLastMotionX = x; 1613bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1614b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1615bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1616bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 1617d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (xDiff > mTouchSlop && xDiff > yDiff) { 1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 162047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 1621d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1622d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 1623d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1624d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (yDiff > mTouchSlop) { 1625d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // The finger has moved enough in the vertical 1626d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // direction to be counted as a drag... abort 1627d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // any attempt to drag horizontally, to work correctly 1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // with children that have scrolling containers. 1629d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 1630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = true; 1631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1638d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1639d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1640d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1641d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1642d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionY = ev.getY(); 1643d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1644b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1645d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1646b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1647b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 164847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 164947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 165047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 165147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 165247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 165347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 165447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1655d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1656d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1657d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1658d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1659d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1660d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1661d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1662d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1663d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1664d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1665d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1666d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16673ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (!mIsBeingDragged) { 16683ce9274ccb8034c1787415c77307bbda36071bddAdam Powell // Track the velocity as long as we aren't dragging. 16693ce9274ccb8034c1787415c77307bbda36071bddAdam Powell // Once we start a real drag we will track in onTouchEvent. 16703ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker == null) { 16713ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = VelocityTracker.obtain(); 16723ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 16733ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.addMovement(ev); 16743ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 16753ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1676d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 16773ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 16783ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 16793ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1682d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1684d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 168569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 168669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 168769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 168869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 168969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 169069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1692d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1693d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1694d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 16993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 17003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 17013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 17023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1703d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1704d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1705d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1706d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1707d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1708d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1709560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1710d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1711d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1712d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1713d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1714d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If being flinged and user touches, stop the fling. isFinished 1715d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * will be false if being flinged. 1716d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 171747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1720d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1721d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1722d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1723d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1724d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 17253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 17263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 17273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 172847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 17293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 173047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 17313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 17323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 17333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 17343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 17353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mLastMotionX = x; 173647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 17373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 17383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 17393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 174031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1742d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1743d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 174647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float deltaX = mLastMotionX - x; 1747d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1748560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float oldScrollX = getScrollX(); 1749560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float scrollX = oldScrollX + deltaX; 17503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int width = getWidth(); 175147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 1752a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 1753a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 1754a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean leftAbsolute = true; 1755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean rightAbsolute = true; 1756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 1758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 1759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 1760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftAbsolute = false; 1761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 1762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 1764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightAbsolute = false; 1765a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 1766a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1767a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 176847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (scrollX < leftBound) { 1769a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (leftAbsolute) { 1770a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float over = leftBound - scrollX; 1771a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 1772560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 177347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollX = leftBound; 177447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else if (scrollX > rightBound) { 1775a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (rightAbsolute) { 1776560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float over = scrollX - rightBound; 1777a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 1778560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 177947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollX = rightBound; 1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 178147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Don't lose the rounded component 178247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mLastMotionX += scrollX - (int) scrollX; 178347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollTo((int) scrollX, getScrollY()); 17848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 17911cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 1794a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 17951cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 1796a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1797a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1798a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 1799035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 1800035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 1801035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 1802035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 1803035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 1804035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 18051cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1809560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1810d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1814d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mCurItem, true, true); 1815d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1816d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1817560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1820d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 1821d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 1822d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 1823d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1824d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 1825d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1826d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1829d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 1830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 1831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1832d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1833560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1834b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1835560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 1840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 1841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 1842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 1843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 1844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 1846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 1848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 1849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 1850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 1851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1852ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 1853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1854a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 1856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 1857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 1858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 1859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 1860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 1861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 1862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 1863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 1865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float leftBound = offset - 0.0001f; 1867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset + 0.0001f; 1868ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 1869ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 1870ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 1871ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 1872ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 1873ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 1876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 1877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 1878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 1879ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 1880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1882ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1884a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1885035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 1886035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 1887035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 1888035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 1889035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 1890035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = (int) (currentPage + pageOffset + 0.5f); 1891035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1892035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1893a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 1894a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 1895a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 1896a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 1898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 1899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1901035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 1902035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1903035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1904560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 1905560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 1906560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 1907560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1908560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1909560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 1910560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 1911560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 1912560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 1913560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 1914560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1915560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1917560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1918560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 1919a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 1920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 1921560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 1922560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1923560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1924560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 1925560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1926560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 1927560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1928560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1929560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 1930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 1931560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 1932560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 1933560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1934560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1935560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 1936560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 1937560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 1938560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1939560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1940560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1941560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 1942b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1943560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1944560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1945560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1946329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 1947329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 1948329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 1949329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 1951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 1952329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 1953329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 1954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 1958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 1959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 1961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 1962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 1963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 1964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 1965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 196723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 1968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 196923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 1970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 1971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 197323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 1974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 1975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 1978a56d6faa9df608aaa2907864669800abb68acec7Adam Powell mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, 197923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 1980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 1981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 1984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 1985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1986329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1987329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1988329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1989329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 199069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 199169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 199269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 199369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 199469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 199569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 199669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 199769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 199869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 199969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 200069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 200169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 200269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 200369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 200469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 200569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 200669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 200769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 200869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 200969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 201069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 201169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 201269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 201369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 201469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 201569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 201669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 201769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 201869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 201969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 202069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 202169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 202269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 202369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 202469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 202569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 202669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 202769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 202869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 202969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 203069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 203169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 203269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 203369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 203469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 203569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 203669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 203769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 203869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 203969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 20400f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 204169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 204269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2043a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2044035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2047a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2048a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2049a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2051035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 205269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 205369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 205469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 205569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 205669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 205769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 205869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 205969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 206069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 206169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 206269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 206369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 206469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 206569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 206669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 206769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 206869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 206969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2070a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2071a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 20720f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 207369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final int width = getWidth(); 207469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2075a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2076a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2077a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2078a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2081a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2082a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2085a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2086a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 208769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 208869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 208969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 209069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 209169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 209269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 209369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 209469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 20958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 209669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 209769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 209869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 209969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 210069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 210169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 210269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 210369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 210469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 210569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 210669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 210769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 210869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 210969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 211069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 211169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 211269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 211369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 211469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 211569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 211669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 211769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2133d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2134d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2135d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2136d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2138d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2139d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2141d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 21573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2158bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2159cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2160bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2161bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2162bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2163bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2164bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2165cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2166bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2167cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2168bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2169cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2170bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2171bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2172bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2173bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2174bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2175bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2176bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2177bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2178bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2179bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2180bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2181bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2182bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2183bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2184bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2185bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2186bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2187bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2188bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2189bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2190bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2191bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2192481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 21932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 21942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 21952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 21962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 21972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 21982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 21992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 22002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 22012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 22022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 22032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 22042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 22052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 22062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 22072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 22082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 22092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 22102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 22112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 22122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 22142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 22152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 22175de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 22185de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 22195de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 22205de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 22215de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 22225de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 22235de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 22245de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 22252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 22332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 22342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused == this) currentFocused = null; 22352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 22372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 22392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 22402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 22412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 22422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 22432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 22442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused != null && nextFocused.getLeft() >= currentFocused.getLeft()) { 22452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 22502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 22512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 22522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) { 22532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 22592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 22602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 22622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 22632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 22662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 22672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 22722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 22732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 22742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 22752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 22772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2280218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 22812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 22822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 22832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 22852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 22882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 22892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 22902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 22912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 22922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 22932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 22952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 22972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 22982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 22992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 23032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 23092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 23102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 23112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 23122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 23132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 23142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 23152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 23162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 23172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 23182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 23192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 23202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 23222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 23232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 23242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 23262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 23272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 23332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 23362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 23372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 23382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 23392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 23402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 23412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 23452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 23522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 23552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 23562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 23572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 23582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 23592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 23602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 23612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 23622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 23632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 23642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 23652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 23662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 23672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 23682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 23702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 23712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(direction, previouslyFocusedRect)) { 23752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 23762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2379481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 23802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2381481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2382481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2383481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2384481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2385481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // ViewPagers should only report accessibility info for the current page, 2386481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // otherwise things get very confusing. 2387481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2388481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // TODO: Should this note something about the paging container? 2389481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2390481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2391481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2392481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2393481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2394481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2395481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2396481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2397481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2398481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2399481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2400481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2401481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2402481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2403481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2404481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 24058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 24078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 24088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 24128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 24138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 24178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 24188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 24221ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 24238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 242525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov class MyAccessibilityDelegate extends AccessibilityDelegateCompat { 242625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 242725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 242825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 242925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityEvent(host, event); 243025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov event.setClassName(ViewPager.class.getName()); 243125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 243225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 243325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 243425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 243525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(host, info); 243625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setClassName(ViewPager.class.getName()); 243725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setScrollable(mAdapter != null && mAdapter.getCount() > 1); 243825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 243925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 244025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 244125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 244225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 244325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 244425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 244525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 244625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 244725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public boolean performAccessibilityAction(View host, int action, Bundle args) { 244825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (super.performAccessibilityAction(host, action, args)) { 244925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 245025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 245125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov switch (action) { 245225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { 245325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 245425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem + 1); 245525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 245625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 245725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 245825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { 245925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 246025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem - 1); 246125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 246225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 246325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 246425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 246525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return false; 246625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 246725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 246825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 24698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 24708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 24728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 24738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 24758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 24763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 24773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 24783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 24798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 24817dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 24827dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 24837dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 24848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 24858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 24868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 24878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 24888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 24898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 24908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2491a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 24923d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 24937dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 24947dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2495a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 24968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 24978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2498a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2499a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2500a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2501a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public float widthFactor = 0.f; 2502a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2503a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2504a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2505a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2506a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2507a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public boolean needsMeasure; 2508a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 25098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 25108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 25118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 25128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 25138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 25148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 25158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 25168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2517a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 25188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 25198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 25208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2522