AdapterViewAnimator.java revision 5b53f9186e7812c93bc578d18e92cb123481fcbc
13db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/* 23db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Copyright (C) 2010 The Android Open Source Project 33db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 43db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Licensed under the Apache License, Version 2.0 (the "License"); 53db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * you may not use this file except in compliance with the License. 63db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * You may obtain a copy of the License at 73db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 83db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * http://www.apache.org/licenses/LICENSE-2.0 93db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Unless required by applicable law or agreed to in writing, software 113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * distributed under the License is distributed on an "AS IS" BASIS, 123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * See the License for the specific language governing permissions and 143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * limitations under the License. 153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenpackage android.widget; 183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport java.util.ArrayList; 2044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 2144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.animation.PropertyAnimator; 223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Context; 233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Intent; 243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.res.TypedArray; 2544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.graphics.Rect; 263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Handler; 273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Looper; 283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.AttributeSet; 293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.View; 3044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.view.ViewGroup; 313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.Animation; 323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.AnimationUtils; 333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/** 353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Base class for a {@link AdapterView} that will perform animations 363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * when switching between its views. 373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation 393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation 403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView 413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenpublic abstract class AdapterViewAnimator extends AdapterView<Adapter> 4344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen implements RemoteViewsAdapter.RemoteAdapterConnectionCallback{ 443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private static final String TAG = "RemoteViewAnimator"; 453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 4744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index of the current child, which appears anywhere from the beginning 4844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * to the end of the current set of children, as specified by {@link #mActiveOffset} 4944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int mWhichChild = 0; 5144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Whether or not the first view(s) should be animated in 5444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mAnimateFirstTime = true; 563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Represents where the in the current window of 5944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * views the current <code>mDisplayedChild</code> sits 6044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 6144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mActiveOffset = 0; 6244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 6344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 6444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The number of views that the {@link AdapterViewAnimator} keeps as children at any 6544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * given time (not counting views that are pending removal, see {@link #mPreviousViews}). 6644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 6744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mNumActiveViews = 1; 6844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 6944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Array of the children of the {@link AdapterViewAnimator}. This array 7144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * is accessed in a circular fashion 7244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View[] mActiveViews; 7444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * List of views pending removal from the {@link AdapterViewAnimator} 7744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen ArrayList<View> mPreviousViews; 7944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the beginning of the window of views 8244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 8344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStart = 0; 8444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the end of the window of views 8744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 8844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowEnd = -1; 8944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The same as {@link #mCurrentWindowStart}, except when the we have bounded 9244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * {@link #mCurrentWindowStart} to be non-negative 9344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStartUnbounded = 0; 9544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Indicates whether to treat the adapter to be a circular structure, ie. 9844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * the view before 0 is considered to be <code>mAdapter.getCount() - 1</code> 9944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 10044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * TODO: this doesn't do anything yet 10144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 10244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 10344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean mCycleViews = false; 10444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 10544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Handler to post events to the main thread 10744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 10844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Handler mMainQueue; 10944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Listens for data changes from the adapter 11244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen AdapterDataSetObserver mDataSetObserver; 1143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 11544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link Adapter} for this {@link AdapterViewAnimator} 11744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Adapter mAdapter; 11944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 12044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 12144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link RemoteViewsAdapter} for this {@link AdapterViewAnimator} 12244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 12344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen RemoteViewsAdapter mRemoteViewsAdapter; 12444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 12544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 12644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Specifies whether this is the first time the animator is showing views 12744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 12844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean mFirstTime = true; 1293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 13044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 13144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit. 13244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mInAnimation; 1343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mOutAnimation; 13544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private ArrayList<View> mViewsToBringToFront; 1363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context) { 1383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context); 1395b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs) { 1433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context, attrs); 1443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 14544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen TypedArray a = context.obtainStyledAttributes(attrs, 14644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator); 14744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int resource = a.getResourceId( 14844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator_inAnimation, 0); 1493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(context, resource); 1513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0); 1543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(context, resource); 1563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 15844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean flag = a.getBoolean( 15944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator_animateFirstView, true); 1603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAnimateFirstView(flag); 1613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen a.recycle(); 1633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1645b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Initialize this {@link AdapterViewAnimator} 1693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1705b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy private void initViewAnimator() { 1713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mMainQueue = new Handler(Looper.myLooper()); 17244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews = new View[mNumActiveViews]; 17344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews = new ArrayList<View>(); 17444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront = new ArrayList<View>(); 17544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 17644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 17744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 17844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This method is used by subclasses to configure the animator to display the 17944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * desired number of views, and specify the offset 18044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 18144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param numVisibleViews The number of views the animator keeps in the {@link ViewGroup} 1825b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * @param activeOffset This parameter specifies where the current index ({@link #mWhichChild}) 18344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * sits within the window. For example if activeOffset is 1, and numVisibleViews is 3, 1845b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * and {@link #setDisplayedChild(int)} is called with 10, then the effective window will 1855b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * be the indexes 9, 10, and 11. In the same example, if activeOffset were 0, then the 18644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * window would instead contain indexes 10, 11 and 12. 18744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 18844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void configureViewAnimator(int numVisibleViews, int activeOffset) { 18944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (activeOffset > numVisibleViews - 1) { 19044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Throw an exception here. 19144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 19244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews = numVisibleViews; 19344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveOffset = activeOffset; 19444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews = new View[mNumActiveViews]; 19544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 19644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeAllViewsInLayout(); 19744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = 0; 19844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = -1; 19944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 20044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 20144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 20244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This class should be overridden by subclasses to customize view transitions within 20344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * the set of visible views 20444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 20544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param fromIndex The relative index within the window that the view was in, -1 if it wasn't 20644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * in the window 20744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param toIndex The relative index within the window that the view is going to, -1 if it is 20844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * being removed 20944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param view The view that is being animated 21044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 21144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void animateViewForTransition(int fromIndex, int toIndex, View view) { 21244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen PropertyAnimator pa; 21344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (fromIndex == -1) { 21444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa = new PropertyAnimator(400, view, "alpha", 0.0f, 1.0f); 21544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa.start(); 21644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else if (toIndex == -1) { 21744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa = new PropertyAnimator(400, view, "alpha", 1.0f, 0.0f); 21844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa.start(); 21944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 2203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets which child view will be displayed. 2243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param whichChild the index of the child view to display 2263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setDisplayedChild(int whichChild) { 2283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 2293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = whichChild; 2303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (whichChild >= mAdapter.getCount()) { 2313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = 0; 2323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else if (whichChild < 0) { 2333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = mAdapter.getCount() - 1; 2343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean hasFocus = getFocusedChild() != null; 2373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This will clear old focus if we had it 2383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild); 2393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (hasFocus) { 2403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Try to retake focus if we had it 2413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestFocus(FOCUS_FORWARD); 2423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Return default inAnimation. To be overriden by subclasses. 2483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 24944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Animation getDefaultInAnimation() { 2503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 2513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 25444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Return default outAnimation. To be overridden by subclasses. 2553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 25644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Animation getDefaultOutAnimation() { 2573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 2583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 26144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * To be overridden by subclasses. This method applies a view / index specific 26244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * transform to the child view. 26344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 26444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param child 26544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex 26644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 26744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void applyTransformForChildAtIndex(View child, int relativeIndex) { 26844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 26944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 27044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 2713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the index of the currently displayed child view. 2723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getDisplayedChild() { 2743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mWhichChild; 2753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the next child. 2793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showNext() { 2813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild + 1); 2823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the previous child. 2863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showPrevious() { 2883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild - 1); 2893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen, 2933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * optionally with the with the {@link #getOutAnimation() out animation} and 2943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the specified child enters the screen, optionally with the 2953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * {@link #getInAnimation() in animation}. 2963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 2983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate Whether or not to use the in and out animations, defaults 2993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * to true. 3003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex, boolean animate) { 3023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate, false); 3033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 30544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private int modulo(int pos, int size) { 30644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return (size + (pos % size)) % size; 3073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 30944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 31044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Get the view at this index relative to the current window's start 31144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 31244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex Position relative to the current window's start 31344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @return View at this index, null if the index is outside the bounds 31444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 31544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View getViewAtRelativeIndex(int relativeIndex) { 31644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1) { 31744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = mCurrentWindowStartUnbounded + relativeIndex; 31844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return mActiveViews[modulo(index, mNumActiveViews)]; 31944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 32044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return null; 32144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 32344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private LayoutParams createOrReuseLayoutParams(View v) { 3245b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy final ViewGroup.LayoutParams currentLp = v.getLayoutParams(); 32544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (currentLp instanceof LayoutParams) { 3265b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy return (LayoutParams) currentLp; 32744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 32844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return new LayoutParams(v); 32944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 33144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void showOnly(int childIndex, boolean animate, boolean onLayout) { 33244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mAdapter == null) return; 3333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 33444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mPreviousViews.size(); i++) { 33544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View viewToRemove = mPreviousViews.get(i); 33644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen viewToRemove.clearAnimation(); 33744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // applyTransformForChildAtIndex here just allows for any cleanup 33844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // associated with this view that may need to be done by a subclass 33944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(viewToRemove, -1); 34044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeViewInLayout(viewToRemove); 34144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 34244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 34344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStartUnbounded = childIndex - mActiveOffset; 34444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1; 34544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStart = Math.max(0, newWindowStartUnbounded); 34644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowEnd = Math.min(mAdapter.getCount(), newWindowEndUnbounded); 34744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 34844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // This section clears out any items that are in our mActiveViews list 34944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // but are outside the effective bounds of our window (this is becomes an issue 35044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // at the extremities of the list, eg. where newWindowStartUnbounded < 0 or 35144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // newWindowEndUnbounded > mAdapter.getCount() - 1 35244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStartUnbounded; i < newWindowEndUnbounded; i++) { 35344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (i < newWindowStart || i > newWindowEnd) { 35444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = modulo(i, mNumActiveViews); 35544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mActiveViews[index] != null) { 35644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View previousView = mActiveViews[index]; 35744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.add(previousView); 35844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int previousViewRelativeIndex = modulo(index - mCurrentWindowStart, 35944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews); 36044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(previousViewRelativeIndex, -1, previousView); 36144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 36344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 36544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the window has changed 36644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (! (newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd)) { 36744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Run through the indices in the new range 36844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStart; i <= newWindowEnd; i++) { 36944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 37044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int oldRelativeIndex = i - mCurrentWindowStartUnbounded; 37144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newRelativeIndex = i - newWindowStartUnbounded; 37244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = modulo(i, mNumActiveViews); 37344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 37444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If this item is in the current window, great, we just need to apply 37544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // the transform for it's new relative position in the window, and animate 37644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // between it's current and new relative positions 37744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (i >= mCurrentWindowStart && i <= mCurrentWindowEnd) { 37844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View view = mActiveViews[index]; 37944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(view, newRelativeIndex); 38044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(oldRelativeIndex, newRelativeIndex, view); 38144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 38244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Otherwise this view is new, so first we have to displace the view that's 38344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // taking the new view's place within our cache (a circular array) 38444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 38544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mActiveViews[index] != null) { 38644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View previousView = mActiveViews[index]; 38744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.add(previousView); 38844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int previousViewRelativeIndex = modulo(index - mCurrentWindowStart, 38944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews); 39044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(previousViewRelativeIndex, -1, previousView); 39144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 39244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mCurrentWindowStart > newWindowStart) { 39344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront.add(previousView); 39444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 39544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 39744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // We've cleared a spot for the new view. Get it from the adapter, add it 39844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // and apply any transform / animation 39944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View newView = mAdapter.getView(i, null, this); 40044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (newView != null) { 40144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews[index] = newView; 40244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen addViewInLayout(newView, -1, createOrReuseLayoutParams(newView)); 40344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(newView, newRelativeIndex); 40444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(-1, newRelativeIndex, newView); 40544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 40744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews[index].bringToFront(); 4083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 41044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mViewsToBringToFront.size(); i++) { 41144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View v = mViewsToBringToFront.get(i); 41244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen v.bringToFront(); 4133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 41444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront.clear(); 4153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 41644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = newWindowStart; 41744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = newWindowEnd; 41844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStartUnbounded = newWindowStartUnbounded; 41944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 42044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 42144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mFirstTime = false; 42244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (!onLayout) { 42344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen requestLayout(); 42444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidate(); 42544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 42644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the Adapter tries to layout the current view when we get it using getView 42744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // above the layout will end up being ignored since we are currently laying out, so 42844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // we post a delayed requestLayout and invalidate 42944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mMainQueue.post(new Runnable() { 43044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen @Override 43144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen public void run() { 43244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen requestLayout(); 43344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidate(); 43444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 43544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen }); 4363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 4403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 4413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean dataChanged = mDataChanged; 4423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (dataChanged) { 4433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen handleDataChanged(); 4443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // if the data changes, mWhichChild might be out of the bounds of the adapter 4463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // in this case, we reset mWhichChild to the beginning 4473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mWhichChild >= mAdapter.getCount()) 4483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = 0; 4493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild, true, true); 4513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int childCount = getChildCount(); 4543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < childCount; i++) { 4553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 4563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childRight = mPaddingLeft + child.getMeasuredWidth(); 4583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childBottom = mPaddingTop + child.getMeasuredHeight(); 45944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 4603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 46144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset, 46244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen childRight + lp.horizontalOffset, childBottom + lp.verticalOffset); 4633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataChanged = false; 4653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 4683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 4693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int count = getChildCount(); 4703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 4723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 4733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < count; i++) { 4753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 4763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 4783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen lp.width = widthSpecSize - mPaddingLeft - mPaddingRight; 4803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen lp.height = heightSpecSize - mPaddingTop - mPaddingBottom; 4813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, 4833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen MeasureSpec.EXACTLY); 4843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, 4853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen MeasureSpec.EXACTLY); 4863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen child.measure(childWidthMeasureSpec, childheightMeasureSpec); 4883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 4903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 4933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen 4943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * with the {@link #getOutAnimation() out animation} and the specified child 4953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * enters the screen with the {@link #getInAnimation() in animation}. 4963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 4973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 4983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex) { 5003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final boolean animate = (!mFirstTime || mAnimateFirstTime); 5013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate); 5023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the View corresponding to the currently displayed child. 5063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return The View currently displayed. 5083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getDisplayedChild() 5103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getCurrentView() { 51244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 5133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that enters the screen. 5173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 5193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 5213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 5223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getInAnimation() { 5243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mInAnimation; 5253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 5293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param inAnimation The animation started when a View enters the screen. 5313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 5333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 5343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Animation inAnimation) { 5363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mInAnimation = inAnimation; 5373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that exits the screen. 5413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 5433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 5453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 5463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getOutAnimation() { 5483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mOutAnimation; 5493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 5533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param outAnimation The animation started when a View exit the screen. 5553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 5573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 5583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Animation outAnimation) { 5603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mOutAnimation = outAnimation; 5613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 5653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 5673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 5683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 5703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 5713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Context context, int resourceID) { 5733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); 5743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 5783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 5803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 5813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 5833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 5843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Context context, int resourceID) { 5863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); 5873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 5903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Indicates whether the current View should be animated the first time 5913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the ViewAnimation is displayed. 5923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 5933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate True to animate the current View the first time it is displayed, 5943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * false otherwise. 5953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 5963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAnimateFirstView(boolean animate) { 5973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAnimateFirstTime = animate; 5983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 6013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getBaseline() { 6023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 6033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 6063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Adapter getAdapter() { 6073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mAdapter; 6083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 6113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAdapter(Adapter adapter) { 6128322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen if (mAdapter != null && mDataSetObserver != null) { 6138322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen mAdapter.unregisterDataSetObserver(mDataSetObserver); 6148322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen } 6158322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen 6163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter = adapter; 6173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 6193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataSetObserver = new AdapterDataSetObserver(); 6203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.registerDataSetObserver(mDataSetObserver); 6213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 62244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen setFocusable(true); 6233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 62644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a 62744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * RemoteViewsService through the specified intent. 62844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 62944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param intent the intent used to identify the RemoteViewsService for the adapter to 63044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * connect to. 6313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @android.view.RemotableViewMethod 6333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setRemoteViewsAdapter(Intent intent) { 6343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); 6353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 6383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setSelection(int position) { 6393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(position); 6403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 6433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getSelectedView() { 64444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 6453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter connects to the RemoteViewsService. 6493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterConnected() { 6513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 6523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 6533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter disconnects from the RemoteViewsService. 6583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterDisconnected() { 6603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 6613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = null; 6623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 6633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 66544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 66644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen static class LayoutParams extends ViewGroup.LayoutParams { 66744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int horizontalOffset; 66844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int verticalOffset; 66944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View mView; 67044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 67144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen LayoutParams(View view) { 67244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen super(0, 0); 67344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen horizontalOffset = 0; 67444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen verticalOffset = 0; 67544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mView = view; 67644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 67744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 67844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen LayoutParams(Context c, AttributeSet attrs) { 67944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen super(c, attrs); 68044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen horizontalOffset = 0; 68144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen verticalOffset = 0; 68244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 68344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 68444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private Rect parentRect = new Rect(); 68544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void invalidateGlobalRegion(View v, Rect r) { 68644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View p = v; 68744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean firstPass = true; 68844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen parentRect.set(0, 0, 0, 0); 68944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen while (p.getParent() != null && p.getParent() instanceof View 69044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen && !parentRect.contains(r)) { 69144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (!firstPass) r.offset(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY()); 69244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen firstPass = false; 69344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen p = (View) p.getParent(); 69444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen parentRect.set(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY(), 69544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen p.getRight() - p.getScrollX(), p.getBottom() - p.getScrollY()); 69644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 69744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen p.invalidate(r.left, r.top, r.right, r.bottom); 69844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 69944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 70044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private Rect invalidateRect = new Rect(); 70144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // This is public so that PropertyAnimator can access it 70244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen public void setVerticalOffset(int newVerticalOffset) { 70344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int offsetDelta = newVerticalOffset - verticalOffset; 70444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen verticalOffset = newVerticalOffset; 70544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mView != null) { 70644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mView.requestLayout(); 70744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int top = Math.min(mView.getTop() + offsetDelta, mView.getTop()); 70844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int bottom = Math.max(mView.getBottom() + offsetDelta, mView.getBottom()); 70944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidateRect.set(mView.getLeft(), top, mView.getRight(), bottom); 71044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidateGlobalRegion(mView, invalidateRect); 71144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 71244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 71332a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen 71432a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen public void setHorizontalOffset(int newHorizontalOffset) { 71532a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen int offsetDelta = newHorizontalOffset - horizontalOffset; 71632a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen horizontalOffset = newHorizontalOffset; 71732a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen if (mView != null) { 71832a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen mView.requestLayout(); 71932a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen int left = Math.min(mView.getLeft() + offsetDelta, mView.getLeft()); 72032a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen int right = Math.max(mView.getRight() + offsetDelta, mView.getRight()); 72132a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen invalidateRect.set(left, mView.getTop(), right, mView.getBottom()); 72232a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen invalidateGlobalRegion(mView, invalidateRect); 72332a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen } 72432a42f1587db77b958d62c3de4f2734eb0a3b965Adam Cohen } 72544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 7263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen} 727