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; 3564f49357df06a29f989f688379451024a178bcd8Adam Powellimport android.util.FloatMath; 36d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log; 372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder; 388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity; 392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent; 40d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent; 412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants; 42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker; 43d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View; 44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration; 45d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup; 46218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent; 47481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent; 481cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator; 49d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller; 50d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 518a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powellimport java.lang.reflect.Method; 52d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList; 5366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections; 5466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator; 55d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 56d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/** 57d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right 585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data. You supply an implementation of a 595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows. 605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * 615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and 625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development. The API will likely change in later updates of 635c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code 645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p> 657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, 677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page. 687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager, 697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases. These are 707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter}, 717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter}, 727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and 737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these 747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface 757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them. 767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction 787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs. You can find other examples of using 797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 817dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java 827dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * complete} 83d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 84ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup { 853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private static final String TAG = "ViewPager"; 86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean DEBUG = false; 87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 88d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean USE_CACHE = false; 89d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 9029a6184d74279156a9297dc67398712fb047fdc0Adam Powell private static final int DEFAULT_OFFSCREEN_PAGES = 1; 911cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final int MAX_SETTLE_DURATION = 600; // ms 92035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private static final int MIN_DISTANCE_FOR_FLING = 25; // dips 9329a6184d74279156a9297dc67398712fb047fdc0Adam Powell 948f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private static final int DEFAULT_GUTTER_SIZE = 16; // dips 958f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 9616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private static final int MIN_FLING_VELOCITY = 400; // dips 9716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell 988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private static final int[] LAYOUT_ATTRS = new int[] { 998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell android.R.attr.layout_gravity 1008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell }; 1018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn static class ItemInfo { 103ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Object object; 104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1054c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn boolean scrolling; 106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor; 107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11066c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ 11166c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham @Override 11266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham public int compare(ItemInfo lhs, ItemInfo rhs) { 11366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham return lhs.position - rhs.position; 114a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 115a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell }; 11666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 1171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final Interpolator sInterpolator = new Interpolator() { 1181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell public float getInterpolation(float t) { 1191cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell t -= 1.0f; 120035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return t * t * t * t * t + 1.0f; 1211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 1221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell }; 1231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); 125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private final ItemInfo mTempItem = new ItemInfo(); 126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 127dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private final Rect mTempRect = new Rect(); 128dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 129ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private PagerAdapter mAdapter; 1303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private int mCurItem; // Index of currently displayed page. 131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mRestoredCurItem = -1; 132ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private Parcelable mRestoredAdapterState = null; 1335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn private ClassLoader mRestoredClassLoader = null; 134d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private Scroller mScroller; 1358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private PagerObserver mObserver; 136d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 137329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private int mPageMargin; 138329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private Drawable mMarginDrawable; 1398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mTopPageBounds; 1408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mBottomPageBounds; 141329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Offsets of the first and last items, if known. 143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Set during population, used to determine if we are at the beginning 144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // or end of the pager data set during touch scrolling. 145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mFirstOffset = -Float.MAX_VALUE; 146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mLastOffset = Float.MAX_VALUE; 147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildWidthMeasureSpec; 149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildHeightMeasureSpec; 150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mInLayout; 151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mScrollingCacheEnabled; 153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mPopulatePending; 15529a6184d74279156a9297dc67398712fb047fdc0Adam Powell private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; 156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsBeingDragged; 158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsUnableToDrag; 1598f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean mIgnoreGutter; 1608f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mDefaultGutterSize; 1618f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mGutterSize; 162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mTouchSlop; 163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Position of the last motion event. 165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionX; 167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionY; 16816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private float mInitialMotionX; 16916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private float mInitialMotionY; 170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ID of the active pointer. This is used to retain consistency during 172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * drags/flings if multiple pointers are used. 173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mActivePointerId = INVALID_POINTER; 175d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Sentinel value for no current active pointer. 177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Used by {@link #mActivePointerId}. 178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final int INVALID_POINTER = -1; 180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 182d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Determines speed during touch scrolling 183d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 184d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private VelocityTracker mVelocityTracker; 185d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMinimumVelocity; 186d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMaximumVelocity; 187035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int mFlingDistance; 188b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private int mCloseEnough; 189b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell 190b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // If the pager is at least this close to its final position, complete the scroll 191b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // on touch down and let the user interact with the content inside instead of 192b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // "catching" the flinging pager. 193b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private static final int CLOSE_ENOUGH = 2; // dp 194d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private boolean mFakeDragging; 19669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private long mFakeDragBeginTime; 19769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 198560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mLeftEdge; 199560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mRightEdge; 200560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 20197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell private boolean mFirstLayout = true; 202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private boolean mNeedCalculatePageOffsets = false; 2038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private boolean mCalledSuper; 2048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mDecorChildCount; 20597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 2063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private OnPageChangeListener mOnPageChangeListener; 2078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnPageChangeListener mInternalPageChangeListener; 2088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnAdapterChangeListener mAdapterChangeListener; 2098a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private PageTransformer mPageTransformer; 2108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private Method mSetChildrenDrawingOrderEnabled; 2113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2127e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_DEFAULT = 0; 2137e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_FORWARD = 1; 2147e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_REVERSE = 2; 2157e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private int mDrawingOrder; 2167e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private ArrayList<View> mDrawingOrderedChildren; 2177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); 2187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 2193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 22047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in an idle, settled state. The current page 22147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * is fully in view and no animation is in progress. 22247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 22347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_IDLE = 0; 22447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 22547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 22647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is currently being dragged by the user. 22747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 22847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_DRAGGING = 1; 22947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 23047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 23147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in the process of settling to a final position. 23247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 23347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_SETTLING = 2; 23447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 23571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio private final Runnable mEndScrollRunnable = new Runnable() { 23671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio public void run() { 23771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio setScrollState(SCROLL_STATE_IDLE); 23871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio populate(); 23971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 24071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio }; 24171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio 24247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private int mScrollState = SCROLL_STATE_IDLE; 24347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 24447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 2453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Callback interface for responding to changing state of the selected page. 2463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public interface OnPageChangeListener { 24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 2493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * This method will be invoked when the current page is scrolled, either as part 2513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 2523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the first page currently being displayed. 2543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 2553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 2563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffsetPixels Value in pixels indicating the offset from position. 2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); 2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 26147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * This method will be invoked when a new page becomes selected. Animation is not 26247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * necessarily complete. 2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the new selected page. 2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position); 26747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 26847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 26947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Called when the scroll state changes. Useful for discovering when the user 27047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * begins dragging, when the pager is automatically settling to the current page, 27147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * or when it is fully stopped/idle. 27247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * 27347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @param state The new scroll state. 27447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_IDLE 27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_DRAGGING 27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_SETTLING 27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state); 2793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2823661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Simple implementation of the {@link OnPageChangeListener} interface with stub 2833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * implementations of each method. Extend this if you do not intend to override 2843661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * every method of {@link OnPageChangeListener}. 2853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public static class SimpleOnPageChangeListener implements OnPageChangeListener { 2873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 2893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position) { 2943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 29647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 29747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell @Override 29847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state) { 29947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // This space for rent 30047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 3013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 3038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3048a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * A PageTransformer is invoked whenever a visible/attached page is scrolled. 3058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * This offers an opportunity for the application to apply a custom transformation 3068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * to the page views using animation properties. 3078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 3088a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * <p>As property animation is only supported as of Android 3.0 and forward, 3098a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * setting a PageTransformer on a ViewPager on earlier platform versions will 3108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * be ignored.</p> 3118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 3128a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public interface PageTransformer { 3138a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 3148a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * Apply a property transformation to the given page. 3158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 3168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param page Apply the transformation to this page 3178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param position Position of page relative to the current front-and-center 3188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * position of the pager. 0 is front and center. 1 is one full 3198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * page position to the right, and -1 is one page position to the left. 3208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 3218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public void transformPage(View page, float position); 3228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 3238a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 3248a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 3258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Used internally to monitor when adapters are switched. 3268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 3278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell interface OnAdapterChangeListener { 3288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); 3298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 3308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 3311ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell /** 3321ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * Used internally to tag special types of child views that should be added as 3331ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * pager decorations by default. 3341ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell */ 3351ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell interface Decor {} 3361ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell 337ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context) { 338d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context); 33947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 340d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 341d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 342ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context, AttributeSet attrs) { 343d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context, attrs); 34447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 345d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 346d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 34747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell void initViewPager() { 348d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setWillNotDraw(false); 3492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 3502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setFocusable(true); 351560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final Context context = getContext(); 3521cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller = new Scroller(context, sInterpolator); 3531cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 35416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float density = context.getResources().getDisplayMetrics().density; 35516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell 356d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 35716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); 358d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 359560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge = new EdgeEffectCompat(context); 360560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge = new EdgeEffectCompat(context); 3611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 362035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); 363b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mCloseEnough = (int) (CLOSE_ENOUGH * density); 3648f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); 36525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 36625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); 36725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 36825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (ViewCompat.getImportantForAccessibility(this) 36925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 37025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setImportantForAccessibility(this, 37125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 37225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 373d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 374d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 37571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio @Override 37671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio protected void onDetachedFromWindow() { 37771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio removeCallbacks(mEndScrollRunnable); 37871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio super.onDetachedFromWindow(); 37971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 38071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio 38147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void setScrollState(int newState) { 38247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mScrollState == newState) { 38347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell return; 38447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 38547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 38647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mScrollState = newState; 3878a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mPageTransformer != null) { 3888a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell // PageTransformers can do complex things that benefit from hardware layers. 3898a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell enableLayers(newState != SCROLL_STATE_IDLE); 3908a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 39147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mOnPageChangeListener != null) { 39247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageScrollStateChanged(newState); 39347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 39447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 39547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 3968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a PagerAdapter that will supply views for this pager as needed. 3988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 3998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param adapter Adapter to use 4008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 401ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public void setAdapter(PagerAdapter adapter) { 4023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter != null) { 4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.unregisterDataSetObserver(mObserver); 4040d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.startUpdate(this); 4050d6d2990ddacd3f419879149137f09a30c061436Minh Pham for (int i = 0; i < mItems.size(); i++) { 4060d6d2990ddacd3f419879149137f09a30c061436Minh Pham final ItemInfo ii = mItems.get(i); 4070d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.destroyItem(this, ii.position, ii.object); 4080d6d2990ddacd3f419879149137f09a30c061436Minh Pham } 4090d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.finishUpdate(this); 4100d6d2990ddacd3f419879149137f09a30c061436Minh Pham mItems.clear(); 411a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeNonDecorViews(); 4120d6d2990ddacd3f419879149137f09a30c061436Minh Pham mCurItem = 0; 413871a68b5daafd810623d680207652f87eb2d11ccMinh Pham scrollTo(0, 0); 4143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 4168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final PagerAdapter oldAdapter = mAdapter; 417d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mAdapter = adapter; 418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 4203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mObserver == null) { 4218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mObserver = new PagerObserver(); 4223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.registerDataSetObserver(mObserver); 424d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 42591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell mFirstLayout = true; 426d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mRestoredCurItem >= 0) { 4275c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 428d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mRestoredCurItem, false, true); 429d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = -1; 430ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = null; 4315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = null; 432d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 4368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 4378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mAdapterChangeListener != null && oldAdapter != adapter) { 4388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 4398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 441d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 442a7aea206661d601755bfac4165092d9130cba2bcAdam Powell private void removeNonDecorViews() { 443a7aea206661d601755bfac4165092d9130cba2bcAdam Powell for (int i = 0; i < getChildCount(); i++) { 444a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final View child = getChildAt(i); 445a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 446a7aea206661d601755bfac4165092d9130cba2bcAdam Powell if (!lp.isDecor) { 447a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeViewAt(i); 448a7aea206661d601755bfac4165092d9130cba2bcAdam Powell i--; 449a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 450a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 451a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 452a7aea206661d601755bfac4165092d9130cba2bcAdam Powell 4538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Retrieve the current adapter supplying pages. 4558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The currently registered PagerAdapter 4578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 458ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public PagerAdapter getAdapter() { 459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mAdapter; 460d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 461d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell void setOnAdapterChangeListener(OnAdapterChangeListener listener) { 4638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener = listener; 4648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 4658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 46697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 46797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. If the ViewPager has already been through its first 46891eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * layout with its current adapter there will be a smooth animated transition between 46991eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * the current item and the specified item. 47097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 47197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 47297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 473d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void setCurrentItem(int item) { 474d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 47597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, !mFirstLayout, false); 47697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell } 47797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 47897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 47997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. 48097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 48197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 48297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately 48397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 48497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell public void setCurrentItem(int item, boolean smoothScroll) { 48597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mPopulatePending = false; 48697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, smoothScroll, false); 487d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 488d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 489bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki public int getCurrentItem() { 490bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki return mCurItem; 491bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki } 492bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki 493d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { 4941cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(item, smoothScroll, always, 0); 4951cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 4961cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 4971cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { 498d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null || mAdapter.getCount() <= 0) { 499d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 500d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 501d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 502d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!always && mCurItem == item && mItems.size() != 0) { 503d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 504d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 505d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 5068d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell 507d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (item < 0) { 508d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = 0; 509d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else if (item >= mAdapter.getCount()) { 510d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = mAdapter.getCount() - 1; 511d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 51229a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 51329a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { 5144c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // We are doing a jump by more than one page. To avoid 5154c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // glitches, we want to keep all current pages in the view 5164c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // until the scroll ends. 5174c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 5184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mItems.get(i).scrolling = true; 5194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 5204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 52147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final boolean dispatchSelected = mCurItem != item; 522a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(item); 523a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne scrollToItem(item, smoothScroll, velocity, dispatchSelected); 524a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne } 525a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne 526a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne private void scrollToItem(int item, boolean smoothScroll, int velocity, 527a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne boolean dispatchSelected) { 528a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo curInfo = infoForPosition(item); 52931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell int destX = 0; 53031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (curInfo != null) { 53131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int width = getWidth(); 53231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell destX = (int) (width * Math.max(mFirstOffset, 53331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell Math.min(curInfo.offset, mLastOffset))); 53431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 535d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (smoothScroll) { 5361cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(destX, 0, velocity); 53747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 53847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageSelected(item); 53947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 5408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 5418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 5428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 543d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 54447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 5453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener.onPageSelected(item); 5463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 5488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 5498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 55071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 551329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell scrollTo(destX, 0); 552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 5558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 5568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 5578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 5588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 5623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 5633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 565d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 5668a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * Set a {@link PageTransformer} that will be called for each attached page whenever 5678a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * the scroll position is changed. This allows the application to apply custom property 5688a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * transformations to each page, overriding the default sliding look and feel. 5698a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 5708a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist. 5718a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p> 5728a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 5738a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param reverseDrawingOrder true if the supplied PageTransformer requires page views 5748a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * to be drawn from last to first instead of first to last. 5758a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param transformer PageTransformer that will modify each page's animation properties 5768a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 5778a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { 5788a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (Build.VERSION.SDK_INT >= 11) { 5797e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean hasTransformer = transformer != null; 5807e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean needsPopulate = hasTransformer != (mPageTransformer != null); 5818a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer = transformer; 5827e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell setChildrenDrawingOrderEnabledCompat(hasTransformer); 5837e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (hasTransformer) { 5847e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; 5857e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } else { 5867e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = DRAW_ORDER_DEFAULT; 5877e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 5887e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (needsPopulate) populate(); 5898a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 5908a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 5918a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 5928a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell void setChildrenDrawingOrderEnabledCompat(boolean enable) { 5938a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mSetChildrenDrawingOrderEnabled == null) { 5948a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell try { 5957e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( 5968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE }); 5978a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } catch (NoSuchMethodException e) { 5988a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); 5998a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6008a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6018a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell try { 6028a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mSetChildrenDrawingOrderEnabled.invoke(this, enable); 6038a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } catch (Exception e) { 6048a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell Log.e(TAG, "Error changing children drawing order", e); 6058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6088a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell @Override 6098a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell protected int getChildDrawingOrder(int childCount, int i) { 6107e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; 6117e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; 6127e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return result; 6138a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6148a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 6168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 6178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 6188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 6198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 6208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 6218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 6228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 6238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 6248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 6258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 6268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 6278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 62829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 62929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 63029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 63129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 63229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 63329a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 63429a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 63529a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 63629a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 63729a6184d74279156a9297dc67398712fb047fdc0Adam Powell 63829a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 63929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 64029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 64129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 64229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 64329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 64429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 64529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 64629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 64729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 64829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 64929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 65029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 65129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 65229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 65329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 65429a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 65529a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 65629a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 65729a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 65829a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 65929a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 66029a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 66129a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 66229a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 66329a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 66429a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 66529a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 66629a6184d74279156a9297dc67398712fb047fdc0Adam Powell 66729a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 668329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 669329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 670329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 671329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 672329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 673329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 674329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 675329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 676329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 677329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 678329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 679329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 680329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 681329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 682329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 683329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 684329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 685329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 686329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 687329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 688329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 689329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 690329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 691329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 692329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 693329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 694329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 695329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 696329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 697329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 698329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 699329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 700329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 701329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 702329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 703329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 704329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 705329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 706329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 707329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 708329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 709329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 710329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 711329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 712329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 713329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 714329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 715329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 716329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 717329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 718329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 719329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 720329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 721329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 722329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 723329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 724329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 725329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 726329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 727329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 728329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 7291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 7301cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 7311cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 7321cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 7331cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 7341cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 7351cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 7361cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 7371cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7381cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 739329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 740d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 742cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 743cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 7461cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 7471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7481cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 7491cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 7501cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 7511cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 7521cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 7531cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 7541cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 7551cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 7561cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 757d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 758d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 759d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 761d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 7643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 7653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 7663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 76771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 76831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 7693040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 7703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 7713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 77447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 7751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 776035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int width = getWidth(); 777035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 778035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 779035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 780035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 7811cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 782035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 7831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 7841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 785035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 7861cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 787a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 788a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 789035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 7901cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7911cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 7921cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 7931cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 794b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 796d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 797a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 798d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 8005c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 801a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 802a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 807a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 809d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 8113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 8123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8131a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 8141a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell mItems.size() < mAdapter.getCount(); 8151e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 8163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8179508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 8183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 8193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 8203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 8213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 8233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 8273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 8283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 8299508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8309508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 8319508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 8329508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 8339508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8349508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 8363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 8393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 8403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); 8411a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 8423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 8473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 8483661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 8493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 8503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 8533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8579508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 8589508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 8599508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8609508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 86166c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 86266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 874d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 8753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 8763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 879d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 884a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 885a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 886a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 887a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 888a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 889a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 891d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 892d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 893d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 894d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 895d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 896d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 897d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 898d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 8993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 900d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 901d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 902d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 903ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 904ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 905ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 906ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 907ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 908ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 909ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 9105c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 911d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 91229a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 91329a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 9144c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 91529a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 916d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 918a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 919a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 921a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 922a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 926a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 927d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 93931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final float leftWidthNeeded = 2.f - curItem.widthFactor; 940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 94131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 94871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 94971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 95071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 95171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 9654c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 966d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 967d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight >= 2.f && pos > endPos) { 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 98071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 98171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 98271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 98371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 997d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 1000d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1001d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10024c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 10034c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 10044c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 10054c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 1006d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1007d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1008d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 10102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10115c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 10122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10137e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Check width measurement of current pages and drawing sort order. 10147e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Update LayoutParams as needed. 10157e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean sort = mDrawingOrder != DRAW_ORDER_DEFAULT; 10167e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (sort) { 10177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (mDrawingOrderedChildren == null) { 10187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrderedChildren = new ArrayList<View>(); 10197e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } else { 10207e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrderedChildren.clear(); 10217e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 10227e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 1023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 1024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 1025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1026a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 10277e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.childIndex = i; 1028a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 1029a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 1030a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 1031a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 1032a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 10337e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.position = ii.position; 1034a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1035a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 10367e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (sort) mDrawingOrderedChildren.add(child); 10377e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 10387e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (sort) { 10397e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell Collections.sort(mDrawingOrderedChildren, sPositionComparator); 1040a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1041a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 10422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 10432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 1044218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 10452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 10462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 10472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 10482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 10492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 10502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(FOCUS_FORWARD)) { 10512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 10522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1058d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1059a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 1060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 1061a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1062a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1063a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 1064a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 1065a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 1066a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 1067a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 1068a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1069a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 10706bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 1071a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 1072a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 1073a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1074a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 1075a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1076a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1077a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1078a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1081a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 1082a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 1083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1085a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1086a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1087a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 1088a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 1089a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 1090a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 1091a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 1092a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 1093a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1094a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 1095a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1096a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1097a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1098a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1099a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1100a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1101a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 1102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 1103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1104a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1105a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1108a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1109a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 1111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 1113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 1114a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 111531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 111631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 1117a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 1118a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 1119a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 1122a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1123a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 1126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 1131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 113531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 113631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 113731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 1138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 1143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 11457dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 11467dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 11477dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 11487dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 11497dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 11507dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1153ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 11545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 11645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11745c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 11755c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 11765c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 11775c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 11785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 11795c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 11805c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 11815c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 11825c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 11835c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 11845c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 11855c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 11865c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1187d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 11885c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 11895c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1190ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 11915c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 11925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 11935c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1194d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1195d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1196d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1197d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1198d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1199d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1200d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1201d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1202677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1203677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1204677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1205d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1206d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1207d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1208d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1209d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1210d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1211d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1212d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1214d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1215d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1216d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1217d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1218d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 12195c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1222d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1223ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 12245c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1225d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1226d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1227d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1228d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 12301ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 12311ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 12321ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 12331ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 12341ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 12368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 12378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 12388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1239a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1240d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1241d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1242d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1243d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1244d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1245d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1246d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1247d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1248d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1249d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1250d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1251d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1252d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1253d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 125437a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase @Override 125537a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase public void removeView(View view) { 125637a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase if (mInLayout) { 125737a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase removeViewInLayout(view); 125837a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } else { 125937a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase super.removeView(view); 126037a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 126137a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 126237a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase 1263d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1264d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1265d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1266ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1267d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1273218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1274218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1275218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1276218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1277218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1278218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1279218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1280218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1281218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1282218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1283218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1284a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1285a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1286a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1287a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1288a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1289a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1290a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1291a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1292a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1293a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1294d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1295ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1296ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 129797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1298ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1299ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1300ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1301d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1302d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // For simple implementation, or internal size is always 0. 1303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1309d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 13108f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int measuredWidth = getMeasuredWidth(); 13118f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int maxGutterSize = measuredWidth / 10; 13128f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); 13138f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 13158f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); 13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1323862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 13348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 13358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 13378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 13388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 13398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 13408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1342a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1343a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1344a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1355a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1356a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1357a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 13588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 13598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 13618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 13628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 13638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 13648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 13708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1372d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1373d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1374d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 13778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1378862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1381d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1382d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 13838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 13848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1387a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1388a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1389a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 13908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1394d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1395d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1396d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1397d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1400053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1401329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1402329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1403329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1404329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1405329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 140691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 14078d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int widthWithMargin = width + margin; 14085f6568e7e269783e2668527461878cadfbe65215Adam Powell final int oldWidthWithMargin = oldWidth + oldMargin; 14098d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int xpos = getScrollX(); 14105f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 14115f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1412a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 14135f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1414329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1415329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1416329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 14185f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 14198d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell (int) (targetInfo.offset * width), 0, newDuration); 1420329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1421329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1422a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 14238d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; 14248d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int scrollPos = (int) (scrollOffset * width); 1425329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 142671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 1427053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 14289bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1429d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1430d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1431d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1432d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 14398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 14408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 14418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 14428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1448d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1449a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1450a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1495abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1496abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1497abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1498a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1499a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1500a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1501a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1502a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1503a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1504a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1505a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1506a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1507a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1508a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1509a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1510a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int loff = (int) (width * ii.offset); 1511a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1512a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1513a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1514a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1515a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1516a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1517a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1518a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) ((width - paddingLeft - paddingRight) * lp.widthFactor), 1519a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1520a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1521a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1522a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1523a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1524a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 15258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 15268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 15278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1528abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1529abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1530abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 15318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1532d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1533d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 15348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 15358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 15368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 153797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1538d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1539d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1540d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1541d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1542a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1543a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1544a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1545a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1546a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 15473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1548a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1549a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 15504783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 15514783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 15524783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 15534783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1555a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1556a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1557b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1558a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 15604c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 15614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 156271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(true); 1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1564d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 15654783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 15664783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 15674783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 15684783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 15694783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 15704783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 15714783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 15724783095cc69fa85e484132337526c94d42d41c43Adam Powell } 15734783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 15744783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1575a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1576a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1577a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1578a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1579a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1580a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1581a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1582a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 15838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1585a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 15868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 15878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 15888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 15898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15904783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 15918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 15948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 15958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 15968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 15978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 15988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 15998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 16008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 16018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 16028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 16038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 16048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 16058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 16068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 16078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 16088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 16098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 16108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 16118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 16128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 16138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 16148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 16158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 16178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 16198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 16208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 16218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 16228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 16258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 16278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 16298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 16308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 16318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 16338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 16348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 16358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 16388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 16408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 16418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 16428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 16478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 16488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 16508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 16518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16528a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 16538a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mPageTransformer != null) { 16548a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int scrollX = getScrollX(); 16558a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 16568a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 16578a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final View child = getChildAt(i); 16587e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16597e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 16607e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (lp.isDecor) continue; 16617e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 16628a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final float transformPos = (float) (child.getLeft() - scrollX) / getWidth(); 16638a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer.transformPage(child, transformPos); 16648a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 16658a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 16668a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 16678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 16688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 167071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio private void completeScroll(boolean postEvents) { 16718d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; 1672cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 16734c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 16744c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1675d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1676d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1677d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1678d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1679d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1682d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 16834c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 16843661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 16854c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 16864c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 16874c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 16884c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 16894c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 16904c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 16914c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 16924c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 169371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (postEvents) { 169471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio ViewCompat.postOnAnimation(this, mEndScrollRunnable); 169571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } else { 169671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio mEndScrollRunnable.run(); 169771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 17018f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean isGutterDrag(float x, float dx) { 17028f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); 17038f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell } 17048f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 17058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private void enableLayers(boolean enable) { 17068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 17078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 17088a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int layerType = enable ? 17098a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; 17108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.setLayerType(getChildAt(i), layerType, null); 17118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17128a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17138a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 1714d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1715d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1716d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1717d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1720d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1721d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1722d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1723d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1724d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1725d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1726d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1727d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1728d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1729d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1730d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 17313ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 17323ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 17333ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 17343ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1735d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1736d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1737d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1738d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1739d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1740d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1742d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1743d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1746d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1747d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1748d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1749d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1750d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1751d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1752d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1753d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1754d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1755d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1756d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1757d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1758d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1759d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1761d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1766d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1767d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1768d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1769d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 177047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 177147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 177316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float yDiff = Math.abs(y - mInitialMotionY); 1774d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1775bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 17768f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && 17778f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell canScroll(this, false, (int) dx, (int) x, (int) y)) { 1778bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 177916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionX = x; 1780bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1781b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1782bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1783bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 178416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) { 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 178747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 17888d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : 17898d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 179016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 179216991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell } else if (yDiff > mTouchSlop) { 179316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // The finger has moved enough in the vertical 179416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // direction to be counted as a drag... abort 179516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // any attempt to drag horizontally, to work correctly 179616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // with children that have scrolling containers. 179716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 179816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mIsUnableToDrag = true; 1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 18006e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (mIsBeingDragged) { 18016e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Scroll to follow the motion event 18026e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (performDrag(x)) { 18036e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell ViewCompat.postInvalidateOnAnimation(this); 18046e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18056e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1809d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1810d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1814d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 181516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1816d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1817b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18198d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.computeScrollOffset(); 1820b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1821b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 182247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 18238d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 18248d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 18258d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 182647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 182747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 182847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 182971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 183047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 183147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1832d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1833d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1834d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1835d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1839d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1840d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1841d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1842d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1843d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18448d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell if (mVelocityTracker == null) { 18458d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker = VelocityTracker.obtain(); 18463ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 18478d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker.addMovement(ev); 18483ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1849d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 18503ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 18513ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 18523ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1853d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1854d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1855d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1856d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1857d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 185869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 185969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 186069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 186169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 186269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 186369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1864d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1865d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1866d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1867d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1868d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1869d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1870d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 18723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 18733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 18743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 18753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1876d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1877d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1878d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1879d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1880d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1881d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1882560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1883d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1885d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 18868d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 18878d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 18888d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 18898d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mIsBeingDragged = true; 18908d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell setScrollState(SCROLL_STATE_DRAGGING); 1891d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1892d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1893d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 189416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1895d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1896d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1897d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1898d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 18993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 19003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 19013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 190247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 19033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 190447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 19053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 19063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 19073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 19083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 19098d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : 19108d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 191116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 191247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 19133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 19143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 19153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 191631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1917d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1918d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1919d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1920d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1921d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 19226e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate |= performDrag(x); 1923d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1924d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1925d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1927d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 1928d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 19291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 1930d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 1931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 1932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 19331cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 1934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 1937035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 1938035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 1939035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 1940035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 1941035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 1942035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 19431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 1944d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1945d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1946d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1947560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1948d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1949d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1950d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 1951d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1952a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne scrollToItem(mCurItem, true, 0, false); 1953d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1954d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1955560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1956d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1957d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1958d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 1959d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 1960d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 1961d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1962d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 1963d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1964d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1965d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1966d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1967d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 1968d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 1969d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1970d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1971560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1972b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1973560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1974d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1975d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1976d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19776e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell private boolean performDrag(float x) { 19786e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean needsInvalidate = false; 19796e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 19806e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final float deltaX = mLastMotionX - x; 19816e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX = x; 19826e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 19836e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float oldScrollX = getScrollX(); 19846e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float scrollX = oldScrollX + deltaX; 19856e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final int width = getWidth(); 19866e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 19876e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float leftBound = width * mFirstOffset; 19886e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float rightBound = width * mLastOffset; 19896e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean leftAbsolute = true; 19906e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean rightAbsolute = true; 19916e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 19926e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo firstItem = mItems.get(0); 19936e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 19946e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (firstItem.position != 0) { 19956e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftAbsolute = false; 19966e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftBound = firstItem.offset * width; 19976e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 19986e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (lastItem.position != mAdapter.getCount() - 1) { 19996e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightAbsolute = false; 20006e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightBound = lastItem.offset * width; 20016e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20026e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20036e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (scrollX < leftBound) { 20046e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (leftAbsolute) { 20056e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = leftBound - scrollX; 20066e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 20076e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20086e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = leftBound; 20096e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } else if (scrollX > rightBound) { 20106e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (rightAbsolute) { 20116e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = scrollX - rightBound; 20126e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 20136e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20146e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = rightBound; 20156e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20166e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Don't lose the rounded component 20176e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX += scrollX - (int) scrollX; 20186e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollTo((int) scrollX, getScrollY()); 20196e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell pageScrolled((int) scrollX); 20206e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20216e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell return needsInvalidate; 20226e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20236e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 2024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 2026a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 2027a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2028a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 2029a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2030a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 2031a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 2032a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 2033a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 2034a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 2035a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 2036a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2037ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 2038a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 2039a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 2040a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 2041a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 2042a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 2043a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 2044a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 2045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 2046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 2047a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 2048a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2049a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 2050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 20518d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float leftBound = offset; 20528d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset; 2053ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 2054ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 2055ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 2056ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 2057ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 2058ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2059a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 2061a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 2062a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 2063a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 2064ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 2065a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2066a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2067ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2068a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2069a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2070035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 2071035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 2072035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 2073035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 2074035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 207516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; 207616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell targetPage = (int) (currentPage + pageOffset + truncator); 2077035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2078035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 2080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2081a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2082a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 2084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 2085a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2086a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2087035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 2088035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2089035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2090560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 2091560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 2092560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 2093560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 2094560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2095560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 2096560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 2097560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 2098560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 2099560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 2100560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2101560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2103560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2104560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 2105a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 2106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 2107560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 2108560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2109560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2110560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 2111560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2112560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 2113560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2114560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2115560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 2116a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 2117560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 2118560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 2119560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2120560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2121560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 2122560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 2123560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 2124560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2125560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2126560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 2127560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 2128b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 2129560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2130560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2131560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2132329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 2133329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 2134329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 2135329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 2136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 2137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 2138329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 2139329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 2140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 2142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 2143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 2144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 2145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 2146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 2147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 2148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 2149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 2150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 2151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 215323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 2154a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 215523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 2156a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 2157a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 2158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 215923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 2160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 2161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 2164a56d6faa9df608aaa2907864669800abb68acec7Adam Powell mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, 216523b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 2166a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 2167a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2168a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2169a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 2170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 2171a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2172329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2173329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2174329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2175329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 217669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 217769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 217869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 217969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 218069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 218169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 218269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 218369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 218469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 218569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 218669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 218769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 218869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 218969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 219069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 219169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 219269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 219369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 219469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 219569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 219669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 219769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 219869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 219969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 220069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 220169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 220269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 220369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 220469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 220569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 220669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 220769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 220869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 220969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 221069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 221169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 221269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 221369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 221469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 221569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 221669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 221769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 221869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 221969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 222069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 222169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 222269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 222369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 222469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 222569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 22260f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 222769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 222869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2229a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2230035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2231a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2232a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2233a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2234a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2235a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2236a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2237035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 223869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 223969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 224069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 224169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 224269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 224369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 224469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 224569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 224669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 224769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 224869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 224969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 225069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 225169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 225269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 225369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 225469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 225569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2256a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2257a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 22580f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 225969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final int width = getWidth(); 226069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2261a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2262a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2263a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2264a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2265a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2266a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2267a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2268a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2269a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2270a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2271a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2272a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 227369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 227469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 227569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 227669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 227769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 227869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 227969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 228069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 22818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 228269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 228369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 228469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 228569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 228669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 228769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 228869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 228969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 229069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 229169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 229269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 229369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 229469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 229569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 229669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 229769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 229869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 229969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 230069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 230169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 230269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 230369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2309d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2310d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2315d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2316d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2317d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2318d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2319d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2320d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2321d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2322d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2323d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2324d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2325d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2326d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2327d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2328d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2329d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2332d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2333d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2334d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2335d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2336d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2337d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2338d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2339d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2340d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2341d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2342d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 23433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2344bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2345cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2346bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2347bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2348bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2349bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2350bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2351cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2352bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2353cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2354bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2355cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2356bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2357bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2358bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2359bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2360bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2361bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2362bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2363bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2364bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2365bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2366bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2367bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2368bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2369bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2370bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2371bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2372bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2373bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2374bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2375bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2376bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2377bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2378481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 23792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 23802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 23812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 23822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 23862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 23872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 23882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 23892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 23902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 23912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 23932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 23942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 23952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 23962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 23972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 23982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 23992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 24002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 24012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 24035de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 24045de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 24055de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 24065de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 24075de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 24085de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 24095de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 24105de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 24112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 24162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 24192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 24202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused == this) currentFocused = null; 24212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 24232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 24252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 24262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 24272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 24282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 24292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 2430dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2431dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2432dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft >= currLeft) { 24332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 24342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 24352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 24362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 24382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 24392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 2440dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2441dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2442dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft <= currLeft) { 24432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 24442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 24452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 24462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 24492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 24502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 24512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 24522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 24532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 24542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 24562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 24572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 24592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 2461dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { 2462dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (outRect == null) { 2463dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect = new Rect(); 2464dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2465efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell if (child == null) { 2466efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell outRect.set(0, 0, 0, 0); 2467efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell return outRect; 2468efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell } 2469dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left = child.getLeft(); 2470dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right = child.getRight(); 2471dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top = child.getTop(); 2472dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom = child.getBottom(); 2473dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2474dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell ViewParent parent = child.getParent(); 2475dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell while (parent instanceof ViewGroup && parent != this) { 2476dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final ViewGroup group = (ViewGroup) parent; 2477dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left += group.getLeft(); 2478dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right += group.getRight(); 2479dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top += group.getTop(); 2480dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom += group.getBottom(); 2481dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2482dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell parent = group.getParent(); 2483dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2484dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell return outRect; 2485dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2486dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 24872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 24882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 24892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 24902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 24912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 24932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2496218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 24972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 24982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 24992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 25012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 25042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 25052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 25062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 25072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 25082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 25092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 25112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 25132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 25142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 25152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 25162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 25172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 25182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 25192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 25252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 25262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 25272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 25282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 25292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 25302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 25312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 25322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 25332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 25342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 25352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 25362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 25382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 25392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 25402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 25422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 25432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 25482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 25492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 25502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 25512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 25522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 25532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 25542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 25552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 25562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 25572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 25582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 25592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 25602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 25612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 25672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 25682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 25692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 25702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 25712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 25722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 25732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 25742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 25752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 25762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 25772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 25782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 25792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 25802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 25812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 25822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 25832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 25842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 25862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 25872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 25882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 25892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 25902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(direction, previouslyFocusedRect)) { 25912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 25922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2595481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 25962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2597481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2598481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2599481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2600481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2601481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // ViewPagers should only report accessibility info for the current page, 2602481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // otherwise things get very confusing. 2603481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2604481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // TODO: Should this note something about the paging container? 2605481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2606481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2607481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2608481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2609481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2610481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2611481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2612481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2613481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2614481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2615481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2616481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2617481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2618481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2619481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2620481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 26218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 26228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 26238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 26248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 26258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 26268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 26278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 26288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 26298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 26308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 26318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 26328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 26338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 26348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 26358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 26368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 26378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 26381ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 26398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 26408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 264125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov class MyAccessibilityDelegate extends AccessibilityDelegateCompat { 264225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 264325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 264425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 264525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityEvent(host, event); 264625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov event.setClassName(ViewPager.class.getName()); 264725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 264825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 264925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 265025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 265125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(host, info); 265225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setClassName(ViewPager.class.getName()); 265325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setScrollable(mAdapter != null && mAdapter.getCount() > 1); 265425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 265525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 265625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 265725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 265825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 265925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 266025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 266125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 266225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 266325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public boolean performAccessibilityAction(View host, int action, Bundle args) { 266425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (super.performAccessibilityAction(host, action, args)) { 266525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 266625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 266725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov switch (action) { 266825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { 266925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 267025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem + 1); 267125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 267225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 267325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 267425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { 267525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 267625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem - 1); 267725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 267825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 267925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 268025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 268125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return false; 268225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 268325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 268425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 26858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 26868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 26878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 26888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 26898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 26903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 26918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 26923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 26933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 26943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 26958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 26967dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 26977dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 26987dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 26997dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 27008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 27018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 27028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 27038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 27048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 27058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 27068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2707a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 27083d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 27097dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 27107dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2711a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 27128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 27138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2714a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2715a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2716a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 27177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell float widthFactor = 0.f; 2718a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2719a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2720a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2721a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2722a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 27237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell boolean needsMeasure; 27247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 27257e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 27267e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Adapter position this view is for if !isDecor 27277e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 27287e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int position; 27297e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 27307e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 27317e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Current child index within the ViewPager that this view occupies 27327e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 27337e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int childIndex; 2734a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 27358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 27368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 27378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 27408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 27418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2743a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 27448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 27458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27477e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 27487e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell static class ViewPositionComparator implements Comparator<View> { 27497e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell @Override 27507e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell public int compare(View lhs, View rhs) { 27517e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); 27527e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); 27537e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (llp.isDecor != rlp.isDecor) { 27547e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.isDecor ? 1 : -1; 27557e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 27567e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.position - rlp.position; 27577e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 27587e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 2759d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2760