AdapterViewAnimator.java revision 9b3a2cf2a0a482ce8212eb2775176dd4c23e8e9a
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 21a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haaseimport android.animation.ObjectAnimator; 223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Context; 233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.Intent; 243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.content.res.TypedArray; 253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Handler; 263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.os.Looper; 27b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcel; 28b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohenimport android.os.Parcelable; 293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.util.AttributeSet; 303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.View; 3144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenimport android.view.ViewGroup; 32839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohenimport android.view.ViewGroup.LayoutParams; 333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.Animation; 343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohenimport android.view.animation.AnimationUtils; 353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen/** 373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Base class for a {@link AdapterView} that will perform animations 383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * when switching between its views. 393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation 413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation 423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView 433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 4444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohenpublic abstract class AdapterViewAnimator extends AdapterView<Adapter> 45dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen implements RemoteViewsAdapter.RemoteAdapterConnectionCallback { 463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen private static final String TAG = "RemoteViewAnimator"; 473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 4844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 4944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index of the current child, which appears anywhere from the beginning 5044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * to the end of the current set of children, as specified by {@link #mActiveOffset} 5144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int mWhichChild = 0; 5344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 5444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 5544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Whether or not the first view(s) should be animated in 5644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean mAnimateFirstTime = true; 583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 6044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Represents where the in the current window of 6144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * views the current <code>mDisplayedChild</code> sits 6244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 6344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mActiveOffset = 0; 6444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 6544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 6644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The number of views that the {@link AdapterViewAnimator} keeps as children at any 6744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * given time (not counting views that are pending removal, see {@link #mPreviousViews}). 6844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 6944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mNumActiveViews = 1; 7044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Array of the children of the {@link AdapterViewAnimator}. This array 7344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * is accessed in a circular fashion 7444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 7544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View[] mActiveViews; 7644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 7744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 7844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * List of views pending removal from the {@link AdapterViewAnimator} 7944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 8044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen ArrayList<View> mPreviousViews; 8144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the beginning of the window of views 8444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 8544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStart = 0; 8644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 8744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 8844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The index, relative to the adapter, of the end of the window of views 8944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowEnd = -1; 9144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The same as {@link #mCurrentWindowStart}, except when the we have bounded 9444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * {@link #mCurrentWindowStart} to be non-negative 9544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 9644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int mCurrentWindowStartUnbounded = 0; 9744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 9844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 9944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Handler to post events to the main thread 10044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 10144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Handler mMainQueue; 10244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 10344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Listens for data changes from the adapter 10544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen AdapterDataSetObserver mDataSetObserver; 1073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 10844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 10944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link Adapter} for this {@link AdapterViewAnimator} 11044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Adapter mAdapter; 11244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * The {@link RemoteViewsAdapter} for this {@link AdapterViewAnimator} 11544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 11644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen RemoteViewsAdapter mRemoteViewsAdapter; 11744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 11844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 11944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Specifies whether this is the first time the animator is showing views 12044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 12144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean mFirstTime = true; 1223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 12344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 124b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Specifies if the animator should wrap from 0 to the end and vice versa 125b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * or have hard boundaries at the beginning and end 126b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 127b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen boolean mShouldLoop = true; 128b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 129b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 130839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * The width and height of some child, used as a size reference in-case our 131839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen * dimensions are unspecified by the parent. 132839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen */ 133839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildWidth = -1; 134839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int mReferenceChildHeight = -1; 135839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 136839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen /** 13744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit. 13844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 1393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mInAnimation; 1403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen Animation mOutAnimation; 14144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private ArrayList<View> mViewsToBringToFront; 1423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context) { 1443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context); 1455b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public AdapterViewAnimator(Context context, AttributeSet attrs) { 1493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen super(context, attrs); 1503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 15144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen TypedArray a = context.obtainStyledAttributes(attrs, 15244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator); 15344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int resource = a.getResourceId( 15444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator_inAnimation, 0); 1553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(context, resource); 1573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1593db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0); 1603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (resource > 0) { 1613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(context, resource); 1623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 16444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen boolean flag = a.getBoolean( 16544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen com.android.internal.R.styleable.ViewAnimator_animateFirstView, true); 1663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAnimateFirstView(flag); 1673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen a.recycle(); 1693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1705b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy initViewAnimator(); 1713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 1723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 1733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 1743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Initialize this {@link AdapterViewAnimator} 1753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 1765b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy private void initViewAnimator() { 1773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mMainQueue = new Handler(Looper.myLooper()); 17844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews = new View[mNumActiveViews]; 17944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews = new ArrayList<View>(); 18044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront = new ArrayList<View>(); 18144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 18244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 18344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 18444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This method is used by subclasses to configure the animator to display the 18544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * desired number of views, and specify the offset 18644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 18744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param numVisibleViews The number of views the animator keeps in the {@link ViewGroup} 1885b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * @param activeOffset This parameter specifies where the current index ({@link #mWhichChild}) 18944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * sits within the window. For example if activeOffset is 1, and numVisibleViews is 3, 1905b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * and {@link #setDisplayedChild(int)} is called with 10, then the effective window will 1915b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy * be the indexes 9, 10, and 11. In the same example, if activeOffset were 0, then the 19244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * window would instead contain indexes 10, 11 and 12. 193b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * @param shouldLoop If the animator is show view 0, and setPrevious() is called, do we 194b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * we loop back to the end, or do we do nothing 19544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 196b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen void configureViewAnimator(int numVisibleViews, int activeOffset, boolean shouldLoop) { 19744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (activeOffset > numVisibleViews - 1) { 19844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Throw an exception here. 19944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 20044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews = numVisibleViews; 20144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveOffset = activeOffset; 20244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews = new View[mNumActiveViews]; 20344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 20444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeAllViewsInLayout(); 20544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = 0; 20644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = -1; 207b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mShouldLoop = shouldLoop; 20844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 20944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 21044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 21144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * This class should be overridden by subclasses to customize view transitions within 21244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * the set of visible views 21344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 21444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param fromIndex The relative index within the window that the view was in, -1 if it wasn't 21544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * in the window 21644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param toIndex The relative index within the window that the view is going to, -1 if it is 21744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * being removed 21844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param view The view that is being animated 21944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 22044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void animateViewForTransition(int fromIndex, int toIndex, View view) { 221a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ObjectAnimator pa; 22244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (fromIndex == -1) { 223b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen view.setAlpha(0.0f); 224a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase pa = new ObjectAnimator(400, view, "alpha", 0.0f, 1.0f); 22544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa.start(); 22644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else if (toIndex == -1) { 227a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase pa = new ObjectAnimator(400, view, "alpha", 1.0f, 0.0f); 22844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen pa.start(); 22944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 2303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Sets which child view will be displayed. 2343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 2353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param whichChild the index of the child view to display 2363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setDisplayedChild(int whichChild) { 2383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 2393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = whichChild; 2403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (whichChild >= mAdapter.getCount()) { 241b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mWhichChild = mShouldLoop ? 0 : mAdapter.getCount() - 1; 2423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } else if (whichChild < 0) { 243b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mWhichChild = mShouldLoop ? mAdapter.getCount() - 1 : 0; 2443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean hasFocus = getFocusedChild() != null; 2473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // This will clear old focus if we had it 2483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(mWhichChild); 2493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (hasFocus) { 2503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // Try to retake focus if we had it 2513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen requestFocus(FOCUS_FORWARD); 2523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Return default inAnimation. To be overriden by subclasses. 2583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 25944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Animation getDefaultInAnimation() { 2603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 2613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 26444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Return default outAnimation. To be overridden by subclasses. 2653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 26644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen Animation getDefaultOutAnimation() { 2673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return null; 2683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 27144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * To be overridden by subclasses. This method applies a view / index specific 27244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * transform to the child view. 27344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 27444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param child 27544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex 27644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 27744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void applyTransformForChildAtIndex(View child, int relativeIndex) { 27844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 27944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 28044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 2813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the index of the currently displayed child view. 2823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getDisplayedChild() { 2843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mWhichChild; 2853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the next child. 2893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showNext() { 2913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild + 1); 2923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 2933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 2943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 2953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Manually shows the previous child. 2963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 2973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void showPrevious() { 2983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(mWhichChild - 1); 2993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 3023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen, 3033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * optionally with the with the {@link #getOutAnimation() out animation} and 3043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the specified child enters the screen, optionally with the 3053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * {@link #getInAnimation() in animation}. 3063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 3073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 3083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate Whether or not to use the in and out animations, defaults 3093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * to true. 3103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 3113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex, boolean animate) { 3123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate, false); 3133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 31544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen private int modulo(int pos, int size) { 31644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return (size + (pos % size)) % size; 3173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 3183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 31944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen /** 32044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Get the view at this index relative to the current window's start 32144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 32244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param relativeIndex Position relative to the current window's start 32344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @return View at this index, null if the index is outside the bounds 32444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen */ 32544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View getViewAtRelativeIndex(int relativeIndex) { 32644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1) { 32744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = mCurrentWindowStartUnbounded + relativeIndex; 32844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return mActiveViews[modulo(index, mNumActiveViews)]; 32944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 33044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return null; 33144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 3339b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen LayoutParams createOrReuseLayoutParams(View v) { 3345b53f9186e7812c93bc578d18e92cb123481fcbcRomain Guy final ViewGroup.LayoutParams currentLp = v.getLayoutParams(); 3359b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen if (currentLp instanceof ViewGroup.LayoutParams) { 336b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen LayoutParams lp = (LayoutParams) currentLp; 337b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return lp; 33844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3399b073948cfb84c0dd04f8a94ee1f7f263f027c83Adam Cohen return new ViewGroup.LayoutParams(0, 0); 34044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 3413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 342bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen private void refreshChildren() { 343bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) { 344bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen int index = modulo(i, mNumActiveViews); 345bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 346bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // get the fresh child from the adapter 347bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen View updatedChild = mAdapter.getView(i, null, this); 348bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 349bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen if (mActiveViews[index] != null) { 350bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen FrameLayout fl = (FrameLayout) mActiveViews[index]; 351bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // flush out the old child 352bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.removeAllViewsInLayout(); 353bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // add the new child to the frame, if it exists 354bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen if (updatedChild != null) { 355bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(updatedChild); 356bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 357bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 358bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 359bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 360bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 361dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen /** 362dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * This method can be overridden so that subclasses can provide a custom frame in which their 363dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * children can live. For example, StackView adds padding to its childrens' frames so as to 364dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * accomodate for the highlight effect. 365dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * 366dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen * @return The FrameLayout into which children can be placed. 367dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen */ 368dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout getFrameForChild() { 369dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen return new FrameLayout(mContext); 370dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen } 371dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen 37244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen void showOnly(int childIndex, boolean animate, boolean onLayout) { 37344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mAdapter == null) return; 3743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 37544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mPreviousViews.size(); i++) { 37644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View viewToRemove = mPreviousViews.get(i); 37744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen viewToRemove.clearAnimation(); 3783d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen if (viewToRemove instanceof ViewGroup) { 3793d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen ViewGroup vg = (ViewGroup) viewToRemove; 3803d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen vg.removeAllViewsInLayout(); 3813d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen } 38244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // applyTransformForChildAtIndex here just allows for any cleanup 38344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // associated with this view that may need to be done by a subclass 38444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(viewToRemove, -1); 3853d07af03421f4727ef7e97c5c19e6ade50b19060Adam Cohen 38644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen removeViewInLayout(viewToRemove); 38744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 38844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.clear(); 38944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStartUnbounded = childIndex - mActiveOffset; 39044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1; 39144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowStart = Math.max(0, newWindowStartUnbounded); 39244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newWindowEnd = Math.min(mAdapter.getCount(), newWindowEndUnbounded); 39344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 39444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // This section clears out any items that are in our mActiveViews list 39544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // but are outside the effective bounds of our window (this is becomes an issue 39644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // at the extremities of the list, eg. where newWindowStartUnbounded < 0 or 39744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // newWindowEndUnbounded > mAdapter.getCount() - 1 39844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStartUnbounded; i < newWindowEndUnbounded; i++) { 39944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (i < newWindowStart || i > newWindowEnd) { 40044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = modulo(i, mNumActiveViews); 40144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mActiveViews[index] != null) { 40244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View previousView = mActiveViews[index]; 40344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.add(previousView); 40444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int previousViewRelativeIndex = modulo(index - mCurrentWindowStart, 40544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews); 40644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(previousViewRelativeIndex, -1, previousView); 407b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mActiveViews[index] = null; 40844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 41044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 41244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the window has changed 41344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (! (newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd)) { 41444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Run through the indices in the new range 41544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = newWindowStart; i <= newWindowEnd; i++) { 41644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 41744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int oldRelativeIndex = i - mCurrentWindowStartUnbounded; 41844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int newRelativeIndex = i - newWindowStartUnbounded; 41944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int index = modulo(i, mNumActiveViews); 42044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 42144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If this item is in the current window, great, we just need to apply 42244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // the transform for it's new relative position in the window, and animate 42344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // between it's current and new relative positions 42444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (i >= mCurrentWindowStart && i <= mCurrentWindowEnd) { 42544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View view = mActiveViews[index]; 42644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen applyTransformForChildAtIndex(view, newRelativeIndex); 42744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(oldRelativeIndex, newRelativeIndex, view); 42844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 42944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // Otherwise this view is new, so first we have to displace the view that's 43044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // taking the new view's place within our cache (a circular array) 43144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 43244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mActiveViews[index] != null) { 43344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View previousView = mActiveViews[index]; 43444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mPreviousViews.add(previousView); 43544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen int previousViewRelativeIndex = modulo(index - mCurrentWindowStart, 43644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mNumActiveViews); 43744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen animateViewForTransition(previousViewRelativeIndex, -1, previousView); 43844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 43944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (mCurrentWindowStart > newWindowStart) { 44044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront.add(previousView); 44144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 44244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 4433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 44444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // We've cleared a spot for the new view. Get it from the adapter, add it 44544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // and apply any transform / animation 44644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View newView = mAdapter.getView(i, null, this); 447bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 448bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // We wrap the new view in a FrameLayout so as to respect the contract 449bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // with the adapter, that is, that we don't modify this view directly 450dfcdddd7c408dddb22fb0867e4799d4c29d2f55fAdam Cohen FrameLayout fl = getFrameForChild(); 451bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen 452bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen // If the view from the adapter is null, we still keep an empty frame in place 45344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (newView != null) { 454bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen fl.addView(newView); 45544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 456bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen mActiveViews[index] = fl; 457bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen addChild(fl); 458bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen applyTransformForChildAtIndex(fl, newRelativeIndex); 459bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen animateViewForTransition(-1, newRelativeIndex, fl); 4603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 46144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mActiveViews[index].bringToFront(); 4623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 46444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen for (int i = 0; i < mViewsToBringToFront.size(); i++) { 46544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen View v = mViewsToBringToFront.get(i); 46644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen v.bringToFront(); 4673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 46844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mViewsToBringToFront.clear(); 4693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 47044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStart = newWindowStart; 47144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowEnd = newWindowEnd; 47244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mCurrentWindowStartUnbounded = newWindowStartUnbounded; 47344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 47444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen 47544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mFirstTime = false; 47644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen if (!onLayout) { 47744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen requestLayout(); 47844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidate(); 47944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } else { 48044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // If the Adapter tries to layout the current view when we get it using getView 48144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // above the layout will end up being ignored since we are currently laying out, so 48244729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen // we post a delayed requestLayout and invalidate 48344729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen mMainQueue.post(new Runnable() { 48444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen @Override 48544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen public void run() { 48644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen requestLayout(); 48744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen invalidate(); 48844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen } 48944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen }); 4903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 4923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 493839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void addChild(View child) { 494839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen addViewInLayout(child, -1, createOrReuseLayoutParams(child)); 495839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 496839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // This code is used to obtain a reference width and height of a child in case we need 497839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // to decide our own size. TODO: Do we want to update the size of the child that we're 498839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // using for reference size? If so, when? 499839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) { 500839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 501839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(measureSpec, measureSpec); 502839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildWidth = child.getMeasuredWidth(); 503839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mReferenceChildHeight = child.getMeasuredHeight(); 504839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 505839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 506839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 507839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen private void measureChildren() { 508839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int count = getChildCount(); 509839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight; 510839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int childHeight = mMeasuredHeight - mPaddingTop - mPaddingBottom; 511839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 512839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen for (int i = 0; i < count; i++) { 513839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final View child = getChildAt(i); 514839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 515839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); 516839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 517839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 518839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 519839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen @Override 520839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 521839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 522839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 523839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 524839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 525839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 526839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1); 527839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 528839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // We need to deal with the case where our parent hasn't told us how 529839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // big we should be. In this case we try to use the desired size of the first 530839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen // child added. 531839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (heightSpecMode == MeasureSpec.UNSPECIFIED) { 532839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop + 533839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingBottom : 0; 534839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 535839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen heightSpecSize = haveChildRefSize ? Math.min(mReferenceChildHeight + mPaddingTop + 536839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingBottom, heightSpecSize) : 0; 537839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 538839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 539839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen if (widthSpecMode == MeasureSpec.UNSPECIFIED) { 540839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft + 541839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingRight : 0; 542839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } else if (heightSpecMode == MeasureSpec.AT_MOST) { 543839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft + 544839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen mPaddingRight, widthSpecSize) : 0; 545839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 546839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 547839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 548839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen measureChildren(); 549839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen } 550839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen 5513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 5523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 5533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen boolean dataChanged = mDataChanged; 5543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (dataChanged) { 5553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen handleDataChanged(); 5563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // if the data changes, mWhichChild might be out of the bounds of the adapter 5583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen // in this case, we reset mWhichChild to the beginning 559bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen if (mWhichChild >= mAdapter.getCount()) { 5603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mWhichChild = 0; 5613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 562bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen showOnly(mWhichChild, true, true); 563bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen } 564bd0136a2fde1d81a835f94efe3193569b10d99ffAdam Cohen refreshChildren(); 5653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final int childCount = getChildCount(); 5683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen for (int i = 0; i < childCount; i++) { 5693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final View child = getChildAt(i); 5703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 5713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childRight = mPaddingLeft + child.getMeasuredWidth(); 5723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen int childBottom = mPaddingTop + child.getMeasuredHeight(); 5733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 574839f4a54e5a6fe602dbc5998b01412d809eba722Adam Cohen child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom); 5753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataChanged = false; 5773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 5783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 579b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen static class SavedState extends BaseSavedState { 580b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen int whichChild; 581b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 582b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 583b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link AdapterViewAnimator#onSaveInstanceState()} 584b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 585b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState(Parcelable superState, int whichChild) { 586b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(superState); 587b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen this.whichChild = whichChild; 588b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 589b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 590b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen /** 591b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen * Constructor called from {@link #CREATOR} 592b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen */ 593b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen private SavedState(Parcel in) { 594b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super(in); 595b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen whichChild = in.readInt(); 596b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 597b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 598b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 599b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void writeToParcel(Parcel out, int flags) { 600b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.writeToParcel(out, flags); 601b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen out.writeInt(whichChild); 602b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 603b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 604b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 605b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public String toString() { 606b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return "AdapterViewAnimator.SavedState{ whichChild = " + whichChild + " }"; 607b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 608b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 609b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public static final Parcelable.Creator<SavedState> CREATOR 610b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen = new Parcelable.Creator<SavedState>() { 611b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState createFromParcel(Parcel in) { 612b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(in); 613b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 614b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 615b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public SavedState[] newArray(int size) { 616b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState[size]; 617b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 618b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen }; 619b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 620b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 621b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 622b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public Parcelable onSaveInstanceState() { 623b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen Parcelable superState = super.onSaveInstanceState(); 624b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen return new SavedState(superState, mWhichChild); 625b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 626b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 627b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen @Override 628b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen public void onRestoreInstanceState(Parcelable state) { 629b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen SavedState ss = (SavedState) state; 630b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen super.onRestoreInstanceState(ss.getSuperState()); 631b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 632b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // Here we set mWhichChild in addition to setDisplayedChild 633b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // We do the former in case mAdapter is null, and hence setDisplayedChild won't 634b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen // set mWhichChild 635b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen mWhichChild = ss.whichChild; 636b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen setDisplayedChild(mWhichChild); 637b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen } 638b04f7ad90b7d5d5e0998e3b56960004cf56e6e8fAdam Cohen 6393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Shows only the specified child. The other displays Views exit the screen 6413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * with the {@link #getOutAnimation() out animation} and the specified child 6423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * enters the screen with the {@link #getInAnimation() in animation}. 6433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param childIndex The index of the child to be shown. 6453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen void showOnly(int childIndex) { 6473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen final boolean animate = (!mFirstTime || mAnimateFirstTime); 6483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen showOnly(childIndex, animate); 6493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the View corresponding to the currently displayed child. 6533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return The View currently displayed. 6553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getDisplayedChild() 6573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getCurrentView() { 65944729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 6603db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6613db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6623db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that enters the screen. 6643db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 6663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 6683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 6693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6703db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getInAnimation() { 6713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mInAnimation; 6723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6743db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6753db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 6763db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6773db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param inAnimation The animation started when a View enters the screen. 6783db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 6803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.content.Context, int) 6813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6823db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Animation inAnimation) { 6833db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mInAnimation = inAnimation; 6843db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6853db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6863db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6873db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Returns the current animation used to animate a View that exits the screen. 6883db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6893db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @return An Animation or null if none is set. 6903db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 6913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 6923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 6933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 6943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Animation getOutAnimation() { 6953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mOutAnimation; 6963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 6973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 6983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 6993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 7003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7013db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param outAnimation The animation started when a View exit the screen. 7023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 7043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.content.Context, int) 7053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Animation outAnimation) { 7073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mOutAnimation = outAnimation; 7083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 7113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that enters the screen. 7123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 7143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 7153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getInAnimation() 7173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setInAnimation(android.view.animation.Animation) 7183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setInAnimation(Context context, int resourceID) { 7203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); 7213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7233db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 7243db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Specifies the animation used to animate a View that exit the screen. 7253db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7263db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param context The application's environment. 7273db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param resourceID The resource id of the animation. 7283db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7293db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #getOutAnimation() 7303db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @see #setOutAnimation(android.view.animation.Animation) 7313db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7323db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setOutAnimation(Context context, int resourceID) { 7333db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); 7343db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7353db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7363db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 7373db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Indicates whether the current View should be animated the first time 7383db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * the ViewAnimation is displayed. 7393db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * 7403db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * @param animate True to animate the current View the first time it is displayed, 7413db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * false otherwise. 7423db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7433db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAnimateFirstView(boolean animate) { 7443db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAnimateFirstTime = animate; 7453db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7463db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7473db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 7483db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public int getBaseline() { 7493db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline(); 7503db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7513db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7523db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 7533db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public Adapter getAdapter() { 7543db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen return mAdapter; 7553db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7563db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7573db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 7583db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setAdapter(Adapter adapter) { 7598322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen if (mAdapter != null && mDataSetObserver != null) { 7608322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen mAdapter.unregisterDataSetObserver(mDataSetObserver); 7618322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen } 7628322834a2544a673a35c5d4ad0d5909b3ca37600Adam Cohen 7633db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter = adapter; 7641480fddea874a42adb43b4bcdac6704e4c3e110bAdam Cohen checkFocus(); 7653db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7663db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mAdapter != null) { 7673db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mDataSetObserver = new AdapterDataSetObserver(); 7683db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mAdapter.registerDataSetObserver(mDataSetObserver); 7693db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 77044729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen setFocusable(true); 7713db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7723db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7733db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 77444729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a 77544729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * RemoteViewsService through the specified intent. 77644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * 77744729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * @param intent the intent used to identify the RemoteViewsService for the adapter to 77844729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen * connect to. 7793db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 7803db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @android.view.RemotableViewMethod 7813db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setRemoteViewsAdapter(Intent intent) { 7829b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Ensure that we don't already have a RemoteViewsAdapter that is bound to an existing 7839b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // service handling the specified intent. 7849b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung Intent.FilterComparison fc = new Intent.FilterComparison(intent); 7859b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung if (mRemoteViewsAdapter != null && 7869b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung fc.equals(mRemoteViewsAdapter.getRemoteViewsServiceIntent())) { 7879b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung return; 7889b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung } 7899b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung 7909b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung // Otherwise, create a new RemoteViewsAdapter for binding 7913db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); 7923db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7933db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7943db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 7953db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void setSelection(int position) { 7963db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setDisplayedChild(position); 7973db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 7983db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 7993db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen @Override 8003db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public View getSelectedView() { 80144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen return getViewAtRelativeIndex(mActiveOffset); 8023db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8033db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8043db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8053db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter connects to the RemoteViewsService. 8063db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8073db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterConnected() { 8083db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 8093db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 8103db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8113db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8123db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen 8133db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen /** 8143db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen * Called back when the adapter disconnects from the RemoteViewsService. 8153db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen */ 8163db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen public void onRemoteAdapterDisconnected() { 8173db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen if (mRemoteViewsAdapter != mAdapter) { 8183db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen mRemoteViewsAdapter = null; 8193db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen setAdapter(mRemoteViewsAdapter); 8203db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8213db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen } 8223db40678d33c2b5f90c380966d36b3e10ed11f05Adam Cohen} 823