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; 20199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powellimport android.content.res.Resources; 218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray; 228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver; 23560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas; 24481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect; 25329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable; 265de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build; 2725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.os.Bundle; 28d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel; 29d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable; 3069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock; 315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat; 325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks; 33109e561bfa6720a7043a28dc265297d915170954Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityEventCompat; 3425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 35109e561bfa6720a7043a28dc265297d915170954Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityRecordCompat; 36560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat; 37d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet; 38d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log; 392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder; 408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity; 412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent; 42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent; 432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants; 44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker; 45d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View; 46d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration; 47d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup; 48218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent; 49481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent; 501cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator; 51d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller; 52d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 538a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powellimport java.lang.reflect.Method; 54d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList; 5566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections; 5666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator; 57d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 58d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/** 59d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right 605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data. You supply an implementation of a 615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows. 625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * 635c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and 645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development. The API will likely change in later updates of 655c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code 665c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p> 677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, 697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page. 707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager, 717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases. These are 7233586fb4d8b42d7c65240ffcc269fe10e682b309Scott Main * {@link android.support.v4.app.FragmentPagerAdapter} and 7333586fb4d8b42d7c65240ffcc269fe10e682b309Scott Main * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these 747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface 757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them. 767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction 787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs. You can find other examples of using 797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * 817dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java 827dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * complete} 83d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 84ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup { 853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private static final String TAG = "ViewPager"; 86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean DEBUG = false; 87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 88d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final boolean USE_CACHE = false; 89d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 9029a6184d74279156a9297dc67398712fb047fdc0Adam Powell private static final int DEFAULT_OFFSCREEN_PAGES = 1; 911cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final int MAX_SETTLE_DURATION = 600; // ms 92035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private static final int MIN_DISTANCE_FOR_FLING = 25; // dips 9329a6184d74279156a9297dc67398712fb047fdc0Adam Powell 948f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private static final int DEFAULT_GUTTER_SIZE = 16; // dips 958f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 9616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private static final int MIN_FLING_VELOCITY = 400; // dips 9716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell 988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private static final int[] LAYOUT_ATTRS = new int[] { 998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell android.R.attr.layout_gravity 1008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell }; 1018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 102199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell /** 103199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell * Used to track what the expected number of items in the adapter should be. 104199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. 105199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell */ 106199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell private int mExpectedAdapterCount; 107199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell 108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn static class ItemInfo { 109ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Object object; 110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1114c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn boolean scrolling; 112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor; 113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 11666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ 11766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham @Override 11866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham public int compare(ItemInfo lhs, ItemInfo rhs) { 11966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham return lhs.position - rhs.position; 120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell }; 12266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 1231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell private static final Interpolator sInterpolator = new Interpolator() { 1241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell public float getInterpolation(float t) { 1251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell t -= 1.0f; 126035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return t * t * t * t * t + 1.0f; 1271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 1281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell }; 1291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); 131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private final ItemInfo mTempItem = new ItemInfo(); 132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 133dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private final Rect mTempRect = new Rect(); 134dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 135ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private PagerAdapter mAdapter; 1363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private int mCurItem; // Index of currently displayed page. 137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mRestoredCurItem = -1; 138ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn private Parcelable mRestoredAdapterState = null; 1395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn private ClassLoader mRestoredClassLoader = null; 140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private Scroller mScroller; 1418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private PagerObserver mObserver; 142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 143329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private int mPageMargin; 144329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private Drawable mMarginDrawable; 1458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mTopPageBounds; 1468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mBottomPageBounds; 147329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Offsets of the first and last items, if known. 149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Set during population, used to determine if we are at the beginning 150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // or end of the pager data set during touch scrolling. 151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mFirstOffset = -Float.MAX_VALUE; 152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private float mLastOffset = Float.MAX_VALUE; 153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildWidthMeasureSpec; 155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mChildHeightMeasureSpec; 156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mInLayout; 157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mScrollingCacheEnabled; 159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mPopulatePending; 16129a6184d74279156a9297dc67398712fb047fdc0Adam Powell private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; 162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsBeingDragged; 164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private boolean mIsUnableToDrag; 1658f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean mIgnoreGutter; 1668f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mDefaultGutterSize; 1678f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private int mGutterSize; 168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mTouchSlop; 169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Position of the last motion event. 171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionX; 173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private float mLastMotionY; 17416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private float mInitialMotionX; 17516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell private float mInitialMotionY; 176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ID of the active pointer. This is used to retain consistency during 178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * drags/flings if multiple pointers are used. 179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mActivePointerId = INVALID_POINTER; 181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 182d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Sentinel value for no current active pointer. 183d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Used by {@link #mActivePointerId}. 184d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 185d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private static final int INVALID_POINTER = -1; 186d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 187d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 188d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Determines speed during touch scrolling 189d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 190d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private VelocityTracker mVelocityTracker; 191d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMinimumVelocity; 192d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private int mMaximumVelocity; 193035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int mFlingDistance; 194b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private int mCloseEnough; 195b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell 196b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // If the pager is at least this close to its final position, complete the scroll 197b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // on touch down and let the user interact with the content inside instead of 198b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell // "catching" the flinging pager. 199b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell private static final int CLOSE_ENOUGH = 2; // dp 200d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 20169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private boolean mFakeDragging; 20269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell private long mFakeDragBeginTime; 20369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 204560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mLeftEdge; 205560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell private EdgeEffectCompat mRightEdge; 206560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 20797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell private boolean mFirstLayout = true; 208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private boolean mNeedCalculatePageOffsets = false; 2098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private boolean mCalledSuper; 2108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private int mDecorChildCount; 21197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 2123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell private OnPageChangeListener mOnPageChangeListener; 2138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnPageChangeListener mInternalPageChangeListener; 2148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private OnAdapterChangeListener mAdapterChangeListener; 2158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private PageTransformer mPageTransformer; 2168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private Method mSetChildrenDrawingOrderEnabled; 2173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_DEFAULT = 0; 2197e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_FORWARD = 1; 2207e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final int DRAW_ORDER_REVERSE = 2; 2217e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private int mDrawingOrder; 2227e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private ArrayList<View> mDrawingOrderedChildren; 2237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); 2247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 22647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in an idle, settled state. The current page 22747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * is fully in view and no animation is in progress. 22847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 22947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_IDLE = 0; 23047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 23147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 23247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is currently being dragged by the user. 23347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 23447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_DRAGGING = 1; 23547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 23647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 23747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Indicates that the pager is in the process of settling to a final position. 23847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 23947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public static final int SCROLL_STATE_SETTLING = 2; 24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 24171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio private final Runnable mEndScrollRunnable = new Runnable() { 24271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio public void run() { 24371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio setScrollState(SCROLL_STATE_IDLE); 24471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio populate(); 24571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 24671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio }; 24771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio 24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private int mScrollState = SCROLL_STATE_IDLE; 24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 25047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 2513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Callback interface for responding to changing state of the selected page. 2523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public interface OnPageChangeListener { 25447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 2553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * This method will be invoked when the current page is scrolled, either as part 2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the first page currently being displayed. 2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param positionOffsetPixels Value in pixels indicating the offset from position. 2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); 2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 26747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * This method will be invoked when a new page becomes selected. Animation is not 26847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * necessarily complete. 2693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * 2703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * @param position Position index of the new selected page. 2713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position); 27347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 27447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell /** 27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * Called when the scroll state changes. Useful for discovering when the user 27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * begins dragging, when the pager is automatically settling to the current page, 27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * or when it is fully stopped/idle. 27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * 27947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @param state The new scroll state. 28047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_IDLE 28147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_DRAGGING 28247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell * @see ViewPager#SCROLL_STATE_SETTLING 28347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell */ 28447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state); 2853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell /** 2883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * Simple implementation of the {@link OnPageChangeListener} interface with stub 2893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * implementations of each method. Extend this if you do not intend to override 2903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell * every method of {@link OnPageChangeListener}. 2913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell */ 2923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public static class SimpleOnPageChangeListener implements OnPageChangeListener { 2933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 2953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 2963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 2973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 2993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void onPageSelected(int position) { 3003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This space for rent 3013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 30247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 30347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell @Override 30447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell public void onPageScrollStateChanged(int state) { 30547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // This space for rent 30647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 3073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 3083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 3098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 3108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * A PageTransformer is invoked whenever a visible/attached page is scrolled. 3118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * This offers an opportunity for the application to apply a custom transformation 3128a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * to the page views using animation properties. 3138a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 3148a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * <p>As property animation is only supported as of Android 3.0 and forward, 3158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * setting a PageTransformer on a ViewPager on earlier platform versions will 3168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * be ignored.</p> 3178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 3188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public interface PageTransformer { 3198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 3208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * Apply a property transformation to the given page. 3218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 3228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param page Apply the transformation to this page 3238a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param position Position of page relative to the current front-and-center 3248a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * position of the pager. 0 is front and center. 1 is one full 3258a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * page position to the right, and -1 is one page position to the left. 3268a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 3278a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public void transformPage(View page, float position); 3288a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 3298a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 3308a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 3318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Used internally to monitor when adapters are switched. 3328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 3338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell interface OnAdapterChangeListener { 3348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); 3358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 3368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 3371ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell /** 3381ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * Used internally to tag special types of child views that should be added as 3391ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell * pager decorations by default. 3401ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell */ 3411ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell interface Decor {} 3421ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell 343ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context) { 344d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context); 34547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 346d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 347d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 348ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public ViewPager(Context context, AttributeSet attrs) { 349d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(context, attrs); 35047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell initViewPager(); 351d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 352d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 35347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell void initViewPager() { 354d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setWillNotDraw(false); 3552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 3562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setFocusable(true); 357560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final Context context = getContext(); 3581cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller = new Scroller(context, sInterpolator); 3591cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 36016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float density = context.getResources().getDisplayMetrics().density; 36116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell 362d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 36316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); 364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 365560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge = new EdgeEffectCompat(context); 366560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge = new EdgeEffectCompat(context); 3671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 368035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); 369b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mCloseEnough = (int) (CLOSE_ENOUGH * density); 3708f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); 37125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 37225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); 37325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 37425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (ViewCompat.getImportantForAccessibility(this) 37525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 37625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.setImportantForAccessibility(this, 37725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 37825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 38171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio @Override 38271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio protected void onDetachedFromWindow() { 38371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio removeCallbacks(mEndScrollRunnable); 38471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio super.onDetachedFromWindow(); 38571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 38671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio 38747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell private void setScrollState(int newState) { 38847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mScrollState == newState) { 38947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell return; 39047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 39147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 39247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mScrollState = newState; 3938a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mPageTransformer != null) { 3948a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell // PageTransformers can do complex things that benefit from hardware layers. 3958a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell enableLayers(newState != SCROLL_STATE_IDLE); 3968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 39747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (mOnPageChangeListener != null) { 39847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageScrollStateChanged(newState); 39947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 40047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 40147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell 4028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a PagerAdapter that will supply views for this pager as needed. 4048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param adapter Adapter to use 4068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 407ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public void setAdapter(PagerAdapter adapter) { 4083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter != null) { 4098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.unregisterDataSetObserver(mObserver); 4100d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.startUpdate(this); 4110d6d2990ddacd3f419879149137f09a30c061436Minh Pham for (int i = 0; i < mItems.size(); i++) { 4120d6d2990ddacd3f419879149137f09a30c061436Minh Pham final ItemInfo ii = mItems.get(i); 4130d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.destroyItem(this, ii.position, ii.object); 4140d6d2990ddacd3f419879149137f09a30c061436Minh Pham } 4150d6d2990ddacd3f419879149137f09a30c061436Minh Pham mAdapter.finishUpdate(this); 4160d6d2990ddacd3f419879149137f09a30c061436Minh Pham mItems.clear(); 417a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeNonDecorViews(); 4180d6d2990ddacd3f419879149137f09a30c061436Minh Pham mCurItem = 0; 419871a68b5daafd810623d680207652f87eb2d11ccMinh Pham scrollTo(0, 0); 4203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 4228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final PagerAdapter oldAdapter = mAdapter; 423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mAdapter = adapter; 424199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mExpectedAdapterCount = 0; 425d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 426d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 4273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mObserver == null) { 4288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mObserver = new PagerObserver(); 4293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 4308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapter.registerDataSetObserver(mObserver); 431d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 432fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell final boolean wasFirstLayout = mFirstLayout; 43391eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell mFirstLayout = true; 434199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mExpectedAdapterCount = mAdapter.getCount(); 435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mRestoredCurItem >= 0) { 4365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(mRestoredCurItem, false, true); 438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = -1; 439ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = null; 4405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = null; 441fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } else if (!wasFirstLayout) { 442d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 443fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } else { 444fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell requestLayout(); 445d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 446d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 4478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 4488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mAdapterChangeListener != null && oldAdapter != adapter) { 4498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 4508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 453a7aea206661d601755bfac4165092d9130cba2bcAdam Powell private void removeNonDecorViews() { 454a7aea206661d601755bfac4165092d9130cba2bcAdam Powell for (int i = 0; i < getChildCount(); i++) { 455a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final View child = getChildAt(i); 456a7aea206661d601755bfac4165092d9130cba2bcAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 457a7aea206661d601755bfac4165092d9130cba2bcAdam Powell if (!lp.isDecor) { 458a7aea206661d601755bfac4165092d9130cba2bcAdam Powell removeViewAt(i); 459a7aea206661d601755bfac4165092d9130cba2bcAdam Powell i--; 460a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 461a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 462a7aea206661d601755bfac4165092d9130cba2bcAdam Powell } 463a7aea206661d601755bfac4165092d9130cba2bcAdam Powell 4648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 4658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Retrieve the current adapter supplying pages. 4668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 4678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The currently registered PagerAdapter 4688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 469ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn public PagerAdapter getAdapter() { 470d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mAdapter; 471d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 472d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 4738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell void setOnAdapterChangeListener(OnAdapterChangeListener listener) { 4748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mAdapterChangeListener = listener; 4758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 4768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 477becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu private int getClientWidth() { 478fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell return getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 479becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu } 480becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu 48197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 48297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. If the ViewPager has already been through its first 48391eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * layout with its current adapter there will be a smooth animated transition between 48491eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell * the current item and the specified item. 48597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 48697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 48797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 488d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void setCurrentItem(int item) { 489d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = false; 49097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, !mFirstLayout, false); 49197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell } 49297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell 49397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell /** 49497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * Set the currently selected page. 49597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * 49697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param item Item index to select 49797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately 49897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell */ 49997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell public void setCurrentItem(int item, boolean smoothScroll) { 50097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mPopulatePending = false; 50197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell setCurrentItemInternal(item, smoothScroll, false); 502d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 503d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 504bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki public int getCurrentItem() { 505bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki return mCurItem; 506bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki } 507bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki 508d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { 5091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(item, smoothScroll, always, 0); 5101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 5111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 5121cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { 513d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null || mAdapter.getCount() <= 0) { 514d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 515d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 516d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 517d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!always && mCurItem == item && mItems.size() != 0) { 518d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 519d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 5218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell 522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (item < 0) { 523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = 0; 524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else if (item >= mAdapter.getCount()) { 525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn item = mAdapter.getCount() - 1; 526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { 5294c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // We are doing a jump by more than one page. To avoid 5304c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // glitches, we want to keep all current pages in the view 5314c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // until the scroll ends. 5324c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 5334c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn mItems.get(i).scrolling = true; 5344c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 5354c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 53647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final boolean dispatchSelected = mCurItem != item; 537fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell 538fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell if (mFirstLayout) { 539fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell // We don't have any idea how big we are yet and shouldn't have any pages either. 540fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell // Just set things up and let the pending layout handle things. 541fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell mCurItem = item; 542fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 543fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell mOnPageChangeListener.onPageSelected(item); 544fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } 545fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 546fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell mInternalPageChangeListener.onPageSelected(item); 547fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } 548fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell requestLayout(); 549fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } else { 550fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell populate(item); 551fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell scrollToItem(item, smoothScroll, velocity, dispatchSelected); 552fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell } 553a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne } 554a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne 555a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne private void scrollToItem(int item, boolean smoothScroll, int velocity, 556a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne boolean dispatchSelected) { 557a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo curInfo = infoForPosition(item); 55831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell int destX = 0; 55931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (curInfo != null) { 560becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 56131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell destX = (int) (width * Math.max(mFirstOffset, 56231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell Math.min(curInfo.offset, mLastOffset))); 56331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 564d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (smoothScroll) { 5651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(destX, 0, velocity); 56647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 56747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mOnPageChangeListener.onPageSelected(item); 56847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 5698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 5708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 5718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 57347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell if (dispatchSelected && mOnPageChangeListener != null) { 5743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener.onPageSelected(item); 5753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (dispatchSelected && mInternalPageChangeListener != null) { 5778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageSelected(item); 5788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 57971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell scrollTo(destX, 0); 581c8c0fc23e8ff21166a7699e324426a6a7dc65806Chet Haase pageScrolled(destX); 582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 584d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 5858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 5868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 5878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 5888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 5923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 5933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 595d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 5968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * Set a {@link PageTransformer} that will be called for each attached page whenever 5978a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * the scroll position is changed. This allows the application to apply custom property 5988a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * transformations to each page, overriding the default sliding look and feel. 5998a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 6008a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist. 6018a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p> 6028a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 6038a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param reverseDrawingOrder true if the supplied PageTransformer requires page views 6048a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * to be drawn from last to first instead of first to last. 6058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param transformer PageTransformer that will modify each page's animation properties 6068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 6078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { 6088a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (Build.VERSION.SDK_INT >= 11) { 6097e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean hasTransformer = transformer != null; 6107e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean needsPopulate = hasTransformer != (mPageTransformer != null); 6118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer = transformer; 6127e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell setChildrenDrawingOrderEnabledCompat(hasTransformer); 6137e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (hasTransformer) { 6147e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; 6157e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } else { 6167e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = DRAW_ORDER_DEFAULT; 6177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 6187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (needsPopulate) populate(); 6198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell void setChildrenDrawingOrderEnabledCompat(boolean enable) { 623f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (Build.VERSION.SDK_INT >= 7) { 624f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mSetChildrenDrawingOrderEnabled == null) { 625f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell try { 626f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( 627f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE }); 628f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } catch (NoSuchMethodException e) { 629f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); 630f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 631f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 6328a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell try { 633f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mSetChildrenDrawingOrderEnabled.invoke(this, enable); 634f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } catch (Exception e) { 635f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Log.e(TAG, "Error changing children drawing order", e); 6368a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6378a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6388a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6398a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6408a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell @Override 6418a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell protected int getChildDrawingOrder(int childCount, int i) { 6427e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; 6437e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; 6447e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return result; 6458a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6468a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6478a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 6488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 6498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 6508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 6518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 6528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 6538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 6548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 6558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 6568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 6578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 6588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 6598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 66029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 66129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 66229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 66329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 66429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 66529a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 66629a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 66729a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 66829a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 66929a6184d74279156a9297dc67398712fb047fdc0Adam Powell 67029a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 67129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 67229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 67329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 67429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 67529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 67629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 67729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 67829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 67929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 68029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 68129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 68229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 68329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 68429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 68529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 68629a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 68729a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 68829a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 68929a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 69029a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 69129a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 69229a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69329a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 69429a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 69529a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 69629a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69729a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69829a6184d74279156a9297dc67398712fb047fdc0Adam Powell 69929a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 700329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 701329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 702329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 703329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 704329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 705329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 706329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 707329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 708329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 709329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 710329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 711329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 712329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 713329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 714329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 715329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 716329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 717329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 718329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 719329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 720329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 721329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 722329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 723329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 724329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 725329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 726329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 727329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 728329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 729329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 730329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 731329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 732329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 733329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 734329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 735329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 736329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 737329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 738329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 739329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 740329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 741329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 742329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 743329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 744329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 745329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 746329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 747329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 748329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 749329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 750329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 751329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 752329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 753329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 754329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 755329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 756329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 757329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 758329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 759329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 760329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 7611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 7621cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 7631cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 7641cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 7651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 7661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 7671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 7681cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 7691cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7701cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 771329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 773d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 774cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 775cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 7781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 7791cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7801cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 7811cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 7821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 7831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 7841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 7851cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 7861cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 7871cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 7881cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 7963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 7973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 7983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 79971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 80031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 8013040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 8023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 8033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 80647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 8071cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 808becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 809035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 810035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 811035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 812035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 8131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 814035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 8151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 8161cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 817035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 8181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 821035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 8221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 8231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 8241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 8251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 826b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 8325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 835d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 840d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 841d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 8433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 8443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 845199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell final int adapterCount = mAdapter.getCount(); 846199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mExpectedAdapterCount = adapterCount; 8471a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 848199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mItems.size() < adapterCount; 8491e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 8503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8519508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 8523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 8533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 8543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 8553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 8573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 8613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 8623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 8639508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8649508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 8659508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 8669508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 8679508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8689508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 8703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 8733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 874199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); 8751a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 8763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 8813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 8823661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 8833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 8843661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 8873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8919508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 8929508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 8939508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8949508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 89566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 89666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 907a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 908d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 9093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 9103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 9113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 9123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 913d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 918a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 919860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu int focusDirection = View.FOCUS_FORWARD; 920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 921860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT; 922a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 927f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 928d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 929d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 930d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 935d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 9363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 937f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 938d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 939d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 940d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 941ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 942ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 943ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 944ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 945ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 946ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 947ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 9485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 949d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 95029a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 95129a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 9524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 95329a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 954d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 955199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell if (N != mExpectedAdapterCount) { 956199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell String resName; 957199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell try { 958199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell resName = getResources().getResourceName(getId()); 959199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } catch (Resources.NotFoundException e) { 960199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell resName = Integer.toHexString(getId()); 961199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } 962199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + 963199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " contents without calling PagerAdapter#notifyDataSetChanged!" + 964199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + 965199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Pager id: " + resName + 966199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Pager class: " + getClass() + 967199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Problematic adapter: " + mAdapter.getClass()); 968199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } 969199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 980d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 9924f4c3a3978997e552c44726fb2862e4461497384Adam Powell final int clientWidth = getClientWidth(); 9934f4c3a3978997e552c44726fb2862e4461497384Adam Powell final float leftWidthNeeded = clientWidth <= 0 ? 0 : 9944f4c3a3978997e552c44726fb2862e4461497384Adam Powell 2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth; 995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 99631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 1002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 100371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 100471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 100571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 100671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 1013a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1014a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 1015a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1016a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 1017a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 1018a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 1019a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 10204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 1024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 1025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 1026a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 10274f4c3a3978997e552c44726fb2862e4461497384Adam Powell final float rightWidthNeeded = clientWidth <= 0 ? 0 : 10284f4c3a3978997e552c44726fb2862e4461497384Adam Powell (float) getPaddingRight() / (float) clientWidth + 2.f; 1029a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 1030becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu if (extraWidthRight >= rightWidthNeeded && pos > endPos) { 1031a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 1032a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 1033a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1034a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 1035a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 1036a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 103771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 103871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 103971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 104071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1041a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1042a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1043a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 1044a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 1045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1047a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1048a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 1049a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 1051a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1052a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1053a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1054d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1055a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1056a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1058d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10594c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 10604c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 10614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 10624c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 10672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10685c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 10692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10707e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Check width measurement of current pages and drawing sort order. 10717e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Update LayoutParams as needed. 1072a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 1073a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 1074a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1075a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 10767e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.childIndex = i; 1077a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 1078a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 1079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 1080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 1081a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 10827e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.position = ii.position; 1083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1085a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1086f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 1087a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 10882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 10892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 1090218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 10912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 10922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 10932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 10942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 10952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 1096860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu if (child.requestFocus(focusDirection)) { 10972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 10982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 11002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 11012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 11022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1105f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell private void sortChildDrawingOrder() { 1106f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mDrawingOrder != DRAW_ORDER_DEFAULT) { 1107f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mDrawingOrderedChildren == null) { 1108f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren = new ArrayList<View>(); 1109f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } else { 1110f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren.clear(); 1111f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1112f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell final int childCount = getChildCount(); 1113f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell for (int i = 0; i < childCount; i++) { 1114f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell final View child = getChildAt(i); 1115f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren.add(child); 1116f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1117f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Collections.sort(mDrawingOrderedChildren, sPositionComparator); 1118f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1119f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1120f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell 1121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 1122a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 1123becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 1124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 1126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 11326bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 1135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 1137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 1153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 1154a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 1155a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1156a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 1157a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1159a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 1164a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 1165a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1166a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1167a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1168a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1169a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1171a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1172a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 1173a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1174a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 1175a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 1176a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 117731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 117831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 1179a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 1180a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 1181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1182a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1183a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 1184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1186a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1187a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 1188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 1190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 1191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 1192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 1193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 1196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 119731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 119831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 119931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 1200a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 12077dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 12087dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 12097dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 12107dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 12117dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 12127dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1214d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1215ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 12165c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1217d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12185c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1219d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1222d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1223d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1224d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1225d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 12265c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1227d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1228d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1229d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 12375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 12385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 12395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 12405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 12415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 12425c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 12435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 12445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 12455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 12465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 12475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 12485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1249d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 12505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 12515c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1252ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 12535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 12545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 12555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1259d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1260d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1261d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1262d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1263d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1264677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1265677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1266677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1267d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1273d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1274d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1275d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1276d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1277d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1278d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1279d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1280d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 12815c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1282d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1283d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1284d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1285ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 12865c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1287d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 12918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 12921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 12931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 12941ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 12951ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 12961ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1301a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1302d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1309d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1310d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1315d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 131637a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase @Override 131737a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase public void removeView(View view) { 131837a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase if (mInLayout) { 131937a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase removeViewInLayout(view); 132037a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } else { 132137a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase super.removeView(view); 132237a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 132337a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 132437a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase 1325d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1326d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1327d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1328ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1329d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1332d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1333d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1334d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1335218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1336218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1337218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1338218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1339218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1340218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1341218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1342218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1343218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1344218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1345218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1355a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1356d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1357ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1358ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 135997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1360ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1361ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1362ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1363d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1364fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell // For simple implementation, our internal size is always 0. 1365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1366d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1367d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1368d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1369d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 13728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int measuredWidth = getMeasuredWidth(); 13738f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int maxGutterSize = measuredWidth / 10; 13748f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); 13758f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 13778f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); 13788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 13798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 13818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 13828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 13838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 13848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1385862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 13878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 13888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 13898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 13918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 13928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 13938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 13968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 13978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 13998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 14008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 14018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 14028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1406a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1407a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1409a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1410a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1411a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1412a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1413a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1419a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 14208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 14218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 14238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 14248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 14258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 14268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 14328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 14398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1440862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1441d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1442d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1443d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1444d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1449a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1450a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1451a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1453d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1457d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1458d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1460d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1461d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1462053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1463329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1464329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1465329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1466329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1467329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 146891eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 1469becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin; 1470becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight() 1471becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu + oldMargin; 14728d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int xpos = getScrollX(); 14735f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 14745f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1475a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 14765f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1477329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1478329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1479329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1480a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 14815f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 14828d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell (int) (targetInfo.offset * width), 0, newDuration); 1483329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1484329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1485a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 14868d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; 1487becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int scrollPos = (int) (scrollOffset * 1488becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu (width - getPaddingLeft() - getPaddingRight())); 1489329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 149071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 1491053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 14929bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1493d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1495d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1496d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1497d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1498d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1508d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1509a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1510a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1511d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 15148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 15158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 15168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 15178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 15188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 15198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 15208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 15218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 15228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 15238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 15258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 15268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 15278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 15298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 15308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 15318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 15338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 15348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 15358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 15388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 15398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 15408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 15428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 15438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 15448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 15468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 15478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 15488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 15508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 15518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 15528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1555abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1556abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1557abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1558a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1559a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1560a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1561a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1562a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1563becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int childWidth = width - paddingLeft - paddingRight; 1564a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1565a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1566a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1567a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1568a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1569a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1570a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1571becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu int loff = (int) (childWidth * ii.offset); 1572a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1573a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1574a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1575a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1576a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1577a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1578a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1579becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu (int) (childWidth * lp.widthFactor), 1580a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1581a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1582a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1583a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1584a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1585a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 15868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 15878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 15888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1589abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1590abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1591abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 15928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 15958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 15968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 15978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 159844fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell 159944fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell if (mFirstLayout) { 160044fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell scrollToItem(mCurItem, false, 0, false); 160144fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell } 160297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1603d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1604d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1606d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1607a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1608a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1609a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1610a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1611a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 16123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1613a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1614a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 16154783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 16164783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 16174783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 16184783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1620a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1621a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1622b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1623a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1624d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 16254c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 16264c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 162771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(true); 1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1629d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16304783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 16314783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 16324783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 16334783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 16344783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 16354783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 16364783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 16374783095cc69fa85e484132337526c94d42d41c43Adam Powell } 16384783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 16394783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1640a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1641becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 1642a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1643a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1644a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1645a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1646a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1647a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 16488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1650a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 16518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 16528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 16538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 16548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16554783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 16568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 16598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 16608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 16618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 16628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 16638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 16648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 16658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 16668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 16678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 16688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 16698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 16708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 16718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 16728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 16738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 16748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 16758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 16768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 16778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 16788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 16798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 16808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 16828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 16848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 16858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 16868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 16878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 16908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 16928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 16948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 16958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 16968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 16988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 16998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 17008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 17018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 17038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 17048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 17058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 17068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 17078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 17118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 17128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 17138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 17158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 17168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 17188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mPageTransformer != null) { 17198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int scrollX = getScrollX(); 17208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 17218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 17228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final View child = getChildAt(i); 17237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 17257e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (lp.isDecor) continue; 17267e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 1727becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); 17288a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer.transformPage(child, transformPos); 17298a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17308a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17318a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 17328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 17338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 173571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio private void completeScroll(boolean postEvents) { 17368d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; 1737cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 17384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 17394c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1740d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1742d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1743d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1746d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1747d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 17484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 17504c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 17514c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 17524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 17534c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 17544c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 17554c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17564c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17574c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 175871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (postEvents) { 175971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio ViewCompat.postOnAnimation(this, mEndScrollRunnable); 176071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } else { 176171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio mEndScrollRunnable.run(); 176271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 17668f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean isGutterDrag(float x, float dx) { 17678f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); 17688f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell } 17698f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 17708a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private void enableLayers(boolean enable) { 17718a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 17728a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 17738a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int layerType = enable ? 17748a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; 17758a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.setLayerType(getChildAt(i), layerType, null); 17768a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17778a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17788a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 1779d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 17963ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 17973ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 17983ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 17993ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1809d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1810d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1814d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1815d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1816d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1817d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1820d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1821d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1822d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1823d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1824d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1825d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1826d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1829d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1832d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1833d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1834d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 183547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 183647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 183816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float yDiff = Math.abs(y - mInitialMotionY); 1839d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1840bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 18418f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && 18428f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell canScroll(this, false, (int) dx, (int) x, (int) y)) { 1843bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 184416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionX = x; 1845bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1846b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1847bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1848bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 184916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) { 1850d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1851d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 18520f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette requestParentDisallowInterceptTouchEvent(true); 185347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 18548d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : 18558d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 185616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 1857d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 185816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell } else if (yDiff > mTouchSlop) { 185916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // The finger has moved enough in the vertical 186016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // direction to be counted as a drag... abort 186116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // any attempt to drag horizontally, to work correctly 186216991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // with children that have scrolling containers. 186316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 186416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mIsUnableToDrag = true; 1865d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 18666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (mIsBeingDragged) { 18676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Scroll to follow the motion event 18686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (performDrag(x)) { 18696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell ViewCompat.postInvalidateOnAnimation(this); 18706e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18716e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 1872d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1873d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1874d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1875d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1876d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1877d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1878d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1879d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1880d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 188116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1882d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1883b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18858d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.computeScrollOffset(); 1886b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1887b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 188847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 18898d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 18908d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 18918d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 189247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 18930f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette requestParentDisallowInterceptTouchEvent(true); 189447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 189547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 189671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 189747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 189847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1899d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1900d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1901d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1902d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1903d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1904d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1905d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1906d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1907d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1908d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1909d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1910d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19118d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell if (mVelocityTracker == null) { 19128d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker = VelocityTracker.obtain(); 19133ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 19148d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker.addMovement(ev); 19153ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1916d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 19173ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 19183ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 19193ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1920d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1921d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1922d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1923d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1924d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 192569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 192669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 192769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 192869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 192969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 193069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1935d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1936d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1937d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 19393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 19403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 19413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 19423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1943d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1944d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1945d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1946d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1947d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1948d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1949560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1950d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1951d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1952d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 19538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 19548d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 19558d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 1956d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1957d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1958d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 195916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1960d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1961d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1962d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1963d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 19643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 19653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 19663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 196747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 19683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 196947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 19703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 19713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 19723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 19733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 19740f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette requestParentDisallowInterceptTouchEvent(true); 19758d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : 19768d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 197716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 197847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 19793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 198023f32662b0e412510094d59c478f1d5370a15244Chris Banes 198123f32662b0e412510094d59c478f1d5370a15244Chris Banes // Disallow Parent Intercept, just in case 198223f32662b0e412510094d59c478f1d5370a15244Chris Banes ViewParent parent = getParent(); 198323f32662b0e412510094d59c478f1d5370a15244Chris Banes if (parent != null) { 198423f32662b0e412510094d59c478f1d5370a15244Chris Banes parent.requestDisallowInterceptTouchEvent(true); 198523f32662b0e412510094d59c478f1d5370a15244Chris Banes } 19863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 19873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 198831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1989d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1990d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1991d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1992d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1993d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 19946e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate |= performDrag(x); 1995d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1996d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1997d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1998d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1999d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 2000d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 20011cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 2002d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 2003d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 2004becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 20051cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 2006a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2009035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 2010035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 2011035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 2012035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 2013035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2014035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 20151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 2016d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2017d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 2018d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 2019560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 2020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 2023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 2024a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne scrollToItem(mCurItem, true, 0, false); 2025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 2026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 2027560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 2028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 2031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 2032d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 2033d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 2034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 2035d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2036d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2037d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 2038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 2039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 2040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 2041d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2042d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2043560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 2044b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 2045560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2046d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 2047d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2048d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 20490f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) { 20500f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette final ViewParent parent = getParent(); 20510f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette if (parent != null) { 20520f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette parent.requestDisallowInterceptTouchEvent(disallowIntercept); 20530f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette } 20540f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette } 20550f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette 20566e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell private boolean performDrag(float x) { 20576e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean needsInvalidate = false; 20586e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20596e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final float deltaX = mLastMotionX - x; 20606e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX = x; 20616e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20626e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float oldScrollX = getScrollX(); 20636e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float scrollX = oldScrollX + deltaX; 2064becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 20656e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float leftBound = width * mFirstOffset; 20676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float rightBound = width * mLastOffset; 20686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean leftAbsolute = true; 20696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean rightAbsolute = true; 20706e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20716e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo firstItem = mItems.get(0); 20726e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 20736e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (firstItem.position != 0) { 20746e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftAbsolute = false; 20756e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftBound = firstItem.offset * width; 20766e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20776e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (lastItem.position != mAdapter.getCount() - 1) { 20786e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightAbsolute = false; 20796e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightBound = lastItem.offset * width; 20806e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20816e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20826e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (scrollX < leftBound) { 20836e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (leftAbsolute) { 20846e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = leftBound - scrollX; 20856e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 20866e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20876e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = leftBound; 20886e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } else if (scrollX > rightBound) { 20896e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (rightAbsolute) { 20906e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = scrollX - rightBound; 20916e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 20926e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20936e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = rightBound; 20946e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20956e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Don't lose the rounded component 20966e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX += scrollX - (int) scrollX; 20976e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollTo((int) scrollX, getScrollY()); 20986e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell pageScrolled((int) scrollX); 20996e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 21006e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell return needsInvalidate; 21016e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 21026e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 2103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2104a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 2105a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 2106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 2108becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 2109a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 2110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 2111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 2112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 2113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 2114a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 2115a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2116ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 2117a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 2118a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 2119a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 2120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 2121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 2122a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 2123a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 2124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 2125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 2126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 2127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 2129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 21308d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float leftBound = offset; 21318d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset; 2132ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 2133ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 2134ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 2135ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 2136ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 2137ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 2140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 2141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 2142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 2143ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 2144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2146ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2149035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 2150035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 2151035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 2152035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 2153035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 215416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; 215516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell targetPage = (int) (currentPage + pageOffset + truncator); 2156035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2157035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 2159a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 2163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 2164a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2165a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2166035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 2167035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2168035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2169560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 2170560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 2171560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 2172560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 2173560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2174560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 2175560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 2176560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 2177560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 2178560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 2179560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2180560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2182560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2183560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 2184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 2185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 2186560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 2187560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2188560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2189560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 2190560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2191560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 2192560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 2195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 2196560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 2197560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 2198560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2199560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2200560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 2201560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 2202560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 2203560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2204560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2205560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 2206560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 2207b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 2208560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2209560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2210560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2211329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 2212329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 2213329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 2214329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 2215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 2216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 2217329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 2218329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 2219a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2220a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 2221a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 2222a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 2223a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 2224a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 2225a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 2226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 2227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 2228a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 2229a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 2230a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2231a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 223223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 2233a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 223423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 2235a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 2236a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 2237a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 223823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 2239a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 2240a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2241a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2242a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 2243a56d6faa9df608aaa2907864669800abb68acec7Adam Powell mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, 224423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 2245a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 2246a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2248a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 2249a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 2250a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2251329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2252329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2253329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2254329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 225569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 225669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 225769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 225869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 225969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 226069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 226169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 226269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 226369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 226469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 226569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 226669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 226769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 226869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 226969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 227069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 227169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 227269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 227369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 227469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 227569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 227669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 227769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 227869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 227969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 228069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 228169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 228269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 228369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 228469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 228569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 228669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 228769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 228869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 228969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 229069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 229169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 229269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 229369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 229469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 229569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 229669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 229769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 229869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 229969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 230069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 230169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 230269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 230369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 230469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 23050f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 230669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 230769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2308becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 2309035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2310a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2311a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2312a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2313a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2314a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2315a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2316035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 231769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 231869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 231969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 232069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 232169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 232269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 232369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 232469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 232569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 232669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 232769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 232869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 232969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 233069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 233169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 233269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 233369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 233469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2335a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2336a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 23370f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 2338becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 233969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2340a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2341a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2342a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2343a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2344a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 235269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 235369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 235469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 235569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 235669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 235769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 235869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 235969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 23608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 236169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 236269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 236369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 236469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 236569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 236669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 236769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 236869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 236969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 237069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 237169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 237269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 237369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 237469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 237569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 237669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 237769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 237869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 237969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 238069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 238169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 238269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2383d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2384d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2385d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2386d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2388d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2389d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2390d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2394d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2395d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2396d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2397d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2401d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2402d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2404d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2405d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2407d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2408d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2409d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2410d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2411d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2412d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2413d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2414d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2415d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2416d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2417d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2420d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2421d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 24223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2423aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette public boolean canScrollHorizontally(int direction) { 2424aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (mAdapter == null) { 2425aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette return false; 2426aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette } 2427aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette 2428aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette final int width = getClientWidth(); 2429aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette final int scrollX = getScrollX(); 2430aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (direction < 0) { 2431aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette return (scrollX > (int) (width * mFirstOffset)); 2432aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette } else if (direction > 0) { 2433aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette return (scrollX < (int) (width * mLastOffset)); 2434aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette } else { 2435aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette return false; 2436aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette } 2437aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette } 2438aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette 2439bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2440cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2441bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2442bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2443bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2444bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2445bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2446cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2447bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2448cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2449bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2450cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2451bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2452bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2453bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2454bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2455bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2456bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2457bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2458bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2459bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2460bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2461bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2462bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2463bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2464bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2465bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2466bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2467bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2468bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2469bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2470bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2471bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2472bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2473481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 24742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 24752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 24762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 24772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 24802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 24812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 24822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 24832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 24842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 24852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 24862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 24872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 24882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 24892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 24902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 24912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 24922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 24932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 24952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 24962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 24985de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 24995de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 25005de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 25015de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 25025de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 25035de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 25045de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 25055de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 25062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 25082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 25112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 25142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 251531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (currentFocused == this) { 251631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell currentFocused = null; 251731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } else if (currentFocused != null) { 251831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell boolean isChild = false; 251931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; 252031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell parent = parent.getParent()) { 252131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (parent == this) { 252231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell isChild = true; 252331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell break; 252431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 252531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 252631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (!isChild) { 252731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell // This would cause the focus search down below to fail in fun ways. 252831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell final StringBuilder sb = new StringBuilder(); 252931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell sb.append(currentFocused.getClass().getSimpleName()); 253031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; 253131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell parent = parent.getParent()) { 253231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell sb.append(" => ").append(parent.getClass().getSimpleName()); 253331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 253431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell Log.e(TAG, "arrowScroll tried to find focus based on non-child " + 253531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell "current focused view " + sb.toString()); 253631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell currentFocused = null; 253731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 253831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 25392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 25412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 25432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 25442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 25452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 25462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 25472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 2548dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2549dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2550dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft >= currLeft) { 25512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 25522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 25532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 25542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 25562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 25572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 2558dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2559dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2560dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft <= currLeft) { 25612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 25622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 25632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 25642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 25672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 25682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 25692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 25702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 25712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 25722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 25742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 25752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 25772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 2579dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { 2580dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (outRect == null) { 2581dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect = new Rect(); 2582dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2583efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell if (child == null) { 2584efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell outRect.set(0, 0, 0, 0); 2585efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell return outRect; 2586efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell } 2587dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left = child.getLeft(); 2588dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right = child.getRight(); 2589dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top = child.getTop(); 2590dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom = child.getBottom(); 2591dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2592dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell ViewParent parent = child.getParent(); 2593dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell while (parent instanceof ViewGroup && parent != this) { 2594dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final ViewGroup group = (ViewGroup) parent; 2595dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left += group.getLeft(); 2596dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right += group.getRight(); 2597dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top += group.getTop(); 2598dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom += group.getBottom(); 2599dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2600dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell parent = group.getParent(); 2601dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2602dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell return outRect; 2603dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2604dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 26052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 26062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 26072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 26082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 26092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 26112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2614218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 26152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 26162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 26172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 26192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 26222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 26232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 26242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 26252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 26262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 26272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 26292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 26312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 26322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 26332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 26342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 26352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 26362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 26372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 26432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 26442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 26452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 26462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 26472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 26482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 26492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 26502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 26512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 26522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 26532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 26542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 26562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 26572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 26582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 26602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 26612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 26662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 26672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 26682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 26692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 26702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 26712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 26722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 26732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 26742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 26752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 26762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 26772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 26782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 26792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 26852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 26862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 26872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 26882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 26892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 26902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 26912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 26922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 26932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 26942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 26952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 26962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 26972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 26982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 26992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 27002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 27012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 27022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 27032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 27042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 27052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 27062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 27072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 27082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(direction, previouslyFocusedRect)) { 27092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 27102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 27112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 27122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2713481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 27142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2715481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2716481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2717481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2718481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2719109e561bfa6720a7043a28dc265297d915170954Alan Viverette // Dispatch scroll events from this ViewPager. 2720109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) { 2721109e561bfa6720a7043a28dc265297d915170954Alan Viverette return super.dispatchPopulateAccessibilityEvent(event); 2722109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 2723481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2724109e561bfa6720a7043a28dc265297d915170954Alan Viverette // Dispatch all other accessibility events from the current page. 2725481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2726481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2727481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2728481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2729481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2730481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2731481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2732481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2733481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2734481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2735481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2736481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2737481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2738481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2739481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 27408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 27428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 27438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 27478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 27488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 27528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 27538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 27571ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 27588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 276025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov class MyAccessibilityDelegate extends AccessibilityDelegateCompat { 276125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 276225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 276325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 276425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityEvent(host, event); 276525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov event.setClassName(ViewPager.class.getName()); 27669a95c60a9c9fcc7d5ca0f9aeaede854d2a47a824Ying Wang final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain(); 2767109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setScrollable(canScroll()); 2768e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED 2769e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav && mAdapter != null) { 2770109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setItemCount(mAdapter.getCount()); 2771109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setFromIndex(mCurItem); 2772109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setToIndex(mCurItem); 2773109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 277425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 277525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 277625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 277725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 277825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(host, info); 277925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setClassName(ViewPager.class.getName()); 2780109e561bfa6720a7043a28dc265297d915170954Alan Viverette info.setScrollable(canScroll()); 2781aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (canScrollHorizontally(1)) { 278225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 278325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 2784aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (canScrollHorizontally(-1)) { 278525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 278625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 278725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 278825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 278925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 279025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public boolean performAccessibilityAction(View host, int action, Bundle args) { 279125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (super.performAccessibilityAction(host, action, args)) { 279225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 279325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 279425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov switch (action) { 279525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { 2796aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (canScrollHorizontally(1)) { 279725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem + 1); 279825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 279925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 280025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 280125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { 2802aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette if (canScrollHorizontally(-1)) { 280325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem - 1); 280425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 280525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 280625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 280725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 280825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return false; 280925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 2810109e561bfa6720a7043a28dc265297d915170954Alan Viverette 2811109e561bfa6720a7043a28dc265297d915170954Alan Viverette private boolean canScroll() { 2812109e561bfa6720a7043a28dc265297d915170954Alan Viverette return (mAdapter != null) && (mAdapter.getCount() > 1); 2813109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 281425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 281525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 28168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 28178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 28188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 28198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 28208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 28228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 28233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 28243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 28253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 28268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28277dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 28287dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 28297dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 28307dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 28318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 28328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 28338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 28348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 28358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 28368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 28378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 28393d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 28407dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 28417dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 28448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28487e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell float widthFactor = 0.f; 2849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28547e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell boolean needsMeasure; 28557e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28567e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 28577e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Adapter position this view is for if !isDecor 28587e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 28597e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int position; 28607e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28617e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 28627e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Current child index within the ViewPager that this view occupies 28637e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 28647e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int childIndex; 2865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 28668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 28678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 28688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 28718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 28728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 28758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 28768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28787e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28797e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell static class ViewPositionComparator implements Comparator<View> { 28807e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell @Override 28817e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell public int compare(View lhs, View rhs) { 28827e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); 28837e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); 28847e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (llp.isDecor != rlp.isDecor) { 28857e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.isDecor ? 1 : -1; 28867e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 28877e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.position - rlp.position; 28887e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 28897e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 2890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2891