ViewPager.java revision d84ef6c972b75c0ddeee88db2d66d40fff7519a8
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; 26d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel; 27d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable; 2869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock; 295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat; 305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks; 31560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat; 32d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet; 33d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log; 342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder; 358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity; 362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent; 37d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent; 382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants; 39d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker; 40d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View; 41d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration; 42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup; 43218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent; 44481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent; 451cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator; 46d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller; 47d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 48d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList; 4966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections; 5066c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator; 51d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 52d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/** 53d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right 545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data. You supply an implementation of a 555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows. 565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * 575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and 585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development. The API will likely change in later updates of 595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code 605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p> 617dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 627dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, 637dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page. 647dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager, 657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases. These are 667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter}, 677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter}, 687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and 697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these 707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface 717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them. 727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction 747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs. You can find other examples of using 757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java 787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * complete} 79d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 80ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup { 813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private static final String TAG = "ViewPager"; 82d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean DEBUG = false; 83d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 84d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean USE_CACHE = false; 85d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8629a6184d74279156a9297dc67398712fb047fdc0Adam Powell private static final int DEFAULT_OFFSCREEN_PAGES = 1; 871cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final int MAX_SETTLE_DURATION = 600; // ms 88035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private static final int MIN_DISTANCE_FOR_FLING = 25; // dips 8929a6184d74279156a9297dc67398712fb047fdc0Adam Powell 908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private static final int[] LAYOUT_ATTRS = new int[] { 918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell android.R.attr.layout_gravity 928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell }; 938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 94d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn static class ItemInfo { 95ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Object object; 96d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 974c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn boolean scrolling; 98a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor; 99a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ 10366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham @Override 10466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham public int compare(ItemInfo lhs, ItemInfo rhs) { 10566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham return lhs.position - rhs.position; 106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell }; 10866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 1091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final Interpolator sInterpolator = new Interpolator() { 1101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell public float getInterpolation(float t) { 1111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell t -= 1.0f; 112035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return t * t * t * t * t + 1.0f; 1131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 1141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell }; 1151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); 117a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private final ItemInfo mTempItem = new ItemInfo(); 118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 119ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private PagerAdapter mAdapter; 1203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private int mCurItem; // Index of currently displayed page. 121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mRestoredCurItem = -1; 122ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private Parcelable mRestoredAdapterState = null; 1235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn private ClassLoader mRestoredClassLoader = null; 124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private Scroller mScroller; 1258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private PagerObserver mObserver; 126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 127329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private int mPageMargin; 128329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private Drawable mMarginDrawable; 1298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mTopPageBounds; 1308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mBottomPageBounds; 131329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Offsets of the first and last items, if known. 133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Set during population, used to determine if we are at the beginning 134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // or end of the pager data set during touch scrolling. 135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mFirstOffset = -Float.MAX_VALUE; 136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mLastOffset = Float.MAX_VALUE; 137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 138d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildWidthMeasureSpec; 139d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildHeightMeasureSpec; 140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mInLayout; 141d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mScrollingCacheEnabled; 143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mPopulatePending; 1454c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn private boolean mScrolling; 14629a6184d74279156a9297dc67398712fb047fdc0Adam Powell private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; 147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsBeingDragged; 149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsUnableToDrag; 150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mTouchSlop; 151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mInitialMotionX; 152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Position of the last motion event. 154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionX; 156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionY; 157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ID of the active pointer. This is used to retain consistency during 159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * drags/flings if multiple pointers are used. 160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mActivePointerId = INVALID_POINTER; 162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Sentinel value for no current active pointer. 164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Used by {@link #mActivePointerId}. 165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final int INVALID_POINTER = -1; 167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Determines speed during touch scrolling 170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private VelocityTracker mVelocityTracker; 172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMinimumVelocity; 173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMaximumVelocity; 174035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int mFlingDistance; 175b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private int mCloseEnough; 176b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell 177b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // If the pager is at least this close to its final position, complete the scroll 178b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // on touch down and let the user interact with the content inside instead of 179b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // "catching" the flinging pager. 180b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private static final int CLOSE_ENOUGH = 2; // dp 181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private boolean mFakeDragging; 18369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private long mFakeDragBeginTime; 18469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 185560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mLeftEdge; 186560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mRightEdge; 187560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 18897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell private boolean mFirstLayout = true; 189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private boolean mNeedCalculatePageOffsets = false; 1908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private boolean mCalledSuper; 1918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mDecorChildCount; 19297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 1933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private OnPageChangeListener mOnPageChangeListener; 1948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnPageChangeListener mInternalPageChangeListener; 1958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnAdapterChangeListener mAdapterChangeListener; 1963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 19847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in an idle, settled state. The current page 19947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * is fully in view and no animation is in progress. 20047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 20147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_IDLE = 0; 20247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 20347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 20447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is currently being dragged by the user. 20547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 20647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_DRAGGING = 1; 20747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 20847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 20947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in the process of settling to a final position. 21047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 21147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_SETTLING = 2; 21247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private int mScrollState = SCROLL_STATE_IDLE; 21447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 21547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 2163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Callback interface for responding to changing state of the selected page. 2173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public interface OnPageChangeListener { 21947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 2203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * This method will be invoked when the current page is scrolled, either as part 2223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 2233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the first page currently being displayed. 2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 2263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 2273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffsetPixels Value in pixels indicating the offset from position. 2283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); 2303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 23247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * This method will be invoked when a new page becomes selected. Animation is not 23347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * necessarily complete. 2343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the new selected page. 2363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position); 23847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 23947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Called when the scroll state changes. Useful for discovering when the user 24147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * begins dragging, when the pager is automatically settling to the current page, 24247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * or when it is fully stopped/idle. 24347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * 24447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @param state The new scroll state. 24547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_IDLE 24647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_DRAGGING 24747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_SETTLING 24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state); 2503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Simple implementation of the {@link OnPageChangeListener} interface with stub 2543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * implementations of each method. Extend this if you do not intend to override 2553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * every method of {@link OnPageChangeListener}. 2563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public static class SimpleOnPageChangeListener implements OnPageChangeListener { 2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position) { 2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 26747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 26847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell @Override 26947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state) { 27047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // This space for rent 27147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 2758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Used internally to monitor when adapters are switched. 2768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 2778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell interface OnAdapterChangeListener { 2788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); 2798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2811ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell /** 2821ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * Used internally to tag special types of child views that should be added as 2831ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * pager decorations by default. 2841ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell */ 2851ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell interface Decor {} 2861ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell 287ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context) { 288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context); 28947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 291d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 292ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context, AttributeSet attrs) { 293d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context, attrs); 29447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 29747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell void initViewPager() { 298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setWillNotDraw(false); 2992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 3002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setFocusable(true); 301560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final Context context = getContext(); 3021cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller = new Scroller(context, sInterpolator); 3031cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 307560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge = new EdgeEffectCompat(context); 308560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge = new EdgeEffectCompat(context); 3091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 310035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float density = context.getResources().getDisplayMetrics().density; 311035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); 312b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mCloseEnough = (int) (CLOSE_ENOUGH * density); 313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 31547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void setScrollState(int newState) { 31647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mScrollState == newState) { 31747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell return; 31847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 31947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 32047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mScrollState = newState; 32147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mOnPageChangeListener != null) { 32247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageScrollStateChanged(newState); 32347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 32447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 32547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 3268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a PagerAdapter that will supply views for this pager as needed. 3288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 3298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param adapter Adapter to use 3308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 331ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public void setAdapter(PagerAdapter adapter) { 3323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter != null) { 3338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.unregisterDataSetObserver(mObserver); 3340d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.startUpdate(this); 3350d6d2990ddacd3f419879149137f09a30c061436Minh Pham for (int i = 0; i < mItems.size(); i++) { 3360d6d2990ddacd3f419879149137f09a30c061436Minh Pham final ItemInfo ii = mItems.get(i); 3370d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.destroyItem(this, ii.position, ii.object); 3380d6d2990ddacd3f419879149137f09a30c061436Minh Pham } 3390d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.finishUpdate(this); 3400d6d2990ddacd3f419879149137f09a30c061436Minh Pham mItems.clear(); 341a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeNonDecorViews(); 3420d6d2990ddacd3f419879149137f09a30c061436Minh Pham mCurItem = 0; 343871a68b5daafd810623d680207652f87eb2d11ccMinh Pham scrollTo(0, 0); 3443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final PagerAdapter oldAdapter = mAdapter; 347d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mAdapter = adapter; 348d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 349d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 3503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mObserver == null) { 3518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mObserver = new PagerObserver(); 3523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.registerDataSetObserver(mObserver); 354d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 35591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell mFirstLayout = true; 356d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mRestoredCurItem >= 0) { 3575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 358d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mRestoredCurItem, false, true); 359d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = -1; 360ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = null; 3615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = null; 362d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 363d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 3668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 3678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mAdapterChangeListener != null && oldAdapter != adapter) { 3688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 3698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 372a7aea206661d601755bfac4165092d9130cba2bcAdam Powell private void removeNonDecorViews() { 373a7aea206661d601755bfac4165092d9130cba2bcAdam Powell for (int i = 0; i < getChildCount(); i++) { 374a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final View child = getChildAt(i); 375a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 376a7aea206661d601755bfac4165092d9130cba2bcAdam Powell if (!lp.isDecor) { 377a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeViewAt(i); 378a7aea206661d601755bfac4165092d9130cba2bcAdam Powell i--; 379a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 380a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 381a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 382a7aea206661d601755bfac4165092d9130cba2bcAdam Powell 3838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Retrieve the current adapter supplying pages. 3858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 3868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The currently registered PagerAdapter 3878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 388ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public PagerAdapter getAdapter() { 389d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mAdapter; 390d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 3928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell void setOnAdapterChangeListener(OnAdapterChangeListener listener) { 3938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener = listener; 3948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 3958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 39697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 39797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. If the ViewPager has already been through its first 39891eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * layout with its current adapter there will be a smooth animated transition between 39991eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * the current item and the specified item. 40097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 40197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 40297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void setCurrentItem(int item) { 404d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 40597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, !mFirstLayout, false); 40697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell } 40797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 40897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 40997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. 41097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 41197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 41297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately 41397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 41497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell public void setCurrentItem(int item, boolean smoothScroll) { 41597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mPopulatePending = false; 41697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, smoothScroll, false); 417d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 419bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki public int getCurrentItem() { 420bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki return mCurItem; 421bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki } 422bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki 423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { 4241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(item, smoothScroll, always, 0); 4251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 4261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 4271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { 428d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null || mAdapter.getCount() <= 0) { 429d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 430d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 431d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 432d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!always && mCurItem == item && mItems.size() != 0) { 433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (item < 0) { 437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = 0; 438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else if (item >= mAdapter.getCount()) { 439d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = mAdapter.getCount() - 1; 440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 44129a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 44229a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { 4434c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // We are doing a jump by more than one page. To avoid 4444c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // glitches, we want to keep all current pages in the view 4454c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // until the scroll ends. 4464c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 4474c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mItems.get(i).scrolling = true; 4484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 4494c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 45047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final boolean dispatchSelected = mCurItem != item; 451a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(item); 452a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo curInfo = infoForPosition(item); 45331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell int destX = 0; 45431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (curInfo != null) { 45531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int width = getWidth(); 45631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell destX = (int) (width * Math.max(mFirstOffset, 45731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell Math.min(curInfo.offset, mLastOffset))); 45831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (smoothScroll) { 4601cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(destX, 0, velocity); 46147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 46247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageSelected(item); 46347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 4648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 467d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 46847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 4693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener.onPageSelected(item); 4703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 4728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 4738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 47447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 475329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell scrollTo(destX, 0); 476d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 477d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 478d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 4818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 4848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 4853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 4863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 4873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 489d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 4908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 4918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 4938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 4948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 4958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 4968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 5018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 50229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 50329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 50429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 50529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 50629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 50729a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 50829a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 50929a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 51029a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 51129a6184d74279156a9297dc67398712fb047fdc0Adam Powell 51229a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 51329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 51429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 51529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 51629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 51729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 51829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 51929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 52029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 52129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 52229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 52329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 52429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 52529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 52629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 52929a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 53029a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 53129a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 53229a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 53329a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 53429a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 53529a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 53629a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 53729a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 53829a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 53929a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 54029a6184d74279156a9297dc67398712fb047fdc0Adam Powell 54129a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 542329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 543329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 544329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 545329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 546329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 547329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 548329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 549329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 550329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 551329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 552329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 553329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 554329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 555329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 556329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 557329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 558329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 559329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 560329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 561329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 562329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 563329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 564329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 565329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 566329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 567329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 568329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 569329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 570329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 571329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 572329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 573329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 574329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 575329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 576329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 577329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 578329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 579329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 581329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 582329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 583329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 584329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 585329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 586329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 587329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 588329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 589329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 590329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 591329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 592329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 593329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 594329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 595329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 596329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 597329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 598329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 599329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 600329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 601329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 602329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 6031cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 6041cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 6051cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 6061cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 6071cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 6081cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 6091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 6101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 6111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6121cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 613329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 614d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 615d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 616cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 617cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 6201cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 6211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 6241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 6251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 6261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 6271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 6281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 6291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 6301cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 6383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 6393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 6403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 64147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 64231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 6433040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 6443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 6453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 6463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 6484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mScrolling = true; 64947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 6501cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 651035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int width = getWidth(); 652035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 653035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 654035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 655035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 6561cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 657035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 6581cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 6591cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 660035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 6611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 662a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 663a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 664035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 6651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 6661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 6671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 6681cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 669b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 672a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 673d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 674d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 6755c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 676a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 677a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 678d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 679d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 682a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 684d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 6853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 6863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 6873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6881a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 6891a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell mItems.size() < mAdapter.getCount(); 6901e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 6913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6929508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 6933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 6943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 6953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 6963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 6973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 6983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 6993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 7023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 7033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 7049508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7059508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 7069508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 7079508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 7089508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7099508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 7103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 7113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 7143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 7153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); 7161a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 7173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 7193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 7223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 7233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 7243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 7253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 7283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 7293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 7329508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 7339508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 7349508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 7359508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 73666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 73766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 738a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 739a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 740a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 741a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 742a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 743a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 744a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 745a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 746a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 747a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 748a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 749d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 7503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 7513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 7533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 754d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 766d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 767d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 768d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 769d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 770d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 771d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 773d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 7743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 775d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 778ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 779ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 780ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 781ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 782ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 783ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 784ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 7855c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 78729a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 78829a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 7894c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 79029a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 792a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 793a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 794a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 795a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 796a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 797a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 798a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 799a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 800a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 801a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 803a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 804a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 805a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 806a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 807a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 808a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 809a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 810a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 811a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 812a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 813a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 81431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final float leftWidthNeeded = 2.f - curItem.widthFactor; 815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 81631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 831a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 8364c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight >= 2.f && pos > endPos) { 845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 854a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 864d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 867d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 868d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8694c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 8704c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 8714c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 8724c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 873d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 874d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 875d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 8772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 8785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 8792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Check width measurement of current pages. Update LayoutParams as needed. 881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 884a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 885a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 886a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 887a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 888a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 889a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 890a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 892a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 893a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 8942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 8952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 896218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 8972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 8982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 8992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 9002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 9012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 9022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(FOCUS_FORWARD)) { 9032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 9042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 9082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 909d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 910d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 911a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 912a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 913a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 918a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 919a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 921a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 9226bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 926a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 927a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 939a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 948a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 96731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 96831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 98731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 98831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 98931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 9977dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 9987dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 9997dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 10007dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 10017dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 10027dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1003d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1004d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1005ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 10065c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1007d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10085c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1009d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1010d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1011d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1012d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1013d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1014d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1015d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 10165c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1017d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1018d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1019d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1024d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10265c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 10275c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 10285c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 10305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 10315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 10335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 10345c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 10355c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 10365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 10375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 10385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 10405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 10415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1042ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 10435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 10445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 10455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1046d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1047d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1048d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1049d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1050d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1051d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1052d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1053d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1054677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1055677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1056677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1058d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1059d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1060d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1061d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1062d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1066d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1067d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1068d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1069d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1070d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 10715c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1072d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1073d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1074d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1075ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 10765c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1077d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1078d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1079d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1080d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 10818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 10821ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 10831ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 10841ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 10851ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 10861ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1087d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 10888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 10898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 10908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1091a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1092d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1093d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1098d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1099d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1106d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1107d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1109ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1116218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1117218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1118218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1119218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1120218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1121218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1122218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1123218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1124218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1125218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1126218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1138ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1139ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 114097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1141ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1142ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1143ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // For simple implementation, or internal size is always 0. 1146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 11548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childWidthSize = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 11558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 11568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 11588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 11598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 11608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 11618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1162862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 11638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 11648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 11658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 11668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 11688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 11698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 11708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 11718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 11728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 11738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 11748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 11768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 11778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 11788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 11798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 11808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1182a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1183a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1186a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1187a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 11978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 11988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 11998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 12008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 12018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 12028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 12038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 12078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 12098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1210d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1211d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1212d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1214d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1215d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1217862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1218d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1219d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 12228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 12238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1228a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1236d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1237d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1238d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1239053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1240329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1241329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1242329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1243329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1244329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 12455f6568e7e269783e2668527461878cadfbe65215Adam Powell final int widthWithMargin = width + margin; 124691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 1247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int xpos = getScrollX(); 12485f6568e7e269783e2668527461878cadfbe65215Adam Powell final int oldWidthWithMargin = oldWidth + oldMargin; 12495f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 12505f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1251a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 12525f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1253329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1254329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1255329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1256a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 12575f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 12585f6568e7e269783e2668527461878cadfbe65215Adam Powell (int) (targetInfo.offset * widthWithMargin), 0, newDuration); 1259329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1260329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1261a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 126231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell final int scrollPos = 12635f6568e7e269783e2668527461878cadfbe65215Adam Powell (int) ((ii != null ? Math.min(ii.offset, mLastOffset) : 0) * widthWithMargin); 1264329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 1265329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell completeScroll(); 1266053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 12679bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1273d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1274d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1275d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1276d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1277d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 12788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 12798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 12808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 12818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 12828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 12838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 12848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 12858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 12868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1287d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1288a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1289a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 12918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 12928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 12938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 12958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 12968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 12978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 13048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 13058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 13068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 13088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 13098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 13108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 13128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 13138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 13148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 13238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1334abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1335abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1336abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1337a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1338a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1339a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1340a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1341a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1342a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1343a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1344a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int loff = (int) (width * ii.offset); 1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1355a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1356a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1357a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) ((width - paddingLeft - paddingRight) * lp.widthFactor), 1358a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1359a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1360a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1361a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1362a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1363a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 13648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 13658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 13668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1367abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1368abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1369abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 13708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1372d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 13738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 13748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 13758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 137697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1377d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1378d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1381a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1382a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1383a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1384a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1385a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 13863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1387a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1388a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 13894783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 13904783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 13914783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 13924783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1394a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1395a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1396b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1397a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 13994c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 14004c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 140147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 1402d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 14044783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 14054783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 14064783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 14074783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 14084783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 14094783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 14104783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 14114783095cc69fa85e484132337526c94d42d41c43Adam Powell } 14124783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 14134783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1419a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1420a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1421a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 14228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1424a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 14258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 14268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 14278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 14288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14294783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 14308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 14338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 14348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 14358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 14368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 14378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 14388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 14398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 14408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 14418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 14428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 14498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 14508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 149447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void completeScroll() { 1495cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham boolean needPopulate = mScrolling; 1496cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 14974c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 14984c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1499d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1500d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1501d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1502d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1503d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1504d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1505d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1506d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 150747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_IDLE); 15084c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 15103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mScrolling = false; 15114c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 15124c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 15134c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 15144c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 15154c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 15164c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15174c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 15184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 15194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn populate(); 1520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1527d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1528d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1529d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1530d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1531d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1532d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1533d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1534d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1535d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1536d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1537d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1538d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1539d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 15403ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 15413ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 15423ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 15433ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1544d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1545d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1546d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1547d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1548d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1549d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1550d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1551d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1555d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1556d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1557d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1558d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1560d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1561d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1562d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1564d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1565d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1566d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1567d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1569d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1570d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1571d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1573d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1574d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1575d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1576d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1577d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1578d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 157947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 158047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 158247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 1583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1584bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 1585560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (canScroll(this, false, (int) dx, (int) x, (int) y)) { 1586bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 1587bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mInitialMotionX = mLastMotionX = x; 1588bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1589b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1590bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1591bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (xDiff > mTouchSlop && xDiff > yDiff) { 1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 159547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 1596d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1597d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 1598d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1599d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (yDiff > mTouchSlop) { 1600d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // The finger has moved enough in the vertical 1601d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // direction to be counted as a drag... abort 1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // any attempt to drag horizontally, to work correctly 1603d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // with children that have scrolling containers. 1604d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = true; 1606d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1607d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1608d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1609d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1610d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1611d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1612d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1613d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1614d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1615d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1616d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1617d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionY = ev.getY(); 1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1619b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1620d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1621b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1622b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 162347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 162447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 162547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 162647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 162747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 162847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 162947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1638d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1639d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1640d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1641d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16423ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (!mIsBeingDragged) { 16433ce9274ccb8034c1787415c77307bbda36071bddAdam Powell // Track the velocity as long as we aren't dragging. 16443ce9274ccb8034c1787415c77307bbda36071bddAdam Powell // Once we start a real drag we will track in onTouchEvent. 16453ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker == null) { 16463ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = VelocityTracker.obtain(); 16473ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 16483ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.addMovement(ev); 16493ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 16503ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1651d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 16523ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 16533ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 16543ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1655d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1656d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1657d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1658d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1659d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 166069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 166169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 166269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 166369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 166469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 166569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1666d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1667d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1668d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1669d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1672d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 16743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 16753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 16763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 16773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1678d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1679d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1682d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1684560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1685d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1686d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1689d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If being flinged and user touches, stop the fling. isFinished 1690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * will be false if being flinged. 1691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 169247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell completeScroll(); 1693d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1694d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 1696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 17003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 17013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 17023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 170347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 17043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 170547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 17063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 17073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 17083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 17093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 17103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mLastMotionX = x; 171147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 17123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 17133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 17143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 171531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1716d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1717d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1720d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 172147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float deltaX = mLastMotionX - x; 1722d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1723560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float oldScrollX = getScrollX(); 1724560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float scrollX = oldScrollX + deltaX; 17253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int width = getWidth(); 172647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 1727a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 1728a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 1729a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean leftAbsolute = true; 1730a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean rightAbsolute = true; 1731a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1732a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 1733a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 1734a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 1735a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftAbsolute = false; 1736a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 1737a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1738a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 1739a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightAbsolute = false; 1740a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 1741a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1742a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 174347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (scrollX < leftBound) { 1744a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (leftAbsolute) { 1745a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float over = leftBound - scrollX; 1746a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 1747560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 174847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollX = leftBound; 174947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else if (scrollX > rightBound) { 1750a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (rightAbsolute) { 1751560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell float over = scrollX - rightBound; 1752a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 1753560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 175447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollX = rightBound; 1755d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 175647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Don't lose the rounded component 175747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mLastMotionX += scrollX - (int) scrollX; 175847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell scrollTo((int) scrollX, getScrollY()); 17598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 1760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1761d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 1765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 17661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 1767d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 1768d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 1769a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 17701cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 1771a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1772a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1773a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 1774035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 1775035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 1776035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 1777035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 1778035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 1779035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 17801cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1784560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mCurItem, true, true); 1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 1792560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 1796d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 1797d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 1798d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 1805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1808560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1809b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1810560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1814a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 1815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 1816a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 1817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 1818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 1819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 1821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 1823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 1824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 1825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 1826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1827ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 1828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 1831a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 1832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 1833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 1834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 1835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 1836a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 1837a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 1838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 1840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float leftBound = offset - 0.0001f; 1842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset + 0.0001f; 1843ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 1844ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 1845ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 1846ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 1847ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 1848ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 1851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 1852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 1853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 1854ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 1855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1857ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 1858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1860035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 1861035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 1862035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 1863035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 1864035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 1865035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = (int) (currentPage + pageOffset + 0.5f); 1866035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1867035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 1869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 1870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 1871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 1873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 1874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1876035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 1877035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 1878035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 1879560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 1880560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 1881560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 1882560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1883560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1884560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 1885560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 1886560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 1887560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 1888560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 1889560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1890560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 1892560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1893560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 1894a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 1895a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 1896560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 1897560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1898560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1899560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 1900560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 1901560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 1902560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 1903560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1904560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 1905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 1906560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 1907560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 1908560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 1909560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1910560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 1911560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 1912560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 1913560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1914560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1915560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 1916560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 1917b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1918560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1919560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 1920560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 1921329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 1922329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 1923329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 1924329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 1926a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 1927329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 1928329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 1929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 1933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 1934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 1936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 1937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 1938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 1939a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 1940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 194223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 1943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 194423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 1945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 1946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 194823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 1949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 1950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 195323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell mMarginDrawable.setBounds((int) (drawAt - 0.5f), mTopPageBounds, 195423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 1955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 1956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 1959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 1960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1961329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1962329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1963329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1964329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 196569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 196669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 196769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 196869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 196969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 197069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 197169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 197269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 197369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 197469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 197569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 197669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 197769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 197869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 197969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 198069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 198169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 198269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 198369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 198469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 198569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 198669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 198769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 198869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 198969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 199069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 199169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 199269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 199369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 199469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 199569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 199669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 199769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 199869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 199969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 200069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 200169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 200269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 200369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 200469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 200569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 200669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 200769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 200869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 200969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 201069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 201169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 201269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 201369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 201469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 20150f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 201669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 201769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2018a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2019035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2020a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2021a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2022a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2026035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 202769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 202869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 202969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 203069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 203169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 203269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 203369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 203469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 203569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 203669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 203769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 203869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 203969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 204069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 204169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 204269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 204369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 204469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 20470f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 204869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final int width = getWidth(); 204969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2051a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2052a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2053a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2054a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2055a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2056a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2057a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2058a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2059a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2061a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 206269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 206369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 206469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 206569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 206669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 206769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 206869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 206969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 20708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 207169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 207269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 207369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 207469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 207569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 207669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 207769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 207869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 207969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 208069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 208169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 208269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 208369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 208469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 208569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 208669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 208769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 208869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 208969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 209069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 209169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 209269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2093d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2098d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2099d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2106d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2107d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2117d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 21323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2133bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2134cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2135bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2136bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2137bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2138bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2139bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2140cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2141bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2142cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2143bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2144cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2145bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2146bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2147bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2148bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2149bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2150bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2151bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2152bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2153bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2154bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2155bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2156bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2157bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2158bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2159bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2160bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2161bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2162bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2163bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2164bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2165bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2166bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2167481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 21682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 21692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 21702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 21712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 21722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 21732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 21742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 21752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 21762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 21772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 21782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 21792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 21802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 21812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 21822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 21832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 21842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 21852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 21862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 21872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 21882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 21892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 21902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 21912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 21925de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 21935de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 21945de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 21955de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 21965de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 21975de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 21985de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 21995de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 22002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 22022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 22082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 22092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused == this) currentFocused = null; 22102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 22122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 22142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 22152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 22162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 22172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 22182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 22192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused != null && nextFocused.getLeft() >= currentFocused.getLeft()) { 22202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 22252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 22262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 22272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) { 22282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 22302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 22312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 22342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 22352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 22362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 22372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 22382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 22392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 22412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 22422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 22442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 22472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 22482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 22492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 22502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 22522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2255218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 22562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 22572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 22582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 22602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 22632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 22642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 22652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 22662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 22672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 22682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 22702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 22722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 22732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 22742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 22752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 22762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 22772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 22782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 22832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 22842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 22852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 22862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 22872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 22882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 22892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 22902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 22912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 22922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 22932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 22942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 22952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 22962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 22972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 22982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 22992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 23012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 23022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 23082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 23112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 23122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 23132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 23142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 23152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 23162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 23172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 23182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 23192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 23202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 23252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 23262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 23272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 23282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 23292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 23302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 23312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 23322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 23332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 23342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 23352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 23362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 23372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 23382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 23392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 23402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 23412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 23422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 23432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 23452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 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 if (child.requestFocus(direction, previouslyFocusedRect)) { 23502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 23512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 23532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2354481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 23552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2356481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2357481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2358481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2359481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2360481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // ViewPagers should only report accessibility info for the current page, 2361481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // otherwise things get very confusing. 2362481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2363481243c175651c5de0741ab9390eb10f5b024d98Adam Powell // TODO: Should this note something about the paging container? 2364481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2365481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2366481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2367481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2368481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2369481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2370481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2371481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2372481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2373481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2374481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2375481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2376481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2377481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2378481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2379481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 23808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 23818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 23828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 23838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 23848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 23858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 23868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 23878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 23888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 23898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 23908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 23918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 23928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 23938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 23948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 23958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 23968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 23971ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 23988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 23998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 24018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 24028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 24038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 24048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 24068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 24073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 24083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 24093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 24108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24117dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 24127dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 24137dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 24147dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 24158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 24168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 24178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 24188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 24198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 24208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 24218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2422a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 24233d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 24247dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 24257dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2426a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 24278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 24288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2429a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2430a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2431a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2432a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public float widthFactor = 0.f; 2433a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2434a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2435a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2436a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2437a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2438a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell public boolean needsMeasure; 2439a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 24408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 24418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 24428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 24458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 24468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 24478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2448a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 24498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 24508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 24518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 2452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2453