ViewPager.java revision efea2e772645ccd2d0de3e92fa8382d5444eab11
1d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/* 2d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project 3d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 4d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * you may not use this file except in compliance with the License. 6d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * You may obtain a copy of the License at 7d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 8d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 10d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 11d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * See the License for the specific language governing permissions and 14d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * limitations under the License. 15d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 16d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpackage android.support.v4.view; 18d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.content.Context; 208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray; 218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver; 22560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas; 23481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect; 24329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable; 255de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build; 2625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.os.Bundle; 27d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel; 28d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable; 2969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock; 305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat; 315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks; 3225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 33560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat; 34d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet; 35d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log; 362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder; 378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity; 382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent; 39d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent; 402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants; 41d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker; 42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View; 43d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration; 44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup; 45218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent; 46481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent; 471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator; 48d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller; 49d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 50d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList; 5166c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections; 5266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator; 53d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 54d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/** 55d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right 565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data. You supply an implementation of a 575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows. 585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * 595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and 605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development. The API will likely change in later updates of 615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code 625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p> 637dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 647dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, 657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page. 667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager, 677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases. These are 687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter}, 697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter}, 707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and 717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these 727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface 737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them. 747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction 767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs. You can find other examples of using 777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java 807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * complete} 81d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 82ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup { 833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private static final String TAG = "ViewPager"; 84d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean DEBUG = false; 85d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean USE_CACHE = false; 87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8829a6184d74279156a9297dc67398712fb047fdc0Adam Powell private static final int DEFAULT_OFFSCREEN_PAGES = 1; 891cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final int MAX_SETTLE_DURATION = 600; // ms 90035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private static final int MIN_DISTANCE_FOR_FLING = 25; // dips 9129a6184d74279156a9297dc67398712fb047fdc0Adam Powell 928f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private static final int DEFAULT_GUTTER_SIZE = 16; // dips 938f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private static final int[] LAYOUT_ATTRS = new int[] { 958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell android.R.attr.layout_gravity 968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell }; 978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 98d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn static class ItemInfo { 99ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Object object; 100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1014c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn boolean scrolling; 102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor; 103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ 10766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham @Override 10866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham public int compare(ItemInfo lhs, ItemInfo rhs) { 10966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham return lhs.position - rhs.position; 110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell }; 11266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 1131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final Interpolator sInterpolator = new Interpolator() { 1141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell public float getInterpolation(float t) { 1151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell t -= 1.0f; 116035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return t * t * t * t * t + 1.0f; 1171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 1181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell }; 1191cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); 121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private final ItemInfo mTempItem = new ItemInfo(); 122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 123dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private final Rect mTempRect = new Rect(); 124dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 125ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private PagerAdapter mAdapter; 1263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private int mCurItem; // Index of currently displayed page. 127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mRestoredCurItem = -1; 128ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private Parcelable mRestoredAdapterState = null; 1295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn private ClassLoader mRestoredClassLoader = null; 130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private Scroller mScroller; 1318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private PagerObserver mObserver; 132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 133329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private int mPageMargin; 134329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private Drawable mMarginDrawable; 1358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mTopPageBounds; 1368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mBottomPageBounds; 137329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Offsets of the first and last items, if known. 139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Set during population, used to determine if we are at the beginning 140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // or end of the pager data set during touch scrolling. 141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mFirstOffset = -Float.MAX_VALUE; 142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mLastOffset = Float.MAX_VALUE; 143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildWidthMeasureSpec; 145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildHeightMeasureSpec; 146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mInLayout; 147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mScrollingCacheEnabled; 149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mPopulatePending; 15129a6184d74279156a9297dc67398712fb047fdc0Adam Powell private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; 152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsBeingDragged; 154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsUnableToDrag; 1558f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean mIgnoreGutter; 1568f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mDefaultGutterSize; 1578f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mGutterSize; 158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mTouchSlop; 159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mInitialMotionX; 160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Position of the last motion event. 162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionX; 164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionY; 165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ID of the active pointer. This is used to retain consistency during 167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * drags/flings if multiple pointers are used. 168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mActivePointerId = INVALID_POINTER; 170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Sentinel value for no current active pointer. 172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Used by {@link #mActivePointerId}. 173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final int INVALID_POINTER = -1; 175d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Determines speed during touch scrolling 178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private VelocityTracker mVelocityTracker; 180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMinimumVelocity; 181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMaximumVelocity; 182035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int mFlingDistance; 183b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private int mCloseEnough; 184b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell 185b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // If the pager is at least this close to its final position, complete the scroll 186b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // on touch down and let the user interact with the content inside instead of 187b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // "catching" the flinging pager. 188b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private static final int CLOSE_ENOUGH = 2; // dp 189d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private boolean mFakeDragging; 19169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private long mFakeDragBeginTime; 19269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mLeftEdge; 194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mRightEdge; 195560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 19697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell private boolean mFirstLayout = true; 197a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private boolean mNeedCalculatePageOffsets = false; 1988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private boolean mCalledSuper; 1998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mDecorChildCount; 20097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 2013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private OnPageChangeListener mOnPageChangeListener; 2028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnPageChangeListener mInternalPageChangeListener; 2038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnAdapterChangeListener mAdapterChangeListener; 2043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 20647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in an idle, settled state. The current page 20747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * is fully in view and no animation is in progress. 20847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 20947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_IDLE = 0; 21047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 21247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is currently being dragged by the user. 21347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 21447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_DRAGGING = 1; 21547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 21747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in the process of settling to a final position. 21847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 21947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_SETTLING = 2; 22047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 22147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private int mScrollState = SCROLL_STATE_IDLE; 22247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 22347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 2243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Callback interface for responding to changing state of the selected page. 2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public interface OnPageChangeListener { 22747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 2283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * This method will be invoked when the current page is scrolled, either as part 2303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 2313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the first page currently being displayed. 2333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 2343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 2353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffsetPixels Value in pixels indicating the offset from position. 2363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); 2383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * This method will be invoked when a new page becomes selected. Animation is not 24147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * necessarily complete. 2423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the new selected page. 2443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position); 24647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 24747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Called when the scroll state changes. Useful for discovering when the user 24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * begins dragging, when the pager is automatically settling to the current page, 25047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * or when it is fully stopped/idle. 25147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * 25247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @param state The new scroll state. 25347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_IDLE 25447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_DRAGGING 25547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_SETTLING 25647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 25747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state); 2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Simple implementation of the {@link OnPageChangeListener} interface with stub 2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * implementations of each method. Extend this if you do not intend to override 2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * every method of {@link OnPageChangeListener}. 2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public static class SimpleOnPageChangeListener implements OnPageChangeListener { 2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 2683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position) { 2733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell @Override 27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state) { 27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // This space for rent 27947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 2803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 2838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Used internally to monitor when adapters are switched. 2848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 2858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell interface OnAdapterChangeListener { 2868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); 2878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2891ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell /** 2901ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * Used internally to tag special types of child views that should be added as 2911ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * pager decorations by default. 2921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell */ 2931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell interface Decor {} 2941ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell 295ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context) { 296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context); 29747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 299d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 300ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context, AttributeSet attrs) { 301d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context, attrs); 30247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 30547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell void initViewPager() { 306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setWillNotDraw(false); 3072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 3082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setFocusable(true); 309560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final Context context = getContext(); 3101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller = new Scroller(context, sInterpolator); 3111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 315560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge = new EdgeEffectCompat(context); 316560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge = new EdgeEffectCompat(context); 3171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 318035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float density = context.getResources().getDisplayMetrics().density; 319035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); 320b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mCloseEnough = (int) (CLOSE_ENOUGH * density); 3218f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); 32225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 32325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); 32425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 32525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (ViewCompat.getImportantForAccessibility(this) 32625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 32725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setImportantForAccessibility(this, 32825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 32925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 33247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void setScrollState(int newState) { 33347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mScrollState == newState) { 33447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell return; 33547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 33647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 33747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mScrollState = newState; 33847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mOnPageChangeListener != null) { 33947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageScrollStateChanged(newState); 34047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 34147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 34247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 3438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a PagerAdapter that will supply views for this pager as needed. 3458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param adapter Adapter to use 3478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 348ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public void setAdapter(PagerAdapter adapter) { 3493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter != null) { 3508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.unregisterDataSetObserver(mObserver); 3510d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.startUpdate(this); 3520d6d2990ddacd3f419879149137f09a30c061436Minh Pham for (int i = 0; i < mItems.size(); i++) { 3530d6d2990ddacd3f419879149137f09a30c061436Minh Pham final ItemInfo ii = mItems.get(i); 3540d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.destroyItem(this, ii.position, ii.object); 3550d6d2990ddacd3f419879149137f09a30c061436Minh Pham } 3560d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.finishUpdate(this); 3570d6d2990ddacd3f419879149137f09a30c061436Minh Pham mItems.clear(); 358a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeNonDecorViews(); 3590d6d2990ddacd3f419879149137f09a30c061436Minh Pham mCurItem = 0; 360871a68b5daafd810623d680207652f87eb2d11ccMinh Pham scrollTo(0, 0); 3613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 3638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final PagerAdapter oldAdapter = mAdapter; 364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mAdapter = adapter; 365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 366d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 3673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mObserver == null) { 3688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mObserver = new PagerObserver(); 3693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.registerDataSetObserver(mObserver); 371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 37291eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell mFirstLayout = true; 373d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mRestoredCurItem >= 0) { 3745c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mRestoredCurItem, false, true); 376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = -1; 377ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = null; 3785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = null; 379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 381d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 382d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 3838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 3848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mAdapterChangeListener != null && oldAdapter != adapter) { 3858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 3868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 388d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 389a7aea206661d601755bfac4165092d9130cba2bcAdam Powell private void removeNonDecorViews() { 390a7aea206661d601755bfac4165092d9130cba2bcAdam Powell for (int i = 0; i < getChildCount(); i++) { 391a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final View child = getChildAt(i); 392a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 393a7aea206661d601755bfac4165092d9130cba2bcAdam Powell if (!lp.isDecor) { 394a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeViewAt(i); 395a7aea206661d601755bfac4165092d9130cba2bcAdam Powell i--; 396a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 397a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 398a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 399a7aea206661d601755bfac4165092d9130cba2bcAdam Powell 4008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Retrieve the current adapter supplying pages. 4028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The currently registered PagerAdapter 4048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 405ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public PagerAdapter getAdapter() { 406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mAdapter; 407d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 408d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell void setOnAdapterChangeListener(OnAdapterChangeListener listener) { 4108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener = listener; 4118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 4128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 41397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 41497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. If the ViewPager has already been through its first 41591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * layout with its current adapter there will be a smooth animated transition between 41691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * the current item and the specified item. 41797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 41897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 41997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 420d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void setCurrentItem(int item) { 421d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 42297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, !mFirstLayout, false); 42397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell } 42497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 42597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 42697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. 42797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 42897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 42997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately 43097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 43197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell public void setCurrentItem(int item, boolean smoothScroll) { 43297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mPopulatePending = false; 43397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, smoothScroll, false); 434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 436bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki public int getCurrentItem() { 437bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki return mCurItem; 438bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki } 439bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki 440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { 4411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(item, smoothScroll, always, 0); 4421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 4431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 4441cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { 445d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null || mAdapter.getCount() <= 0) { 446d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 447d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 448d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 449d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!always && mCurItem == item && mItems.size() != 0) { 450d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 4538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell 454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (item < 0) { 455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = 0; 456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else if (item >= mAdapter.getCount()) { 457d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = mAdapter.getCount() - 1; 458d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 45929a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 46029a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { 4614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // We are doing a jump by more than one page. To avoid 4624c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // glitches, we want to keep all current pages in the view 4634c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // until the scroll ends. 4644c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 4654c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mItems.get(i).scrolling = true; 4664c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 4674c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 46847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final boolean dispatchSelected = mCurItem != item; 469a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(item); 470a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo curInfo = infoForPosition(item); 47131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell int destX = 0; 47231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (curInfo != null) { 47331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int width = getWidth(); 47431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell destX = (int) (width * Math.max(mFirstOffset, 47531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell Math.min(curInfo.offset, mLastOffset))); 47631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 477d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (smoothScroll) { 4781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(destX, 0, velocity); 47947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 48047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageSelected(item); 48147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 485d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 48647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 4873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener.onPageSelected(item); 4883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 49247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 493329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell scrollTo(destX, 0); 494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 495d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 496d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 5043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 5053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 507d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 5088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 5098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 5128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 5148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 5158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 5168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 5178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 5188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 5198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 52029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 52129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 52229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 52329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 52429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 52529a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 52629a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 52929a6184d74279156a9297dc67398712fb047fdc0Adam Powell 53029a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 53129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 53229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 53329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 53429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 53529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 53629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 53729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 53829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 53929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 54029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 54129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 54229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 54329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 54429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 54529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 54629a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 54729a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 54829a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 54929a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 55029a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 55129a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 55229a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55329a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 55429a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 55529a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 55629a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55729a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 55829a6184d74279156a9297dc67398712fb047fdc0Adam Powell 55929a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 560329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 561329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 562329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 563329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 564329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 565329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 566329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 567329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 568329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 569329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 570329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 571329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 572329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 573329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 574329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 575329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 576329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 577329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 578329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 579329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 581329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 582329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 583329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 584329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 585329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 586329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 587329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 588329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 589329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 590329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 591329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 592329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 593329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 594329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 595329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 596329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 597329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 598329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 599329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 600329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 601329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 602329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 603329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 604329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 605329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 606329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 607329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 608329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 609329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 610329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 611329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 612329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 613329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 614329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 615329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 616329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 617329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 618329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 619329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 620329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 6211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 6221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 6231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 6241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 6251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 6261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 6271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 6281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 6291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6301cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 631329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 634cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 635cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 6381cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 6391cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6401cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 6421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 6431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 6441cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 6451cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 6461cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 6471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 6481cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 649d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 650d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 651d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 652d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 653d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 654d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 655d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 6563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 6573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 6583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 65947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 66031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 6613040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 6623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 6633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 6643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 66647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 6671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 668035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int width = getWidth(); 669035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 670035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 671035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 672035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 6731cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 674035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 6751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 6761cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 677035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 6781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 679a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 680a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 681035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 6821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 6841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6851cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 686b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 689a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 6925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 693a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 694a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 699a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 701d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 7023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 7033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 7043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7051a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 7061a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell mItems.size() < mAdapter.getCount(); 7071e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 7083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7099508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 7103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 7113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 7123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 7133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 7153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 7163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 7193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 7203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 7219508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7229508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 7239508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 7249508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 7259508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7269508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 7283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 7313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 7323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); 7331a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 7343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 7363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 7393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 7403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 7413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 7423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 7453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7483661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7499508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 7509508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 7519508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7529508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 75366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 75466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 765a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 766d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 7673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 7683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 771d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 772a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 773a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 774a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 775a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 776a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 777a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 778a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 779a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 780a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 781a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 7913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 795ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 796ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 797ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 798ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 799ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 800ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 801ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 8025c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 80429a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 80529a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 8064c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 80729a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 809a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 810a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 811a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 812a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 813a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 814a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 816a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 83131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final float leftWidthNeeded = 2.f - curItem.widthFactor; 832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 83331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 836a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 837a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 8534c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 854d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 855d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight >= 2.f && pos > endPos) { 862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 879a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 881d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 885d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8864c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 8874c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 8884c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 8894c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 891d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 892d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 8942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 8955c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 8962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Check width measurement of current pages. Update LayoutParams as needed. 898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 907a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 908a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 909a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 910a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 9112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 9122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 913218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 9142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 9152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 9162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 9172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 9182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 9192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(FOCUS_FORWARD)) { 9202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 9212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 927d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 9396bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 948a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 967a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 98431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 98531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 1003a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 100431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 100531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 100631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1013a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 10147dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 10157dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 10167dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 10177dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 10187dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 10197dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1022ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 10235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1024d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10255c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1027d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1032d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 10335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1035d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1036d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1037d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1041d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1042d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 10445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 10455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 10475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 10485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10495c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 10515c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 10525c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 10545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 10555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1056d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 10575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 10585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1059ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 10605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 10615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 10625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1066d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1067d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1068d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1069d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1070d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1071677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1072677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1073677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1074d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1075d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1076d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1077d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1078d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1079d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1080d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1081d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1082d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1083d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1084d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1085d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1086d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1087d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 10885c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1089d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1090d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1091d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1092ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 10935c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 10988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 10991ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 11001ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 11011ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 11021ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 11031ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 11058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 11068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 11078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1108a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1117d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1126ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1133218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1134218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1135218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1136218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1137218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1138218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1139218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1140218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1141218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1142218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1143218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1155ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1156ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 115797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1158ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1159ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1160ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // For simple implementation, or internal size is always 0. 1163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11708f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int measuredWidth = getMeasuredWidth(); 11718f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int maxGutterSize = measuredWidth / 10; 11728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); 11738f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 11758f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); 11768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 11778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 11798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 11808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 11818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 11828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1183862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 11848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 11858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 11868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 11878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 11898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 11908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 11918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 11928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 11938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 11948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 11958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 11978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 11988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 11998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 12008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1207a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1209a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1210a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1211a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1212a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1213a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1214a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1217a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 12188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 12198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 12218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 12228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 12238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 12248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 12308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1236d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1238862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1239d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1240d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1241d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1242d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 12438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 12448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1248a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1249a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 12508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1251d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1252d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1253d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1254d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1255d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1259d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1260053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1261329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1262329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1263329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1264329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1265329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 126691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 12678d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int widthWithMargin = width + margin; 12685f6568e7e269783e2668527461878cadfbe65215Adam Powell final int oldWidthWithMargin = oldWidth + oldMargin; 12698d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int xpos = getScrollX(); 12705f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 12715f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1272a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 12735f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1274329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1275329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1276329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1277a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 12785f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 12798d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell (int) (targetInfo.offset * width), 0, newDuration); 1280329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1281329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1282a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 12838d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; 12848d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int scrollPos = (int) (scrollOffset * width); 1285329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 1286329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell completeScroll(); 1287053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 12889bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1291d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1292d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1293d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1294d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 13018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 13028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 13038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 13048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 13058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 13068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1309a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1310a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 13128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 13138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 13148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 13348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 13358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 13388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 13428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 13448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 13468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 13478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 13488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 13508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 13518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 13528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1355abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1356abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1357abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1358a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1359a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1360a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1361a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1362a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1363a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1364a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1365a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1366a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1367a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1368a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1369a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1370a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int loff = (int) (width * ii.offset); 1371a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1372a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1373a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1374a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1375a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1376a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1377a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1378a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) ((width - paddingLeft - paddingRight) * lp.widthFactor), 1379a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1380a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1381a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1382a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1383a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1384a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 13858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 13878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1388abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1389abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1390abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 13918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 13968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 139797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1401d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1402a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1403a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1406a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 14073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1409a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 14104783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 14114783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 14124783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 14134783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1414d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1417b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 14204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 14214c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 142247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 1423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1424d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 14254783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 14264783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 14274783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 14284783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 14294783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 14304783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 14314783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 14324783095cc69fa85e484132337526c94d42d41c43Adam Powell } 14334783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 14344783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1435a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1436a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1437a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1438a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1439a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1440a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1441a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1442a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1445a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 14498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14504783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 14948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 14958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 14988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 15078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 15088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 15108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 15118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 151547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void completeScroll() { 15168d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; 1517cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 15184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 15194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1527d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 152847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_IDLE); 15294c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 15314c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 15324c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 15334c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 15344c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 15354c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 15364c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15374c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 15394c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn populate(); 1540d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1541d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1542d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 15438f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean isGutterDrag(float x, float dx) { 15448f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); 15458f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell } 15468f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1547d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1548d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1549d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1550d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1551d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1555d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1556d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1557d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1558d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1560d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1561d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1562d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 15643ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 15653ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 15663ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 15673ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1569d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1570d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1571d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1573d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1574d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1575d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1576d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1577d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1578d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1579d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1580d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1584d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1585d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1586d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1587d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1588d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1589d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1590d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1591d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1595d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1596d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1597d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1598d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1599d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1600d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1601d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 160347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 160447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 160647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 1607d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1608bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 16098f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && 16108f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell canScroll(this, false, (int) dx, (int) x, (int) y)) { 1611bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 1612bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mInitialMotionX = mLastMotionX = x; 1613bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1614b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1615bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1616bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 1617d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (xDiff > mTouchSlop && xDiff > yDiff) { 1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 162047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 16218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : 16228d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 1623d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 1624d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1625d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (yDiff > mTouchSlop) { 1626d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // The finger has moved enough in the vertical 1627d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // direction to be counted as a drag... abort 1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // any attempt to drag horizontally, to work correctly 1629d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // with children that have scrolling containers. 1630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 1631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = true; 1632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 16346e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (mIsBeingDragged) { 16356e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Scroll to follow the motion event 16366e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (performDrag(x)) { 16376e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell ViewCompat.postInvalidateOnAnimation(this); 16386e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 16396e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 1640d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1641d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1642d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1643d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1644d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1645d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1646d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1647d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1648d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1649d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionY = ev.getY(); 1650d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1651b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1652d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.computeScrollOffset(); 1654b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1655b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 165647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 16578d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 16588d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 16598d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 166047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 166147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 166247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 166347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 166447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 166547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1666d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1667d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1668d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1669d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1672d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1673d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1674d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1675d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1676d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1677d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16788d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell if (mVelocityTracker == null) { 16798d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker = VelocityTracker.obtain(); 16803ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 16818d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker.addMovement(ev); 16823ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 16843ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 16853ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 16863ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1689d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 169269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 169369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 169469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 169569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 169669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 169769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1701d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1702d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1703d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1704d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 17053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 17063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 17073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 17083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 17093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1710d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1711d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1712d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1713d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1714d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1715d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1716560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1717d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 17208d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 17218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 17228d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 17238d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mIsBeingDragged = true; 17248d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell setScrollState(SCROLL_STATE_DRAGGING); 1725d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1726d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1727d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1728d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1729d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1730d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1731d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 17323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 17333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 17343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 173547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 17363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 173747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 17383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 17393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 17403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 17413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 17428d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : 17438d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 174447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 17453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 17463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 17473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 174831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1749d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1750d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1751d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1752d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1753d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 17546e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate |= performDrag(x); 1755d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1756d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1757d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1758d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1759d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 1760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 17611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 1764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 17651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 1766a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1767a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1768a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 1769035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 1770035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 1771035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 1772035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 1773035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 1774035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 17751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 1776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1778d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1779560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mCurItem, true, true); 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1787560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1796d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1797d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1798d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1803560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1804b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1805560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18096e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell private boolean performDrag(float x) { 18106e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean needsInvalidate = false; 18116e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18126e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final float deltaX = mLastMotionX - x; 18136e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX = x; 18146e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18156e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float oldScrollX = getScrollX(); 18166e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float scrollX = oldScrollX + deltaX; 18176e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final int width = getWidth(); 18186e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18196e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float leftBound = width * mFirstOffset; 18206e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float rightBound = width * mLastOffset; 18216e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean leftAbsolute = true; 18226e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean rightAbsolute = true; 18236e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18246e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo firstItem = mItems.get(0); 18256e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 18266e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (firstItem.position != 0) { 18276e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftAbsolute = false; 18286e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftBound = firstItem.offset * width; 18296e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18306e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (lastItem.position != mAdapter.getCount() - 1) { 18316e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightAbsolute = false; 18326e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightBound = lastItem.offset * width; 18336e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18346e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18356e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (scrollX < leftBound) { 18366e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (leftAbsolute) { 18376e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = leftBound - scrollX; 18386e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 18396e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18406e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = leftBound; 18416e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } else if (scrollX > rightBound) { 18426e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (rightAbsolute) { 18436e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = scrollX - rightBound; 18446e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 18456e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18466e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = rightBound; 18476e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18486e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Don't lose the rounded component 18496e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX += scrollX - (int) scrollX; 18506e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollTo((int) scrollX, getScrollY()); 18516e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell pageScrolled((int) scrollX); 18526e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 18536e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell return needsInvalidate; 18546e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18556e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 1856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 1857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 1858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 1859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 1860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 1861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 1863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 1865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 1866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 1867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 1868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1869ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 1870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 1873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 1874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 1875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 1876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 1877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 1878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 1879a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 1880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 1882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 18838d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float leftBound = offset; 18848d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset; 1885ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 1886ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 1887ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 1888ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 1889ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 1890ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1892a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 1893a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 1894a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 1895a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 1896ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 1897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1899ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1902035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 1903035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 1904035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 1905035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 1906035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 1907035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = (int) (currentPage + pageOffset + 0.5f); 1908035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1909035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1910a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 1911a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 1912a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 1913a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 1915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 1916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1918035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 1919035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1920035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1921560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 1922560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 1923560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 1924560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1925560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1926560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 1927560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 1928560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 1929560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 1930560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 1931560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1932560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1934560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1935560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 1936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 1937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 1938560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 1939560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1940560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1941560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 1942560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1943560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 1944560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1945560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1946560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 1947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 1948560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 1949560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 1950560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1951560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1952560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 1953560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 1954560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 1955560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1956560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1957560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1958560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 1959b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1960560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1961560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1962560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1963329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 1964329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 1965329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 1966329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1967a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 1968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 1969329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 1970329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 1971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 1975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 1976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 1978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 1979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 1980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 1981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 1982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 198423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 1985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 198623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 1987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 1988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 199023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 1991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 1992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 1995a56d6faa9df608aaa2907864669800abb68acec7Adam Powell mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, 199623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 1997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 1998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 2001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 2002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2003329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2004329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2005329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2006329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 200769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 200869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 200969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 201069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 201169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 201269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 201369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 201469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 201569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 201669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 201769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 201869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 201969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 202069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 202169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 202269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 202369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 202469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 202569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 202669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 202769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 202869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 202969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 203069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 203169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 203269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 203369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 203469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 203569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 203669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 203769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 203869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 203969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 204069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 204169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 204269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 204369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 204469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 204569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 204669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 204769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 204869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 204969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 205069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 205169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 205269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 205369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 205469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 205569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 205669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 20570f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 205869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 205969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2061035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2062a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2063a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2064a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2065a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2066a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2067a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2068035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 206969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 207069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 207169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 207269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 207369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 207469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 207569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 207669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 207769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 207869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 207969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 208069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 208169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 208269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 208369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 208469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 208569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 208669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2087a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2088a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 20890f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 209069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final int width = getWidth(); 209169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2092a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2093a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2094a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2095a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2096a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2097a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2098a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2099a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2100a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2101a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 210469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 210569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 210669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 210769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 210869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 210969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 211069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 211169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 21128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 211369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 211469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 211569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 211669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 211769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 211869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 211969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 212069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 212169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 212269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 212369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 212469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 212569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 212669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 212769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 212869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 212969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 213069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 213169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 213269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 213369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 213469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2135d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2136d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2138d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2139d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2141d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 21743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2175bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2176cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2177bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2178bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2179bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2180bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2181bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2182cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2183bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2184cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2185bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2186cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2187bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2188bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2189bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2190bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2191bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2192bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2193bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2194bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2195bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2196bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2197bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2198bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2199bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2200bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2201bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2202bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2203bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2204bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2205bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2206bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2207bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2208bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2209481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 22102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 22112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 22122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 22132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 22162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 22172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 22182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 22192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 22202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 22212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 22222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 22232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 22242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 22252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 22262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 22272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 22282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 22292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 22312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 22322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 22345de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 22355de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 22365de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 22375de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 22385de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 22395de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 22405de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 22415de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 22422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 22502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 22512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused == this) currentFocused = null; 22522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 22542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 22562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 22572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 22582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 22592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 22602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 2261dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2262dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2263dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft >= currLeft) { 22642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 22692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 22702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 2271dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2272dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2273dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft <= currLeft) { 22742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 22802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 22812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 22832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 22842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 22872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 22882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 2292dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { 2293dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (outRect == null) { 2294dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect = new Rect(); 2295dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2296efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell if (child == null) { 2297efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell outRect.set(0, 0, 0, 0); 2298efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell return outRect; 2299efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell } 2300dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left = child.getLeft(); 2301dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right = child.getRight(); 2302dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top = child.getTop(); 2303dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom = child.getBottom(); 2304dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2305dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell ViewParent parent = child.getParent(); 2306dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell while (parent instanceof ViewGroup && parent != this) { 2307dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final ViewGroup group = (ViewGroup) parent; 2308dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left += group.getLeft(); 2309dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right += group.getRight(); 2310dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top += group.getTop(); 2311dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom += group.getBottom(); 2312dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2313dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell parent = group.getParent(); 2314dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2315dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell return outRect; 2316dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2317dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 23182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 23192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 23202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 23212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 23222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 23242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2327218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 23282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 23292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 23302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 23322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 23362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 23392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 23402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 23422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 23442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 23452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 23462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 23502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 23562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 23572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 23582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 23592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 23602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 23612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 23622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 23632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 23642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 23652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 23662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 23672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 23692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 23702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 23712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 23732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 23742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 23802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 23832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 23842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 23852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 23862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 23872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 23882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 23922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 23992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 24002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 24012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 24022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 24032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 24042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 24052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 24062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 24072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 24082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 24092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 24102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 24112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 24122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 24132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 24142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 24152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 24172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 24182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 24192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 24202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 24212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(direction, previouslyFocusedRect)) { 24222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 24232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2426481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 24272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2428481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2429481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2430481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2431481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2432481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // ViewPagers should only report accessibility info for the current page, 2433481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // otherwise things get very confusing. 2434481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2435481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // TODO: Should this note something about the paging container? 2436481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2437481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2438481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2439481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2440481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2441481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2442481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2443481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2444481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2445481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2446481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2447481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2448481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2449481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2450481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2451481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 24528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 24548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 24558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 24598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 24608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 24648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 24658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 24691ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 24708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 247225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov class MyAccessibilityDelegate extends AccessibilityDelegateCompat { 247325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 247425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 247525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 247625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityEvent(host, event); 247725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov event.setClassName(ViewPager.class.getName()); 247825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 247925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 248025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 248125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 248225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(host, info); 248325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setClassName(ViewPager.class.getName()); 248425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setScrollable(mAdapter != null && mAdapter.getCount() > 1); 248525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 248625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 248725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 248825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 248925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 249025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 249125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 249225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 249325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 249425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public boolean performAccessibilityAction(View host, int action, Bundle args) { 249525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (super.performAccessibilityAction(host, action, args)) { 249625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 249725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 249825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov switch (action) { 249925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { 250025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) { 250125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem + 1); 250225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 250325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 250425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 250525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { 250625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) { 250725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem - 1); 250825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 250925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 251025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 251125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 251225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return false; 251325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 251425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 251525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 25168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 25178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 25188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 25198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 25208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 25213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 25228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 25233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 25243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 25253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 25268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 25277dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 25287dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 25297dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 25307dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 25318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 25328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 25338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 25348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 25358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 25368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 25378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2538a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 25393d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 25407dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 25417dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2542a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 25438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 25448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2545a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2546a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2547a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2548a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public float widthFactor = 0.f; 2549a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2550a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2551a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2552a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2553a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2554a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public boolean needsMeasure; 2555a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 25568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 25578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 25588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 25598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 25608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 25618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 25628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 25638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2564a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 25658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 25668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 25678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2569