ViewPager.java revision e4578af7dfd6ae3f85435a569ed8d5107bf20ec3
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); 581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 5848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 5858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a listener that will be invoked whenever the page changes or is incrementally 5868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * scrolled. See {@link OnPageChangeListener}. 5878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 5888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 5898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 5903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell public void setOnPageChangeListener(OnPageChangeListener listener) { 5913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mOnPageChangeListener = listener; 5923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 5933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /** 5958a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * Set a {@link PageTransformer} that will be called for each attached page whenever 5968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * the scroll position is changed. This allows the application to apply custom property 5978a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * transformations to each page, overriding the default sliding look and feel. 5988a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 5998a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist. 6008a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p> 6018a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * 6028a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param reverseDrawingOrder true if the supplied PageTransformer requires page views 6038a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * to be drawn from last to first instead of first to last. 6048a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell * @param transformer PageTransformer that will modify each page's animation properties 6058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell */ 6068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { 6078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (Build.VERSION.SDK_INT >= 11) { 6087e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean hasTransformer = transformer != null; 6097e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final boolean needsPopulate = hasTransformer != (mPageTransformer != null); 6108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer = transformer; 6117e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell setChildrenDrawingOrderEnabledCompat(hasTransformer); 6127e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (hasTransformer) { 6137e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; 6147e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } else { 6157e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell mDrawingOrder = DRAW_ORDER_DEFAULT; 6167e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 6177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (needsPopulate) populate(); 6188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell void setChildrenDrawingOrderEnabledCompat(boolean enable) { 622f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (Build.VERSION.SDK_INT >= 7) { 623f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mSetChildrenDrawingOrderEnabled == null) { 624f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell try { 625f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( 626f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE }); 627f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } catch (NoSuchMethodException e) { 628f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); 629f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 630f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 6318a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell try { 632f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mSetChildrenDrawingOrderEnabled.invoke(this, enable); 633f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } catch (Exception e) { 634f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Log.e(TAG, "Error changing children drawing order", e); 6358a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6368a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6378a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6388a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6398a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell @Override 6408a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell protected int getChildDrawingOrder(int childCount, int i) { 6417e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; 6427e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; 6437e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return result; 6448a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 6458a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 6468a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell /** 6478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Set a separate OnPageChangeListener for internal use by the support library. 6488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 6498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param listener Listener to set 6508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @return The old listener that was set, if any. 6518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 6528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { 6538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell OnPageChangeListener oldListener = mInternalPageChangeListener; 6548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener = listener; 6558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return oldListener; 6568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 6578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 6588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 65929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Returns the number of pages that will be retained to either side of the 66029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Defaults to 1. 66129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 66229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @return How many pages will be kept offscreen on either side 66329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @see #setOffscreenPageLimit(int) 66429a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 66529a6184d74279156a9297dc67398712fb047fdc0Adam Powell public int getOffscreenPageLimit() { 66629a6184d74279156a9297dc67398712fb047fdc0Adam Powell return mOffscreenPageLimit; 66729a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 66829a6184d74279156a9297dc67398712fb047fdc0Adam Powell 66929a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 67029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * Set the number of pages that should be retained to either side of the 67129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * current page in the view hierarchy in an idle state. Pages beyond this 67229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * limit will be recreated from the adapter when needed. 67329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 67429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>This is offered as an optimization. If you know in advance the number 67529a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of pages you will need to support or have lazy-loading mechanisms in place 67629a6184d74279156a9297dc67398712fb047fdc0Adam Powell * on your pages, tweaking this setting can have benefits in perceived smoothness 67729a6184d74279156a9297dc67398712fb047fdc0Adam Powell * of paging animations and interaction. If you have a small number of pages (3-4) 67829a6184d74279156a9297dc67398712fb047fdc0Adam Powell * that you can keep active all at once, less time will be spent in layout for 67929a6184d74279156a9297dc67398712fb047fdc0Adam Powell * newly created view subtrees as the user pages back and forth.</p> 68029a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 68129a6184d74279156a9297dc67398712fb047fdc0Adam Powell * <p>You should keep this limit low, especially if your pages have complex layouts. 68229a6184d74279156a9297dc67398712fb047fdc0Adam Powell * This setting defaults to 1.</p> 68329a6184d74279156a9297dc67398712fb047fdc0Adam Powell * 68429a6184d74279156a9297dc67398712fb047fdc0Adam Powell * @param limit How many pages will be kept offscreen in an idle state. 68529a6184d74279156a9297dc67398712fb047fdc0Adam Powell */ 68629a6184d74279156a9297dc67398712fb047fdc0Adam Powell public void setOffscreenPageLimit(int limit) { 68729a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit < DEFAULT_OFFSCREEN_PAGES) { 68829a6184d74279156a9297dc67398712fb047fdc0Adam Powell Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + 68929a6184d74279156a9297dc67398712fb047fdc0Adam Powell DEFAULT_OFFSCREEN_PAGES); 69029a6184d74279156a9297dc67398712fb047fdc0Adam Powell limit = DEFAULT_OFFSCREEN_PAGES; 69129a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69229a6184d74279156a9297dc67398712fb047fdc0Adam Powell if (limit != mOffscreenPageLimit) { 69329a6184d74279156a9297dc67398712fb047fdc0Adam Powell mOffscreenPageLimit = limit; 69429a6184d74279156a9297dc67398712fb047fdc0Adam Powell populate(); 69529a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69629a6184d74279156a9297dc67398712fb047fdc0Adam Powell } 69729a6184d74279156a9297dc67398712fb047fdc0Adam Powell 69829a6184d74279156a9297dc67398712fb047fdc0Adam Powell /** 699329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set the margin between pages. 700329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 701329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param marginPixels Distance between adjacent pages in pixels 702329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #getPageMargin() 703329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(Drawable) 704329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @see #setPageMarginDrawable(int) 705329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 706329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMargin(int marginPixels) { 707329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int oldMargin = mPageMargin; 708329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mPageMargin = marginPixels; 709329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 710329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 711329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(width, width, marginPixels, oldMargin); 712329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 713329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell requestLayout(); 714329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 715329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 716329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 717329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Return the margin between pages. 718329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 719329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @return The size of the margin in pixels 720329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 721329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public int getPageMargin() { 722329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return mPageMargin; 723329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 724329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 725329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 726329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 727329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 728329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param d Drawable to display between pages 729329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 730329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(Drawable d) { 731329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell mMarginDrawable = d; 732329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null) refreshDrawableState(); 733329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setWillNotDraw(d == null); 734329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell invalidate(); 735329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 736329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 737329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 738329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * Set a drawable that will be used to fill the margin between pages. 739329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * 740329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell * @param resId Resource ID of a drawable to display between pages 741329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell */ 742329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell public void setPageMarginDrawable(int resId) { 743329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell setPageMarginDrawable(getContext().getResources().getDrawable(resId)); 744329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 745329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 746329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 747329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected boolean verifyDrawable(Drawable who) { 748329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell return super.verifyDrawable(who) || who == mMarginDrawable; 749329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 750329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 751329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 752329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void drawableStateChanged() { 753329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.drawableStateChanged(); 754329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final Drawable d = mMarginDrawable; 755329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (d != null && d.isStateful()) { 756329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell d.setState(getDrawableState()); 757329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 758329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 759329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 7601cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // We want the duration of the page snap animation to be influenced by the distance that 7611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // the screen has to travel, however, we don't want this duration to be effected in a 7621cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // purely linear fashion. Instead, we use this method to moderate the effect that the distance 7631cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell // of travel has on the overall snap duration. 7641cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell float distanceInfluenceForSnapDuration(float f) { 7651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f -= 0.5f; // center the values about 0. 7661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell f *= 0.3f * Math.PI / 2.0f; 7671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell return (float) Math.sin(f); 7681cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7691cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 770329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell /** 771d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * 773cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x the number of pixels to scroll by on the X axis 774cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param y the number of pixels to scroll by on the Y axis 775d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void smoothScrollTo(int x, int y) { 7771cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell smoothScrollTo(x, y, 0); 7781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 7791cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 7801cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell /** 7811cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 7821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * 7831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param x the number of pixels to scroll by on the X axis 7841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param y the number of pixels to scroll by on the Y axis 7851cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) 7861cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell */ 7871cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell void smoothScrollTo(int x, int y, int velocity) { 788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (getChildCount() == 0) { 789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing to do. 790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(false); 791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sx = getScrollX(); 794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int sy = getScrollY(); 7953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dx = x - sx; 7963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell int dy = y - sy; 7973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (dx == 0 && dy == 0) { 79871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 79931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell populate(); 8003040c142491acd4a09e7d0add073be0067aec2d5Adam Powell setScrollState(SCROLL_STATE_IDLE); 8013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return; 8023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 80547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_SETTLING); 8061cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 807becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 808035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int halfWidth = width / 2; 809035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); 810035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float distance = halfWidth + halfWidth * 811035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell distanceInfluenceForSnapDuration(distanceRatio); 8121cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 813035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int duration = 0; 8141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell velocity = Math.abs(velocity); 8151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell if (velocity > 0) { 816035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 8171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } else { 818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageWidth = width * mAdapter.getPageWidth(mCurItem); 819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); 820035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell duration = (int) ((pageDelta + 1) * 100); 8211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell } 8221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell duration = Math.min(duration, MAX_SETTLE_DURATION); 8231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell 8241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell mScroller.startScroll(sx, sy, dx, dy, duration); 825b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 826d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo addNewItem(int position, int index) { 829d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = new ItemInfo(); 830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ii.position = position; 8315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ii.object = mAdapter.instantiateItem(this, position); 832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(position); 833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (index < 0 || index >= mItems.size()) { 834d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(ii); 835d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mItems.add(index, ii); 837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 839d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 840d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 8413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell void dataSetChanged() { 8423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // This method only gets called if our observer is attached, so mAdapter is non-null. 8433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 844199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell final int adapterCount = mAdapter.getCount(); 845199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mExpectedAdapterCount = adapterCount; 8461a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && 847199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell mItems.size() < adapterCount; 8481e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell int newCurrItem = mCurItem; 8493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8509508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell boolean isUpdating = false; 8513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell for (int i = 0; i < mItems.size(); i++) { 8523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final ItemInfo ii = mItems.get(i); 8533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int newPos = mAdapter.getItemPosition(ii.object); 8543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_UNCHANGED) { 8563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (newPos == PagerAdapter.POSITION_NONE) { 8603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mItems.remove(i); 8613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell i--; 8629508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8639508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (!isUpdating) { 8649508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.startUpdate(this); 8659508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell isUpdating = true; 8669508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8679508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 8683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mAdapter.destroyItem(this, ii.position, ii.object); 8693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mCurItem == ii.position) { 8723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Keep the current item in the valid range 873199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); 8741a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell needPopulate = true; 8753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell continue; 8773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position != newPos) { 8803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (ii.position == mCurItem) { 8813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Our current item changed position. Follow it. 8823661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell newCurrItem = newPos; 8833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8843661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell ii.position = newPos; 8863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell needPopulate = true; 8873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 8893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 8909508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell if (isUpdating) { 8919508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell mAdapter.finishUpdate(this); 8929508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell } 8939508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell 89466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham Collections.sort(mItems, COMPARATOR); 89566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham 896a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (needPopulate) { 897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Reset our known page widths; populate will recompute them. 898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor) { 903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = 0.f; 904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 907d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell setCurrentItemInternal(newCurrItem, false, true); 9083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell requestLayout(); 9093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 9103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 9113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 912d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn void populate() { 913a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell populate(mCurItem); 914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell void populate(int newCurrentItem) { 917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo oldCurInfo = null; 918860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu int focusDirection = View.FOCUS_FORWARD; 919a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mCurItem != newCurrentItem) { 920860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT; 921a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell oldCurInfo = infoForPosition(mCurItem); 922a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mCurItem = newCurrentItem; 923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 925d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter == null) { 926f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 927d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 928d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 929d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 930d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Bail now if we are waiting to populate. This is to hold off 931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // on creating views from the time the user releases their finger to 932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // fling to a new position until we have finished the scroll to 933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // that position, avoiding glitches from happening at that point. 934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mPopulatePending) { 9353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); 936f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 937d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 938d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 939d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 940ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // Also, don't populate until we are attached to a window. This is to 941ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // avoid trying to populate before we have restored our view hierarchy 942ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn // state and conflicting with what is restored. 943ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (getWindowToken() == null) { 944ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn return; 945ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 946ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 9475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.startUpdate(this); 948d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 94929a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int pageLimit = mOffscreenPageLimit; 95029a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int startPos = Math.max(0, mCurItem - pageLimit); 9514c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn final int N = mAdapter.getCount(); 95229a6184d74279156a9297dc67398712fb047fdc0Adam Powell final int endPos = Math.min(N-1, mCurItem + pageLimit); 953d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 954199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell if (N != mExpectedAdapterCount) { 955199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell String resName; 956199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell try { 957199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell resName = getResources().getResourceName(getId()); 958199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } catch (Resources.NotFoundException e) { 959199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell resName = Integer.toHexString(getId()); 960199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } 961199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + 962199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " contents without calling PagerAdapter#notifyDataSetChanged!" + 963199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + 964199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Pager id: " + resName + 965199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Pager class: " + getClass() + 966199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell " Problematic adapter: " + mAdapter.getClass()); 967199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell } 968199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell 969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Locate the currently focused item or add it if needed. 970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int curIndex = -1; 971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo curItem = null; 972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (curIndex = 0; curIndex < mItems.size(); curIndex++) { 973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(curIndex); 974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position >= mCurItem) { 975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == mCurItem) curItem = ii; 976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 979d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem == null && N > 0) { 981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curItem = addNewItem(mCurItem, curIndex); 982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fill 3x the available width or up to the number of offscreen 985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // pages requested to either side, whichever is larger. 986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // If we have no current item we have no work to do. 987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (curItem != null) { 988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthLeft = 0.f; 989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = curIndex - 1; 990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 9914f4c3a3978997e552c44726fb2862e4461497384Adam Powell final int clientWidth = getClientWidth(); 9924f4c3a3978997e552c44726fb2862e4461497384Adam Powell final float leftWidthNeeded = clientWidth <= 0 ? 0 : 9934f4c3a3978997e552c44726fb2862e4461497384Adam Powell 2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth; 994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem - 1; pos >= 0; pos--) { 99531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { 996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 100271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 100371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 100471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 100571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1006a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex--; 1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1013a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 1014a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1015a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex + 1); 1016a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthLeft += ii.widthFactor; 1017a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell curIndex++; 1018a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; 10194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1022a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float extraWidthRight = curItem.widthFactor; 1023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex = curIndex + 1; 1024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (extraWidthRight < 2.f) { 1025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 10264f4c3a3978997e552c44726fb2862e4461497384Adam Powell final float rightWidthNeeded = clientWidth <= 0 ? 0 : 10274f4c3a3978997e552c44726fb2862e4461497384Adam Powell (float) getPaddingRight() / (float) clientWidth + 2.f; 1028a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = mCurItem + 1; pos < N; pos++) { 1029becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu if (extraWidthRight >= rightWidthNeeded && pos > endPos) { 1030a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii == null) { 1031a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; 1032a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1033a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position && !ii.scrolling) { 1034a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mItems.remove(itemIndex); 1035a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mAdapter.destroyItem(this, pos, ii.object); 103671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (DEBUG) { 103771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio Log.i(TAG, "populate() - destroyItem() with pos: " + pos + 103871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio " view: " + ((View) ii.object)); 103971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1040a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1041a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1042a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (ii != null && pos == ii.position) { 1043a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 1044a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 1047a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = addNewItem(pos, itemIndex); 1048a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1049a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell extraWidthRight += ii.widthFactor; 1050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; 1051a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1052a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1053d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1054a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1055a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell calculatePageOffsets(curItem, curIndex, oldCurInfo); 1056d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10584c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (DEBUG) { 10594c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "Current page list:"); 10604c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 10614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); 1062d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 10652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); 10662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10675c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.finishUpdate(this); 10682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 10697e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Check width measurement of current pages and drawing sort order. 10707e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell // Update LayoutParams as needed. 1071a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int childCount = getChildCount(); 1072a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < childCount; i++) { 1073a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1074a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 10757e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.childIndex = i; 1076a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && lp.widthFactor == 0.f) { 1077a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // 0 means requery the adapter for this, it doesn't have a valid width. 1078a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForChild(child); 1079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii != null) { 1080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.widthFactor = ii.widthFactor; 10817e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell lp.position = ii.position; 1082a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1085f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell sortChildDrawingOrder(); 1086a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 10872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (hasFocus()) { 10882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 1089218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; 10902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii == null || ii.position != mCurItem) { 10912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i=0; i<getChildCount(); i++) { 10922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 10932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ii = infoForChild(child); 10942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 1095860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu if (child.requestFocus(focusDirection)) { 10962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 10972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 10992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 11002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 11012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 1102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1104f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell private void sortChildDrawingOrder() { 1105f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mDrawingOrder != DRAW_ORDER_DEFAULT) { 1106f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell if (mDrawingOrderedChildren == null) { 1107f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren = new ArrayList<View>(); 1108f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } else { 1109f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren.clear(); 1110f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1111f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell final int childCount = getChildCount(); 1112f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell for (int i = 0; i < childCount; i++) { 1113f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell final View child = getChildAt(i); 1114f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell mDrawingOrderedChildren.add(child); 1115f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1116f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell Collections.sort(mDrawingOrderedChildren, sPositionComparator); 1117f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1118f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell } 1119f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell 1120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { 1121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int N = mAdapter.getCount(); 1122becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 1123a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 1124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Fix up offsets for later layout. 1125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurInfo != null) { 1126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int oldCurPosition = oldCurInfo.position; 1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base offsets off of oldCurInfo. 1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldCurPosition < curItem.position) { 1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 11316bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; 1132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition + 1; 1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos <= curItem.position && itemIndex < mItems.size(); pos++) { 1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < mItems.size() - 1) { 1136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex++; 1137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos) + marginOffset; 1143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos++; 1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else if (oldCurPosition > curItem.position) { 1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = mItems.size() - 1; 1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = null; 1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = oldCurInfo.offset; 1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = oldCurPosition - 1; 1153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos >= curItem.position && itemIndex >= 0; pos--) { 1154a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1155a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position && itemIndex > 0) { 1156a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell itemIndex--; 1157a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(itemIndex); 1158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1159a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // We don't have an item populated for this, 1161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // ask the adapter for an offset. 1162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos) + marginOffset; 1163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos--; 1164a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1165a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1166a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1167a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1168a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1169a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1171a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Base all offsets off of curItem. 1172a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 1173a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = curItem.offset; 1174a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int pos = curItem.position - 1; 1175a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; 117631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = curItem.position == N - 1 ? 117731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; 1178a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Previous pages 1179a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex - 1; i >= 0; i--, pos--) { 1180a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position) { 1182a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= mAdapter.getPageWidth(pos--) + marginOffset; 1183a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset -= ii.widthFactor + marginOffset; 1185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1186a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == 0) mFirstOffset = offset; 1187a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = curItem.offset + curItem.widthFactor + marginOffset; 1189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell pos = curItem.position + 1; 1190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Next pages 1191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = curIndex + 1; i < itemCount; i++, pos++) { 1192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = mItems.get(i); 1193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos < ii.position) { 1194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += mAdapter.getPageWidth(pos++) + marginOffset; 1195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 119631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell if (ii.position == N - 1) { 119731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell mLastOffset = offset + ii.widthFactor - 1; 119831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell } 1199a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = offset; 1200a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += ii.widthFactor + marginOffset; 1201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mNeedCalculatePageOffsets = false; 1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 12067dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 12077dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * This is the persistent state that is saved by ViewPager. Only needed 12087dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * if you are creating a sublass of ViewPager that must save its own 12097dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * state, in which case it should implement a subclass of this which 12107dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * contains that state. 12117dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 1212d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public static class SavedState extends BaseSavedState { 1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int position; 1214ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn Parcelable adapterState; 12155c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn ClassLoader loader; 1216d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState(Parcelable superState) { 1218d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(superState); 1219d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1222d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void writeToParcel(Parcel out, int flags) { 1223d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.writeToParcel(out, flags); 1224d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn out.writeInt(position); 12255c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn out.writeParcelable(adapterState, flags); 1226d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1227d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1228d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1229d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public String toString() { 1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return "FragmentPager.SavedState{" 1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + Integer.toHexString(System.identityHashCode(this)) 1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " position=" + position + "}"; 1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 12355c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public static final Parcelable.Creator<SavedState> CREATOR 12365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { 12375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 12385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState createFromParcel(Parcel in, ClassLoader loader) { 12395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState(in, loader); 12405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 12415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn @Override 12425c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn public SavedState[] newArray(int size) { 12435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn return new SavedState[size]; 12445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn } 12455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn }); 12465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn 12475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn SavedState(Parcel in, ClassLoader loader) { 1248d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super(in); 12495c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn if (loader == null) { 12505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn loader = getClass().getClassLoader(); 1251ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 12525c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn position = in.readInt(); 12535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn adapterState = in.readParcelable(loader); 12545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn this.loader = loader; 1255d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1259d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public Parcelable onSaveInstanceState() { 1260d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn Parcelable superState = super.onSaveInstanceState(); 1261d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = new SavedState(superState); 1262d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ss.position = mCurItem; 1263677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki if (mAdapter != null) { 1264677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki ss.adapterState = mAdapter.saveState(); 1265677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki } 1266d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ss; 1267d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void onRestoreInstanceState(Parcelable state) { 1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (!(state instanceof SavedState)) { 1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(state); 1273d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return; 1274d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1275d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1276d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn SavedState ss = (SavedState)state; 1277d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onRestoreInstanceState(ss.getSuperState()); 1278d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1279d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mAdapter != null) { 12805c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mAdapter.restoreState(ss.adapterState, ss.loader); 1281d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setCurrentItemInternal(ss.position, false, true); 1282d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1283d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mRestoredCurItem = ss.position; 1284ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn mRestoredAdapterState = ss.adapterState; 12855c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn mRestoredClassLoader = ss.loader; 1286d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1287d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 12908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void addView(View child, int index, ViewGroup.LayoutParams params) { 12911ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell if (!checkLayoutParams(params)) { 12921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell params = generateLayoutParams(params); 12931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell } 12941ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell final LayoutParams lp = (LayoutParams) params; 12951ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell lp.isDecor |= child instanceof Decor; 1296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mInLayout) { 12978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException("Cannot add pager decor view during layout"); 12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1300a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = true; 1301d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn addViewInLayout(child, index, params); 1302d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.addView(child, index, params); 1304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 1307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(mScrollingCacheEnabled); 1309d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } else { 1310d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(false); 1311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 131537a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase @Override 131637a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase public void removeView(View view) { 131737a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase if (mInLayout) { 131837a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase removeViewInLayout(view); 131937a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } else { 132037a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase super.removeView(view); 132137a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 132237a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase } 132337a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase 1324d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo infoForChild(View child) { 1325d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i=0; i<mItems.size(); i++) { 1326d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ItemInfo ii = mItems.get(i); 1327ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn if (mAdapter.isViewFromObject(child, ii.object)) { 1328d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return ii; 1329d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return null; 1332d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1333d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1334218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ItemInfo infoForAnyChild(View child) { 1335218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn ViewParent parent; 1336218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn while ((parent=child.getParent()) != this) { 1337218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (parent == null || !(parent instanceof View)) { 1338218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return null; 1339218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1340218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn child = (View)parent; 1341218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1342218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn return infoForChild(child); 1343218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn } 1344218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn 1345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo infoForPosition(int position) { 1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (ii.position == position) { 1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return ii; 1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return null; 1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1355d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1356ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn protected void onAttachedToWindow() { 1357ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn super.onAttachedToWindow(); 135897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = true; 1359ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn } 1360ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn 1361ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn @Override 1362d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1363fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell // For simple implementation, our internal size is always 0. 1364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // We depend on the container to specify the layout size of 1365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // our view. We can't really know what it is since we will be 1366d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // adding and removing different arbitrary views and do not 1367d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // want the layout to change as this happens. 1368d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), 1369d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn getDefaultSize(0, heightMeasureSpec)); 1370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 13718f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int measuredWidth = getMeasuredWidth(); 13728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell final int maxGutterSize = measuredWidth / 10; 13738f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); 13748f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 1375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Children are just made to fill our space. 13768f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); 13778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 13788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /* 13808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Make sure all children have been properly measured. Decor views first. 13818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Right now we cheat and make this less complicated by assuming decor 13828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * views won't intersect. We will pin to edges based on gravity. 13838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 1384862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell int size = getChildCount(); 13858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < size; ++i) { 13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 13878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 13888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 13898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp != null && lp.isDecor) { 13908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 13918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 13928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int widthMode = MeasureSpec.AT_MOST; 13938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int heightMode = MeasureSpec.AT_MOST; 13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; 13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; 13968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 13978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 13988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell widthMode = MeasureSpec.EXACTLY; 13998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 14008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell heightMode = MeasureSpec.EXACTLY; 14018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 1403a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int widthSize = childWidthSize; 1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int heightSize = childHeightSize; 1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.WRAP_CONTENT) { 1406a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthMode = MeasureSpec.EXACTLY; 1407a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.width != LayoutParams.FILL_PARENT) { 1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell widthSize = lp.width; 1409a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1410a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1411a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.WRAP_CONTENT) { 1412a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightMode = MeasureSpec.EXACTLY; 1413a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.height != LayoutParams.FILL_PARENT) { 1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell heightSize = lp.height; 1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); 1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 14198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.measure(widthSpec, heightSpec); 14208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (consumeVertical) { 14228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childHeightSize -= child.getMeasuredHeight(); 14238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } else if (consumeHorizontal) { 14248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childWidthSize -= child.getMeasuredWidth(); 14258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 14298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 14318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); 1432d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure we have created all fragments that we need to have shown. 1434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = true; 1435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn populate(); 1436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mInLayout = false; 1437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 14388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Page views next. 1439862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell size = getChildCount(); 1440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 1441d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 1442d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 1443d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child 14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ": " + mChildWidthMeasureSpec); 14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp == null || !lp.isDecor) { 1448a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1449a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); 1450a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, mChildHeightMeasureSpec); 14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1453d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1457d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1458d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn super.onSizeChanged(w, h, oldw, oldh); 1459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1460d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Make sure scroll position is set correctly. 1461053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell if (w != oldw) { 1462329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); 1463329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1464329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1465329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 1466329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { 146791eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell if (oldWidth > 0 && !mItems.isEmpty()) { 1468becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin; 1469becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight() 1470becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu + oldMargin; 14718d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final int xpos = getScrollX(); 14725f6568e7e269783e2668527461878cadfbe65215Adam Powell final float pageOffset = (float) xpos / oldWidthWithMargin; 14735f6568e7e269783e2668527461878cadfbe65215Adam Powell final int newOffsetPixels = (int) (pageOffset * widthWithMargin); 1474a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 14755f6568e7e269783e2668527461878cadfbe65215Adam Powell scrollTo(newOffsetPixels, getScrollY()); 1476329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (!mScroller.isFinished()) { 1477329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell // We now return to your regularly scheduled scroll, already in progress. 1478329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int newDuration = mScroller.getDuration() - mScroller.timePassed(); 1479a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo targetInfo = infoForPosition(mCurItem); 14805f6568e7e269783e2668527461878cadfbe65215Adam Powell mScroller.startScroll(newOffsetPixels, 0, 14818d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell (int) (targetInfo.offset * width), 0, newDuration); 1482329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 1483329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } else { 1484a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForPosition(mCurItem); 14858d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; 1486becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int scrollPos = (int) (scrollOffset * 1487becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu (width - getPaddingLeft() - getPaddingRight())); 1488329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell if (scrollPos != getScrollX()) { 148971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 1490053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell scrollTo(scrollPos, getScrollY()); 14919bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell } 1492d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1493d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1495d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1496d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn protected void onLayout(boolean changed, int l, int t, int r, int b) { 1497d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int count = getChildCount(); 14988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int width = r - l; 14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int height = b - t; 15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingTop = getPaddingTop(); 15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingBottom = getPaddingBottom(); 15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int decorCount = 0; 1507d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1508a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // First pass - decor views. We need to do this in two passes so that 1509a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // we have the proper offsets for non-decor views later. 1510d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < count; i++) { 15118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (child.getVisibility() != GONE) { 15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 15148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 15158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childTop = 0; 15168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (lp.isDecor) { 15178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 15188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; 15198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 15208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 15218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 15228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 15248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 15258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getMeasuredWidth(); 15268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 15288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 15298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 15308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 15328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 15338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 15348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (vgrav) { 15378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 15388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 15398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.TOP: 15418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = paddingTop; 15428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop += child.getMeasuredHeight(); 15438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_VERTICAL: 15458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = Math.max((height - child.getMeasuredHeight()) / 2, 15468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingTop); 15478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.BOTTOM: 15498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childTop = height - paddingBottom - child.getMeasuredHeight(); 15508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingBottom += child.getMeasuredHeight(); 15518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 15528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 15538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 1554abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1555abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1556abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 1557a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell decorCount++; 1558a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1559a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1560a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 1561a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1562becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int childWidth = width - paddingLeft - paddingRight; 1563a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Page views. Do this once we have the right padding offsets from above. 1564a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < count; i++) { 1565a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final View child = getChildAt(i); 1566a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (child.getVisibility() != GONE) { 1567a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1568a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii; 1569a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!lp.isDecor && (ii = infoForChild(child)) != null) { 1570becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu int loff = (int) (childWidth * ii.offset); 1571a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childLeft = paddingLeft + loff; 1572a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int childTop = paddingTop; 1573a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lp.needsMeasure) { 1574a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // This was added during layout and needs measurement. 1575a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Do it now that we know what we're working with. 1576a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lp.needsMeasure = false; 1577a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthSpec = MeasureSpec.makeMeasureSpec( 1578becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu (int) (childWidth * lp.widthFactor), 1579a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1580a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int heightSpec = MeasureSpec.makeMeasureSpec( 1581a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (int) (height - paddingTop - paddingBottom), 1582a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell MeasureSpec.EXACTLY); 1583a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell child.measure(widthSpec, heightSpec); 1584a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 15858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object 15868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() 15878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell + "x" + child.getMeasuredHeight()); 1588abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell child.layout(childLeft, childTop, 1589abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childLeft + child.getMeasuredWidth(), 1590abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell childTop + child.getMeasuredHeight()); 15918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 15948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mTopPageBounds = paddingTop; 15958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mBottomPageBounds = height - paddingBottom; 15968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mDecorChildCount = decorCount; 159744fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell 159844fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell if (mFirstLayout) { 159944fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell scrollToItem(mCurItem, false, 0, false); 160044fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell } 160197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell mFirstLayout = false; 1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1603d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1604d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public void computeScroll() { 1606a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { 1607a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldX = getScrollX(); 1608a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int oldY = getScrollY(); 1609a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int x = mScroller.getCurrX(); 1610a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int y = mScroller.getCurrY(); 16113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1612a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (oldX != x || oldY != y) { 1613a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell scrollTo(x, y); 16144783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!pageScrolled(x)) { 16154783095cc69fa85e484132337526c94d42d41c43Adam Powell mScroller.abortAnimation(); 16164783095cc69fa85e484132337526c94d42d41c43Adam Powell scrollTo(0, y); 16174783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1619a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 1620a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Keep on drawing until the animation has finished. 1621b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 1622a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell return; 1623d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 16244c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn 16254c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, clean up state. 162671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(true); 1627d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 16294783095cc69fa85e484132337526c94d42d41c43Adam Powell private boolean pageScrolled(int xpos) { 16304783095cc69fa85e484132337526c94d42d41c43Adam Powell if (mItems.size() == 0) { 16314783095cc69fa85e484132337526c94d42d41c43Adam Powell mCalledSuper = false; 16324783095cc69fa85e484132337526c94d42d41c43Adam Powell onPageScrolled(0, 0, 0); 16334783095cc69fa85e484132337526c94d42d41c43Adam Powell if (!mCalledSuper) { 16344783095cc69fa85e484132337526c94d42d41c43Adam Powell throw new IllegalStateException( 16354783095cc69fa85e484132337526c94d42d41c43Adam Powell "onPageScrolled did not call superclass implementation"); 16364783095cc69fa85e484132337526c94d42d41c43Adam Powell } 16374783095cc69fa85e484132337526c94d42d41c43Adam Powell return false; 16384783095cc69fa85e484132337526c94d42d41c43Adam Powell } 1639a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1640becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 1641a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int widthWithMargin = width + mPageMargin; 1642a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 1643a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 1644a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) xpos / width) - ii.offset) / 1645a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell (ii.widthFactor + marginOffset); 1646a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int offsetPixels = (int) (pageOffset * widthWithMargin); 16478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = false; 1649a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell onPageScrolled(currentPage, pageOffset, offsetPixels); 16508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!mCalledSuper) { 16518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell throw new IllegalStateException( 16528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell "onPageScrolled did not call superclass implementation"); 16538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16544783095cc69fa85e484132337526c94d42d41c43Adam Powell return true; 16558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 16568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 16588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * This method will be invoked when the current page is scrolled, either as part 16598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * of a programmatically initiated smooth scroll or a user initiated touch scroll. 16608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * If you override this method you must call through to the superclass implementation 16618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled 16628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * returns. 16638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * 16648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param position Position index of the first page currently being displayed. 16658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * Page position+1 will be visible if positionOffset is nonzero. 16668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offset Value from [0, 1) indicating the offset from the page at position. 16678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * @param offsetPixels Value in pixels indicating the offset from position. 16688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 16698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected void onPageScrolled(int position, float offset, int offsetPixels) { 16708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell // Offset any decor views if needed - keep them on-screen at all times. 16718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mDecorChildCount > 0) { 16728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int scrollX = getScrollX(); 16738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingLeft = getPaddingLeft(); 16748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int paddingRight = getPaddingRight(); 16758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int width = getWidth(); 16768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childCount = getChildCount(); 16778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell for (int i = 0; i < childCount; i++) { 16788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final View child = getChildAt(i); 16798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (!lp.isDecor) continue; 16818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 16828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; 16838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell int childLeft = 0; 16848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell switch (hgrav) { 16858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell default: 16868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.LEFT: 16898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = paddingLeft; 16908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft += child.getWidth(); 16918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.CENTER_HORIZONTAL: 16938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = Math.max((width - child.getMeasuredWidth()) / 2, 16948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingLeft); 16958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 16968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell case Gravity.RIGHT: 16978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft = width - paddingRight - child.getMeasuredWidth(); 16988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell paddingRight += child.getMeasuredWidth(); 16998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell break; 17008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell childLeft += scrollX; 17028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 17038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final int childOffset = childLeft - child.getLeft(); 17048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (childOffset != 0) { 17058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell child.offsetLeftAndRight(childOffset); 17068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 17108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mOnPageChangeListener != null) { 17118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); 17128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell if (mInternalPageChangeListener != null) { 17148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); 17158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 17178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell if (mPageTransformer != null) { 17188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int scrollX = getScrollX(); 17198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 17208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 17218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final View child = getChildAt(i); 17227e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 17247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (lp.isDecor) continue; 17257e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 1726becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); 17278a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell mPageTransformer.transformPage(child, transformPos); 17288a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17298a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17308a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 17318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell mCalledSuper = true; 17328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 17338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 173471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio private void completeScroll(boolean postEvents) { 17358d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; 1736cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham if (needPopulate) { 17374c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn // Done with scroll, no longer want to cache view drawing. 17384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn setScrollingCacheEnabled(false); 1739d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScroller.abortAnimation(); 1740d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldX = getScrollX(); 1741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int oldY = getScrollY(); 1742d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int x = mScroller.getCurrX(); 1743d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn int y = mScroller.getCurrY(); 1744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (oldX != x || oldY != y) { 1745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn scrollTo(x, y); 1746d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 17474c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17483661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mPopulatePending = false; 17494c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn for (int i=0; i<mItems.size(); i++) { 17504c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ItemInfo ii = mItems.get(i); 17514c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (ii.scrolling) { 17524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn needPopulate = true; 17534c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn ii.scrolling = false; 17544c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17554c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn } 17564c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn if (needPopulate) { 175771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio if (postEvents) { 175871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio ViewCompat.postOnAnimation(this, mEndScrollRunnable); 175971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } else { 176071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio mEndScrollRunnable.run(); 176171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio } 1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 17658f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell private boolean isGutterDrag(float x, float dx) { 17668f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); 17678f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell } 17688f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell 17698a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell private void enableLayers(boolean enable) { 17708a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int childCount = getChildCount(); 17718a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell for (int i = 0; i < childCount; i++) { 17728a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell final int layerType = enable ? 17738a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; 17748a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell ViewCompat.setLayerType(getChildAt(i), layerType, null); 17758a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17768a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell } 17778a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell 1778d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1779d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onInterceptTouchEvent(MotionEvent ev) { 1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * This method JUST determines whether we want to intercept the motion. 1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * If we return true, onMotionEvent will be called and we do the actual 1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * scrolling there. 1784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Always take care of the touch gesture being complete. 1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Release the drag. 1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept done!"); 1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 17953ce9274ccb8034c1787415c77307bbda36071bddAdam Powell if (mVelocityTracker != null) { 17963ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker.recycle(); 17973ce9274ccb8034c1787415c77307bbda36071bddAdam Powell mVelocityTracker = null; 17983ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Nothing more to do here if we have decided whether or not we 1803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // are dragging. 1804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (action != MotionEvent.ACTION_DOWN) { 1805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning true!"); 1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1809d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsUnableToDrag) { 1810d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Intercept returning false!"); 1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1814d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1815d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action) { 1816d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: { 1817d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 1819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * whether the user has moved far enough from his original down touch. 1820d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1821d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1822d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1823d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Locally do absolute value. mLastMotionY is set to the y value 1824d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * of the down event. 1825d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1826d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerId = mActivePointerId; 1827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (activePointerId == INVALID_POINTER) { 1828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // If we don't have a valid id, the touch down wasn't on content. 1829d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1832d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); 1833d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, pointerIndex); 183447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float dx = x - mLastMotionX; 183547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(dx); 1836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float y = MotionEventCompat.getY(ev, pointerIndex); 183716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float yDiff = Math.abs(y - mInitialMotionY); 1838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 1839bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 18408f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && 18418f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell canScroll(this, false, (int) dx, (int) x, (int) y)) { 1842bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Nested view has scrollable area under this point. Let it be handled there. 184316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionX = x; 1844bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell mLastMotionY = y; 1845b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = true; 1846bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return false; 1847bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 184816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) { 1849d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Starting drag!"); 1850d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = true; 185147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 18528d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : 18538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 185416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 1855d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn setScrollingCacheEnabled(true); 185616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell } else if (yDiff > mTouchSlop) { 185716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // The finger has moved enough in the vertical 185816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // direction to be counted as a drag... abort 185916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // any attempt to drag horizontally, to work correctly 186016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell // with children that have scrolling containers. 186116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell if (DEBUG) Log.v(TAG, "Starting unable to drag!"); 186216991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mIsUnableToDrag = true; 1863d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 18646e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (mIsBeingDragged) { 18656e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Scroll to follow the motion event 18666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (performDrag(x)) { 18676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell ViewCompat.postInvalidateOnAnimation(this); 18686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 18696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 1870d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1871d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1872d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1873d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 1874d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 1875d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Remember location of down touch. 1876d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * ACTION_DOWN always refers to pointer index 0. 1877d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */ 1878d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 187916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1880d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1881b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell mIsUnableToDrag = false; 1882d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 18838d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.computeScrollOffset(); 1884b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell if (mScrollState == SCROLL_STATE_SETTLING && 1885b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { 188647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell // Let the user 'catch' the pager as it animates. 18878d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 18888d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 18898d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 189047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = true; 189147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 189247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } else { 189371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio completeScroll(false); 189447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell mIsBeingDragged = false; 189547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell } 1896d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1897d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY 1898d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + " mIsBeingDragged=" + mIsBeingDragged 1899d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn + "mIsUnableToDrag=" + mIsUnableToDrag); 1900d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1901d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1902d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1903d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 1904d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 1905d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1906d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1907d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19088d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell if (mVelocityTracker == null) { 19098d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker = VelocityTracker.obtain(); 19103ce9274ccb8034c1787415c77307bbda36071bddAdam Powell } 19118d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mVelocityTracker.addMovement(ev); 19123ce9274ccb8034c1787415c77307bbda36071bddAdam Powell 1913d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn /* 19143ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * The only time we want to intercept motion events is if we are in the 19153ce9274ccb8034c1787415c77307bbda36071bddAdam Powell * drag mode. 19163ce9274ccb8034c1787415c77307bbda36071bddAdam Powell */ 1917d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return mIsBeingDragged; 1918d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1919d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1920d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn @Override 1921d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn public boolean onTouchEvent(MotionEvent ev) { 192269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mFakeDragging) { 192369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // A fake drag is in progress already, ignore this real one 192469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // but still eat the touch events. 192569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // (It is likely that the user is multi-touching the screen.) 192669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 192769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 1928d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1929d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { 1930d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Don't handle edge touches immediately -- they may actually belong to one of our 1931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // descendants. 1932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return false; 1933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 19353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (mAdapter == null || mAdapter.getCount() == 0) { 19363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell // Nothing to present or scroll; nothing to touch. 19373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell return false; 19383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 19393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 1940d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker == null) { 1941d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = VelocityTracker.obtain(); 1942d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1943d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.addMovement(ev); 1944d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1945d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int action = ev.getAction(); 1946560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 1947d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1948d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn switch (action & MotionEventCompat.ACTION_MASK) { 1949d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_DOWN: { 19508d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mScroller.abortAnimation(); 19518d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mPopulatePending = false; 19528d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell populate(); 19538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mIsBeingDragged = true; 19548d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell setScrollState(SCROLL_STATE_DRAGGING); 1955d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 1956d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Remember where the motion event started 1957d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = mInitialMotionX = ev.getX(); 195816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = mInitialMotionY = ev.getY(); 1959d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 1960d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1961d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1962d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_MOVE: 19633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (!mIsBeingDragged) { 19643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 19653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float x = MotionEventCompat.getX(ev, pointerIndex); 196647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float xDiff = Math.abs(x - mLastMotionX); 19673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell final float y = MotionEventCompat.getY(ev, pointerIndex); 196847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell final float yDiff = Math.abs(y - mLastMotionY); 19693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 19703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (xDiff > mTouchSlop && xDiff > yDiff) { 19713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell if (DEBUG) Log.v(TAG, "Starting drag!"); 19723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell mIsBeingDragged = true; 19738d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : 19748d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell mInitialMotionX - mTouchSlop; 197516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell mLastMotionY = y; 197647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 19773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell setScrollingCacheEnabled(true); 19783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 19793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 198031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell // Not else! Note that mIsBeingDragged can be set above. 1981d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1982d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // Scroll to follow the motion event 1983d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int activePointerIndex = MotionEventCompat.findPointerIndex( 1984d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn ev, mActivePointerId); 1985d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, activePointerIndex); 19866e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate |= performDrag(x); 1987d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 1988d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 1989d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_UP: 1990d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 1991d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final VelocityTracker velocityTracker = mVelocityTracker; 1992d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 19931cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 1994d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn velocityTracker, mActivePointerId); 1995d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mPopulatePending = true; 1996becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 19971cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell final int scrollX = getScrollX(); 1998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 1999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2001035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int activePointerIndex = 2002035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell MotionEventCompat.findPointerIndex(ev, mActivePointerId); 2003035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final float x = MotionEventCompat.getX(ev, activePointerIndex); 2004035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int totalDelta = (int) (x - mInitialMotionX); 2005035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2006035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell totalDelta); 20071cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 2008d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2009d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 2010d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 2011560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 2012d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2013d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2014d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEvent.ACTION_CANCEL: 2015d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mIsBeingDragged) { 2016a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne scrollToItem(mCurItem, true, 0, false); 2017d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = INVALID_POINTER; 2018d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn endDrag(); 2019560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); 2020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_DOWN: { 2023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int index = MotionEventCompat.getActionIndex(ev); 2024d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final float x = MotionEventCompat.getX(ev, index); 2025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = x; 2026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, index); 2027d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn case MotionEventCompat.ACTION_POINTER_UP: 2030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn onSecondaryPointerUp(ev); 2031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, 2032d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 2033d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn break; 2034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2035560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 2036b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 2037560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn return true; 2039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 20416e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell private boolean performDrag(float x) { 20426e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean needsInvalidate = false; 20436e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20446e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final float deltaX = mLastMotionX - x; 20456e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX = x; 20466e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20476e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float oldScrollX = getScrollX(); 20486e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float scrollX = oldScrollX + deltaX; 2049becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 20506e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20516e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float leftBound = width * mFirstOffset; 20526e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float rightBound = width * mLastOffset; 20536e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean leftAbsolute = true; 20546e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell boolean rightAbsolute = true; 20556e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20566e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo firstItem = mItems.get(0); 20576e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 20586e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (firstItem.position != 0) { 20596e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftAbsolute = false; 20606e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell leftBound = firstItem.offset * width; 20616e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20626e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (lastItem.position != mAdapter.getCount() - 1) { 20636e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightAbsolute = false; 20646e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell rightBound = lastItem.offset * width; 20656e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (scrollX < leftBound) { 20686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (leftAbsolute) { 20696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = leftBound - scrollX; 20706e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); 20716e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20726e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = leftBound; 20736e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } else if (scrollX > rightBound) { 20746e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell if (rightAbsolute) { 20756e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell float over = scrollX - rightBound; 20766e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); 20776e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20786e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollX = rightBound; 20796e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20806e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell // Don't lose the rounded component 20816e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell mLastMotionX += scrollX - (int) scrollX; 20826e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell scrollTo((int) scrollX, getScrollY()); 20836e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell pageScrolled((int) scrollX); 20846e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 20856e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell return needsInvalidate; 20866e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell } 20876e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell 2088a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2089a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * @return Info about the page at the current scroll position. 2090a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * This can be synthetic for a missing middle page; the 'object' field can be null. 2091a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 2092a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell private ItemInfo infoForCurrentScrollPosition() { 2093becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 2094a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; 2095a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; 2096a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int lastPos = -1; 2097a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastOffset = 0.f; 2098a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float lastWidth = 0.f; 2099a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell boolean first = true; 2100a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2101ad079a869adf67a87a2721342de27970a3ba1844Adam Powell ItemInfo lastItem = null; 2102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int i = 0; i < mItems.size(); i++) { 2103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(i); 2104a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset; 2105a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (!first && ii.position != lastPos + 1) { 2106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Create a synthetic item for a missing page. 2107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mTempItem; 2108a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.offset = lastOffset + lastWidth + marginOffset; 2109a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.position = lastPos + 1; 2110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii.widthFactor = mAdapter.getPageWidth(ii.position); 2111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell i--; 2112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset; 2114a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 21158d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float leftBound = offset; 21168d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell final float rightBound = offset + ii.widthFactor + marginOffset; 2117ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (first || scrollOffset >= leftBound) { 2118ad079a869adf67a87a2721342de27970a3ba1844Adam Powell if (scrollOffset < rightBound || i == mItems.size() - 1) { 2119ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return ii; 2120ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } 2121ad079a869adf67a87a2721342de27970a3ba1844Adam Powell } else { 2122ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2123a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell first = false; 2125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastPos = ii.position; 2126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastOffset = offset; 2127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell lastWidth = ii.widthFactor; 2128ad079a869adf67a87a2721342de27970a3ba1844Adam Powell lastItem = ii; 2129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2131ad079a869adf67a87a2721342de27970a3ba1844Adam Powell return lastItem; 2132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2134035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { 2135035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell int targetPage; 2136035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { 2137035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell targetPage = velocity > 0 ? currentPage : currentPage + 1; 2138035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } else { 213916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; 214016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell targetPage = (int) (currentPage + pageOffset + truncator); 2141035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2142035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mItems.size() > 0) { 2144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Only let the user target pages we have items for 2148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); 2149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2151035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell return targetPage; 2152035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell } 2153035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell 2154560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell @Override 2155560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell public void draw(Canvas canvas) { 2156560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell super.draw(canvas); 2157560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell boolean needsInvalidate = false; 2158560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2159560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int overScrollMode = ViewCompat.getOverScrollMode(this); 2160560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 2161560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && 2162560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mAdapter != null && mAdapter.getCount() > 1)) { 2163560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mLeftEdge.isFinished()) { 2164560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2165560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2166a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int width = getWidth(); 2167560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2168560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(270); 2169a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-height + getPaddingTop(), mFirstOffset * width); 2170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mLeftEdge.setSize(height, width); 2171560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mLeftEdge.draw(canvas); 2172560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2173560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2174560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (!mRightEdge.isFinished()) { 2175560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int restoreCount = canvas.save(); 2176560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int width = getWidth(); 2177560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 2178560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2179560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.rotate(90); 2180a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); 2181560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.setSize(height, width); 2182560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell needsInvalidate |= mRightEdge.draw(canvas); 2183560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell canvas.restoreToCount(restoreCount); 2184560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2185560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } else { 2186560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mLeftEdge.finish(); 2187560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell mRightEdge.finish(); 2188560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2189560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2190560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell if (needsInvalidate) { 2191560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell // Keep animating 2192b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell ViewCompat.postInvalidateOnAnimation(this); 2193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell } 2195560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell 2196329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell @Override 2197329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell protected void onDraw(Canvas canvas) { 2198329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell super.onDraw(canvas); 2199329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 2200a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell // Draw the margin drawable between pages if needed. 2201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { 2202329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int scrollX = getScrollX(); 2203329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell final int width = getWidth(); 2204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float marginOffset = (float) mPageMargin / width; 2206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int itemIndex = 0; 2207a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ItemInfo ii = mItems.get(0); 2208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float offset = ii.offset; 2209a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int itemCount = mItems.size(); 2210a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int firstPos = ii.position; 2211a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int lastPos = mItems.get(itemCount - 1).position; 2212a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell for (int pos = firstPos; pos < lastPos; pos++) { 2213a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell while (pos > ii.position && itemIndex < itemCount) { 2214a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell ii = mItems.get(++itemIndex); 2215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 221723b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell float drawAt; 2218a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (pos == ii.position) { 221923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (ii.offset + ii.widthFactor) * width; 2220a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset = ii.offset + ii.widthFactor + marginOffset; 2221a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } else { 2222a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float widthFactor = mAdapter.getPageWidth(pos); 222323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell drawAt = (offset + widthFactor) * width; 2224a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell offset += widthFactor + marginOffset; 2225a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt + mPageMargin > scrollX) { 2228a56d6faa9df608aaa2907864669800abb68acec7Adam Powell mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, 222923b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); 2230a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell mMarginDrawable.draw(canvas); 2231a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2232a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2233a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (drawAt > scrollX + width) { 2234a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell break; // No more visible, no sense in continuing 2235a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2236329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2237329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2238329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell } 2239329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell 224069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 224169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Start a fake drag of the pager. 224269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 224369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager 224469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * with the touch scrolling of another view, while still letting the ViewPager 224569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) 224669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call 224769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. 224869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 224969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag 225069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * is already in progress, this method will return false. 225169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 225269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if the fake drag began successfully, false if it could not be started. 225369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 225469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 225569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 225669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 225769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean beginFakeDrag() { 225869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mIsBeingDragged) { 225969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return false; 226069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 226169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = true; 226269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell setScrollState(SCROLL_STATE_DRAGGING); 226369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mInitialMotionX = mLastMotionX = 0; 226469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (mVelocityTracker == null) { 226569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker = VelocityTracker.obtain(); 226669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else { 226769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.clear(); 226869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 226969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 227069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); 227169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 227269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 227369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragBeginTime = time; 227469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return true; 227569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 227669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 227769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 227869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * End a fake drag of the pager. 227969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 228069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 228169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 228269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 228369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void endFakeDrag() { 228469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 228569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 228669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 228769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 228869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 228969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 22900f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( 229169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell velocityTracker, mActivePointerId); 229269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mPopulatePending = true; 2293becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 2294035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell final int scrollX = getScrollX(); 2295a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo ii = infoForCurrentScrollPosition(); 2296a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int currentPage = ii.position; 2297a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; 2298a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final int totalDelta = (int) (mLastMotionX - mInitialMotionX); 2299a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, 2300a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell totalDelta); 2301035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell setCurrentItemInternal(nextPage, true, true, initialVelocity); 230269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell endDrag(); 230369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 230469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mFakeDragging = false; 230569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 230669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 230769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 230869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. 230969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 231069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @param xOffset Offset in pixels to drag by. 231169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 231269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 231369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 231469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public void fakeDragBy(float xOffset) { 231569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (!mFakeDragging) { 231669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); 231769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 231869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 231969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += xOffset; 2320a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2321a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float oldScrollX = getScrollX(); 23220f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell float scrollX = oldScrollX - xOffset; 2323becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu final int width = getClientWidth(); 232469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2325a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float leftBound = width * mFirstOffset; 2326a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell float rightBound = width * mLastOffset; 2327a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2328a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo firstItem = mItems.get(0); 2329a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell final ItemInfo lastItem = mItems.get(mItems.size() - 1); 2330a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (firstItem.position != 0) { 2331a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell leftBound = firstItem.offset * width; 2332a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2333a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell if (lastItem.position != mAdapter.getCount() - 1) { 2334a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell rightBound = lastItem.offset * width; 2335a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell } 2336a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 233769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell if (scrollX < leftBound) { 233869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = leftBound; 233969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } else if (scrollX > rightBound) { 234069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollX = rightBound; 234169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 234269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Don't lose the rounded component 234369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX += scrollX - (int) scrollX; 234469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell scrollTo((int) scrollX, getScrollY()); 23458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell pageScrolled((int) scrollX); 234669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 234769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell // Synthesize an event for the VelocityTracker. 234869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final long time = SystemClock.uptimeMillis(); 234969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, 235069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mLastMotionX, 0, 0); 235169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell mVelocityTracker.addMovement(ev); 235269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell ev.recycle(); 235369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 235469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 235569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell /** 235669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * Returns true if a fake drag is in progress. 235769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 235869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @return true if currently in a fake drag, false otherwise. 235969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * 236069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #beginFakeDrag() 236169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #fakeDragBy(float) 236269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell * @see #endFakeDrag() 236369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell */ 236469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell public boolean isFakeDragging() { 236569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell return mFakeDragging; 236669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell } 236769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell 2368d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void onSecondaryPointerUp(MotionEvent ev) { 2369d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerIndex = MotionEventCompat.getActionIndex(ev); 2370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 2371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (pointerId == mActivePointerId) { 2372d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // This was our active pointer going up. Choose a new 2373d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn // active pointer and adjust accordingly. 2374d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 2375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); 2376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 2377d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2378d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.clear(); 2379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2381d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2382d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2383d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void endDrag() { 2384d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsBeingDragged = false; 2385d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mIsUnableToDrag = false; 2386d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mVelocityTracker != null) { 2388d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker.recycle(); 2389d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mVelocityTracker = null; 2390d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn 2393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn private void setScrollingCacheEnabled(boolean enabled) { 2394d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (mScrollingCacheEnabled != enabled) { 2395d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn mScrollingCacheEnabled = enabled; 2396d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (USE_CACHE) { 2397d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final int size = getChildCount(); 2398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn for (int i = 0; i < size; ++i) { 2399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn final View child = getChildAt(i); 2400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn if (child.getVisibility() != GONE) { 2401d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn child.setDrawingCacheEnabled(enabled); 2402d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2404d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2405d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 2406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn } 24073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell 2408bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell /** 2409cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * Tests scrollability within child views of v given a delta of dx. 2410bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * 2411bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param v View to test for horizontal scrollability 2412bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param checkV Whether the view v passed should itself be checked for scrollability (true), 2413bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * or just its children (false). 2414bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param dx Delta scrolled in pixels 2415cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @param x X coordinate of the active touch point 2416bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell * @param y Y coordinate of the active touch point 2417cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham * @return true if child views of v can be scrolled by delta of dx. 2418bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell */ 2419cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 2420bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (v instanceof ViewGroup) { 2421bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final ViewGroup group = (ViewGroup) v; 2422bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollX = v.getScrollX(); 2423bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int scrollY = v.getScrollY(); 2424bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final int count = group.getChildCount(); 2425bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // Count backwards - let topmost views consume scroll distance first. 2426bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell for (int i = count - 1; i >= 0; i--) { 2427bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // TODO: Add versioned support here for transformed views. 2428bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell // This will not work for transformed views in Honeycomb+ 2429bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell final View child = group.getChildAt(i); 2430bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && 2431bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && 2432bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell canScroll(child, true, dx, x + scrollX - child.getLeft(), 2433bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell y + scrollY - child.getTop())) { 2434bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return true; 2435bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2436bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2437bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2438bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2439bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell return checkV && ViewCompat.canScrollHorizontally(v, -dx); 2440bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell } 2441bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell 2442481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 24432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean dispatchKeyEvent(KeyEvent event) { 24442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Let the focused view and/or our descendants get the key first 24452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return super.dispatchKeyEvent(event) || executeKeyEvent(event); 24462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 24492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * You can call this function yourself to have the scroll view perform 24502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * scrolling from a key event, just as if the event had been dispatched to 24512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * it by the view hierarchy. 24522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * 24532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @param event The key event to execute. 24542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * @return Return true if the event was handled, else false. 24552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 24562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean executeKeyEvent(KeyEvent event) { 24572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 24582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (event.getAction() == KeyEvent.ACTION_DOWN) { 24592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn switch (event.getKeyCode()) { 24602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_LEFT: 24612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_LEFT); 24622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_DPAD_RIGHT: 24642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = arrowScroll(FOCUS_RIGHT); 24652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn case KeyEvent.KEYCODE_TAB: 24675de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (Build.VERSION.SDK_INT >= 11) { 24685de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD 24695de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell // before Android 3.0. Ignore the tab key on those devices. 24705de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell if (KeyEventCompat.hasNoModifiers(event)) { 24715de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_FORWARD); 24725de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { 24735de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell handled = arrowScroll(FOCUS_BACKWARD); 24745de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell } 24752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn break; 24772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 24802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 24812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 24822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public boolean arrowScroll(int direction) { 24832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View currentFocused = findFocus(); 248431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (currentFocused == this) { 248531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell currentFocused = null; 248631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } else if (currentFocused != null) { 248731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell boolean isChild = false; 248831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; 248931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell parent = parent.getParent()) { 249031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (parent == this) { 249131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell isChild = true; 249231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell break; 249331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 249431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 249531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell if (!isChild) { 249631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell // This would cause the focus search down below to fail in fun ways. 249731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell final StringBuilder sb = new StringBuilder(); 249831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell sb.append(currentFocused.getClass().getSimpleName()); 249931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; 250031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell parent = parent.getParent()) { 250131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell sb.append(" => ").append(parent.getClass().getSimpleName()); 250231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 250331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell Log.e(TAG, "arrowScroll tried to find focus based on non-child " + 250431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell "current focused view " + sb.toString()); 250531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell currentFocused = null; 250631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 250731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell } 25082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean handled = false; 25102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, 25122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn direction); 25132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (nextFocused != null && nextFocused != currentFocused) { 25142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (direction == View.FOCUS_LEFT) { 25152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the left, or this is causing us to 25162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the right, then what we really want to do is page left. 2517dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2518dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2519dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft >= currLeft) { 25202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 25212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 25222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 25232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == View.FOCUS_RIGHT) { 25252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // If there is nothing to the right, or this is causing us to 25262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // jump to the left, then what we really want to do is page right. 2527dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; 2528dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; 2529dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (currentFocused != null && nextLeft <= currLeft) { 25302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 25312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 25322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = nextFocused.requestFocus(); 25332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { 25362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move left and nothing there; try to page. 25372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageLeft(); 25382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { 25392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Trying to move right and nothing there; try to page. 25402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn handled = pageRight(); 25412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (handled) { 25432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 25442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return handled; 25462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 2548dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { 2549dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell if (outRect == null) { 2550dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect = new Rect(); 2551dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2552efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell if (child == null) { 2553efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell outRect.set(0, 0, 0, 0); 2554efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell return outRect; 2555efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell } 2556dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left = child.getLeft(); 2557dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right = child.getRight(); 2558dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top = child.getTop(); 2559dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom = child.getBottom(); 2560dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2561dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell ViewParent parent = child.getParent(); 2562dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell while (parent instanceof ViewGroup && parent != this) { 2563dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell final ViewGroup group = (ViewGroup) parent; 2564dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.left += group.getLeft(); 2565dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.right += group.getRight(); 2566dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.top += group.getTop(); 2567dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell outRect.bottom += group.getBottom(); 2568dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 2569dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell parent = group.getParent(); 2570dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2571dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell return outRect; 2572dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell } 2573dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell 25742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageLeft() { 25752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (mCurItem > 0) { 25762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem-1, true); 25772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 25782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 25802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn boolean pageRight() { 2583218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { 25842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn setCurrentItem(mCurItem+1, true); 25852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 25862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 25882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 25892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 25912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 25922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 25932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 25942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 25952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int focusableCount = views.size(); 25962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final int descendantFocusability = getDescendantFocusability(); 25982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 25992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 26002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 26012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 26022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 26032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 26042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 26052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addFocusables(views, direction, focusableMode); 26062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we add ourselves (if focusable) in all cases except for when we are 26122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 26132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // to avoid the focus search finding layouts when a more precise search 26142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // among the focusable children would be more interesting. 26152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ( 26162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn descendantFocusability != FOCUS_AFTER_DESCENDANTS || 26172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // No focusable descendants 26182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn (focusableCount == views.size())) { 26192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we can't call the superclass here, because it will 26202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // add all views in. So we need to do the same thing View does. 26212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (!isFocusable()) { 26222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 26232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 26252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn isInTouchMode() && !isFocusableInTouchMode()) { 26262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return; 26272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (views != null) { 26292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn views.add(this); 26302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 26352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be touchable. 26362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 26372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 26382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn public void addTouchables(ArrayList<View> views) { 26392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // Note that we don't call super.addTouchables(), which means that 26402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // we don't call View.addTouchables(). This is okay because a ViewPager 26412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn // is itself not touchable. 26422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = 0; i < getChildCount(); i++) { 26432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn final View child = getChildAt(i); 26442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 26452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 26462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 26472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn child.addTouchables(views); 26482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn 26532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn /** 26542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn * We only want the current page that is being shown to be focusable. 26552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn */ 26562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn @Override 26572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn protected boolean onRequestFocusInDescendants(int direction, 26582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn Rect previouslyFocusedRect) { 26592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int index; 26602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int increment; 26612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int end; 26622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn int count = getChildCount(); 26632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if ((direction & FOCUS_FORWARD) != 0) { 26642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = 0; 26652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = 1; 26662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = count; 26672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } else { 26682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn index = count - 1; 26692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn increment = -1; 26702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn end = -1; 26712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn for (int i = index; i != end; i += increment) { 26732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn View child = getChildAt(i); 26742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.getVisibility() == VISIBLE) { 26752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn ItemInfo ii = infoForChild(child); 26762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (ii != null && ii.position == mCurItem) { 26772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn if (child.requestFocus(direction, previouslyFocusedRect)) { 26782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return true; 26792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 26812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn } 2682481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 26832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn return false; 2684481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2685481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2686481243c175651c5de0741ab9390eb10f5b024d98Adam Powell @Override 2687481243c175651c5de0741ab9390eb10f5b024d98Adam Powell public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2688109e561bfa6720a7043a28dc265297d915170954Alan Viverette // Dispatch scroll events from this ViewPager. 2689109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) { 2690109e561bfa6720a7043a28dc265297d915170954Alan Viverette return super.dispatchPopulateAccessibilityEvent(event); 2691109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 2692481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2693109e561bfa6720a7043a28dc265297d915170954Alan Viverette // Dispatch all other accessibility events from the current page. 2694481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final int childCount = getChildCount(); 2695481243c175651c5de0741ab9390eb10f5b024d98Adam Powell for (int i = 0; i < childCount; i++) { 2696481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final View child = getChildAt(i); 2697481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (child.getVisibility() == VISIBLE) { 2698481243c175651c5de0741ab9390eb10f5b024d98Adam Powell final ItemInfo ii = infoForChild(child); 2699481243c175651c5de0741ab9390eb10f5b024d98Adam Powell if (ii != null && ii.position == mCurItem && 2700481243c175651c5de0741ab9390eb10f5b024d98Adam Powell child.dispatchPopulateAccessibilityEvent(event)) { 2701481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return true; 2702481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2703481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2704481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2705481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 2706481243c175651c5de0741ab9390eb10f5b024d98Adam Powell return false; 2707481243c175651c5de0741ab9390eb10f5b024d98Adam Powell } 2708481243c175651c5de0741ab9390eb10f5b024d98Adam Powell 27098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 27118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return new LayoutParams(); 27128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 27168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return generateDefaultLayoutParams(); 27178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 27218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell return p instanceof LayoutParams && super.checkLayoutParams(p); 27228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 27248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 27261ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell return new LayoutParams(getContext(), attrs); 27278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 272925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov class MyAccessibilityDelegate extends AccessibilityDelegateCompat { 273025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 273125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 273225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 273325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityEvent(host, event); 273425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov event.setClassName(ViewPager.class.getName()); 27359a95c60a9c9fcc7d5ca0f9aeaede854d2a47a824Ying Wang final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain(); 2736109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setScrollable(canScroll()); 2737e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED 2738e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav && mAdapter != null) { 2739109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setItemCount(mAdapter.getCount()); 2740109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setFromIndex(mCurItem); 2741109e561bfa6720a7043a28dc265297d915170954Alan Viverette recordCompat.setToIndex(mCurItem); 2742109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 274325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 274425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 274525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 274625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 274725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(host, info); 274825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.setClassName(ViewPager.class.getName()); 2749109e561bfa6720a7043a28dc265297d915170954Alan Viverette info.setScrollable(canScroll()); 2750109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (canScrollForward()) { 275125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 275225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 2753109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (canScrollBackward()) { 275425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 275525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 275625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 275725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 275825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov @Override 275925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov public boolean performAccessibilityAction(View host, int action, Bundle args) { 276025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov if (super.performAccessibilityAction(host, action, args)) { 276125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 276225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 276325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov switch (action) { 276425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { 2765109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (canScrollForward()) { 276625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem + 1); 276725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 276825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 276925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 277025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { 2771109e561bfa6720a7043a28dc265297d915170954Alan Viverette if (canScrollBackward()) { 277225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov setCurrentItem(mCurItem - 1); 277325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return true; 277425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 277525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } return false; 277625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 277725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov return false; 277825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 2779109e561bfa6720a7043a28dc265297d915170954Alan Viverette 2780109e561bfa6720a7043a28dc265297d915170954Alan Viverette private boolean canScroll() { 2781109e561bfa6720a7043a28dc265297d915170954Alan Viverette return (mAdapter != null) && (mAdapter.getCount() > 1); 2782109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 2783109e561bfa6720a7043a28dc265297d915170954Alan Viverette 2784109e561bfa6720a7043a28dc265297d915170954Alan Viverette private boolean canScrollForward() { 2785109e561bfa6720a7043a28dc265297d915170954Alan Viverette return (mAdapter != null) && (mCurItem >= 0) && (mCurItem < (mAdapter.getCount() - 1)); 2786109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 2787109e561bfa6720a7043a28dc265297d915170954Alan Viverette 2788109e561bfa6720a7043a28dc265297d915170954Alan Viverette private boolean canScrollBackward() { 2789109e561bfa6720a7043a28dc265297d915170954Alan Viverette return (mAdapter != null) && (mCurItem > 0) && (mCurItem < mAdapter.getCount()); 2790109e561bfa6720a7043a28dc265297d915170954Alan Viverette } 279125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov } 279225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov 27938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell private class PagerObserver extends DataSetObserver { 27948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell @Override 27958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onChanged() { 27968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell dataSetChanged(); 27978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 27983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell @Override 27998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public void onInvalidated() { 28003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell dataSetChanged(); 28013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 28023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell } 28038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28047dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn /** 28057dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Layout parameters that should be supplied for views added to a 28067dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager. 28077dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn */ 28088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public static class LayoutParams extends ViewGroup.LayoutParams { 28098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell /** 28108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * true if this view is a decoration on the pager itself and not 28118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell * a view supplied by the adapter. 28128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell */ 28138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public boolean isDecor; 28148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 28163d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn * Gravity setting for use on decor views only: 28177dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Where to position the view page within the overall ViewPager 28187dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * container; constants are defined in {@link android.view.Gravity}. 2819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public int gravity; 28218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 2822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * Width as a 0-1 multiplier of the measured pager width 2824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28257e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell float widthFactor = 0.f; 2826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 2827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell /** 2828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * true if this view was added during layout and needs to be measured 2829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell * before being positioned. 2830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell */ 28317e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell boolean needsMeasure; 28327e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28337e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 28347e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Adapter position this view is for if !isDecor 28357e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 28367e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int position; 28377e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28387e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell /** 28397e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell * Current child index within the ViewPager that this view occupies 28407e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell */ 28417e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell int childIndex; 2842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell 28438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams() { 28448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(FILL_PARENT, FILL_PARENT); 28458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell public LayoutParams(Context context, AttributeSet attrs) { 28488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell super(context, attrs); 28498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell 28508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 2851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell gravity = a.getInteger(0, Gravity.TOP); 28528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell a.recycle(); 28538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell } 28557e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell 28567e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell static class ViewPositionComparator implements Comparator<View> { 28577e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell @Override 28587e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell public int compare(View lhs, View rhs) { 28597e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); 28607e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); 28617e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell if (llp.isDecor != rlp.isDecor) { 28627e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.isDecor ? 1 : -1; 28637e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 28647e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell return llp.position - rlp.position; 28657e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 28667e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell } 2867d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn} 2868