LinearLayoutManagerTest.java revision d7848507d6c561ca8e17d1954653f4fd26b58f84
1d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar/* 2d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 4d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * you may not use this file except in compliance with the License. 6d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * You may obtain a copy of the License at 7d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 8d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 10d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * See the License for the specific language governing permissions and 14d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * limitations under the License. 15d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar */ 16d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 17d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarpackage android.support.v7.widget; 18d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 19d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.content.Context; 20d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.view.View; 21d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 22d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.ArrayList; 23d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.List; 24d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.CountDownLatch; 25d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.TimeUnit; 26d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 27d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarpublic class LinearLayoutManagerTest extends BaseRecyclerViewInstrumentationTest { 28d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 29d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar WrappedLinearLayoutManager mLayoutManager; 30d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 31d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar TestAdapter mTestAdapter; 32d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 33d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final List<Config> mBaseVariations = new ArrayList<Config>(); 34d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 35d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 36d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar protected void setUp() throws Exception { 37d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar super.setUp(); 38d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (int orientation : new int[]{LinearLayoutManager.VERTICAL, 39d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar LinearLayoutManager.HORIZONTAL}) { 40d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (boolean reverseLayout : new boolean[]{false, true}) { 41d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (boolean stackFromBottom : new boolean[]{false, true}) { 42d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mBaseVariations.add(new Config(orientation, reverseLayout, stackFromBottom)); 43d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 44d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 45d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 46d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 47d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 48d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar RecyclerView setupByConfig(Config config) throws Throwable { 49d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 50d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar recyclerView.setHasFixedSize(true); 51d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mTestAdapter = new TestAdapter(config.mItemCount); 52d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar recyclerView.setAdapter(mTestAdapter); 53d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager = new WrappedLinearLayoutManager(getActivity(), config.mOrientation, 54d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar config.mReverseLayout); 55d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.setStackFromEnd(config.mStackFromEnd); 56d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar recyclerView.setLayoutManager(mLayoutManager); 57d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.expectLayouts(1); 58d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar setRecyclerView(recyclerView); 59d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.waitForLayout(2); 60d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return recyclerView; 61d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 62d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 63d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 64d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void testGetFirstLastChildrenTest() throws Throwable { 65d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (Config config : mBaseVariations) { 66d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar getFirstLastChildrenTest(config); 67d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 68d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 69d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 70d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void getFirstLastChildrenTest(final Config config) throws Throwable { 71d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar setupByConfig(config); 72d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Runnable viewInBoundsTest = new Runnable() { 73d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 74d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void run() { 75d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren(); 76d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final String boundsLog = mLayoutManager.getBoundsLog(); 77d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar assertEquals(config + ":\nfirst visible child should match traversal result\n" 78d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar + boundsLog, visibleChildren.firstVisiblePosition, 79d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.findFirstVisibleItemPosition() 80d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ); 81d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar assertEquals( 82d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar config + ":\nfirst fully visible child should match traversal result\n" 83d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar + boundsLog, visibleChildren.firstFullyVisiblePosition, 84d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.findFirstCompletelyVisibleItemPosition() 85d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ); 86d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 87d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar assertEquals(config + ":\nlast visible child should match traversal result\n" 88d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar + boundsLog, visibleChildren.lastVisiblePosition, 89d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.findLastVisibleItemPosition() 90d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ); 91d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar assertEquals( 92d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar config + ":\nlast fully visible child should match traversal result\n" 93d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar + boundsLog, visibleChildren.lastFullyVisiblePosition, 94d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.findLastCompletelyVisibleItemPosition() 95d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ); 96d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 97d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar }; 98d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(viewInBoundsTest); 99d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching 100d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar // case 101d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int scrollPosition = config.mStackFromEnd ? 0 : mTestAdapter.getItemCount(); 102d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(new Runnable() { 103d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 104d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void run() { 105d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mRecyclerView.smoothScrollToPosition(scrollPosition); 106d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 107d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar }); 108d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar while (mLayoutManager.isSmoothScrolling() || 109d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) { 110d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(viewInBoundsTest); 111d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Thread.sleep(200); 112d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 113d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar // delete all items 114d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.expectLayouts(2); 115d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mTestAdapter.deleteAndNotify(0, mTestAdapter.getItemCount()); 116d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.waitForLayout(2); 117d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar // test empty case 118d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(viewInBoundsTest); 119d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar // set a new adapter with huge items to test full bounds check 120d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.expectLayouts(1); 121d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int totalSpace = mLayoutManager.mOrientationHelper.getTotalSpace(); 122d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final TestAdapter newAdapter = new TestAdapter(100) { 123d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 124d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 125d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int position) { 126d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar super.onBindViewHolder(holder, position); 127d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (config.mOrientation == LinearLayoutManager.HORIZONTAL) { 128d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar holder.itemView.setMinimumWidth(totalSpace + 5); 129d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } else { 130d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar holder.itemView.setMinimumHeight(totalSpace + 5); 131d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 132d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 133d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar }; 134d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(new Runnable() { 135d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 136d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void run() { 137d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mRecyclerView.setAdapter(newAdapter); 138d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 139d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar }); 140d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mLayoutManager.waitForLayout(2); 141d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar runTestOnUiThread(viewInBoundsTest); 142d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 143d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 144d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar static class VisibleChildren { 145d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 146d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int firstVisiblePosition = RecyclerView.NO_POSITION; 147d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 148d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int firstFullyVisiblePosition = RecyclerView.NO_POSITION; 149d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 150d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int lastVisiblePosition = RecyclerView.NO_POSITION; 151d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 152d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int lastFullyVisiblePosition = RecyclerView.NO_POSITION; 153d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 154d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 155d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public String toString() { 156d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return "VisibleChildren{" + 157d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar "firstVisiblePosition=" + firstVisiblePosition + 158d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", firstFullyVisiblePosition=" + firstFullyVisiblePosition + 159d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", lastVisiblePosition=" + lastVisiblePosition + 160d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", lastFullyVisiblePosition=" + lastFullyVisiblePosition + 161d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar '}'; 162d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 163d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 164d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 165d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar static class WrappedLinearLayoutManager extends LinearLayoutManager { 166d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 167d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar CountDownLatch layoutLatch; 168d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 169d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public WrappedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 170d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar super(context, orientation, reverseLayout); 171d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 172d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 173d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void expectLayouts(int count) { 174d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar layoutLatch = new CountDownLatch(count); 175d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 176d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 177d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void waitForLayout(long timeout) throws InterruptedException { 178d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar waitForLayout(timeout, TimeUnit.SECONDS); 179d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 180d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 181d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar private void waitForLayout(long timeout, TimeUnit timeUnit) throws InterruptedException { 182d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar layoutLatch.await(timeout, timeUnit); 183d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar assertEquals("all expected layouts should be executed at the expected time", 184d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 0, layoutLatch.getCount()); 185d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 186d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 187d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public String getBoundsLog() { 188d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar StringBuilder sb = new StringBuilder(); 189d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar sb.append("view bounds:[start:").append(mOrientationHelper.getStartAfterPadding()) 190d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar .append(",").append(" end").append(mOrientationHelper.getEndAfterPadding()); 191d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar sb.append("\nchildren bounds\n"); 192d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int childCount = getChildCount(); 193d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (int i = 0; i < childCount; i++) { 194d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar View child = getChildAt(i); 195d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar sb.append("child (ind:").append(i).append(", pos:").append(getPosition(child)) 196d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar .append("[").append("start:").append( 197d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mOrientationHelper.getDecoratedStart(child)).append(", end:") 198d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar .append(mOrientationHelper.getDecoratedEnd(child)).append("]\n"); 199d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 200d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return sb.toString(); 201d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 202d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 203d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public VisibleChildren traverseAndFindVisibleChildren() { 204d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int childCount = getChildCount(); 205d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final VisibleChildren visibleChildren = new VisibleChildren(); 206d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int start = mOrientationHelper.getStartAfterPadding(); 207d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int end = mOrientationHelper.getEndAfterPadding(); 208d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar for (int i = 0; i < childCount; i++) { 209d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar View child = getChildAt(i); 210d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int childStart = mOrientationHelper.getDecoratedStart(child); 211d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int childEnd = mOrientationHelper.getDecoratedEnd(child); 212d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final boolean fullyVisible = childStart >= start && childEnd <= end; 213d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final boolean hidden = childEnd <= start || childStart >= end; 214d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (hidden) { 215d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar continue; 216d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 217d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar final int position = getPosition(child); 218d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (fullyVisible) { 219d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (position < visibleChildren.firstFullyVisiblePosition || 220d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.firstFullyVisiblePosition == RecyclerView.NO_POSITION) { 221d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.firstFullyVisiblePosition = position; 222d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 223d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 224d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (position > visibleChildren.lastFullyVisiblePosition) { 225d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.lastFullyVisiblePosition = position; 226d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 227d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 228d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 229d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (position < visibleChildren.firstVisiblePosition || 230d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.firstVisiblePosition == RecyclerView.NO_POSITION) { 231d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.firstVisiblePosition = position; 232d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 233d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 234d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar if (position > visibleChildren.lastVisiblePosition) { 235d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar visibleChildren.lastVisiblePosition = position; 236d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 237d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 238d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 239d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return visibleChildren; 240d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 241d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 242d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 243d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 244d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar super.onLayoutChildren(recycler, state); 245d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar layoutLatch.countDown(); 246d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 247d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 248d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 249d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar static class Config { 250d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 251d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar private static final int DEFAULT_ITEM_COUNT = 300; 252d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 253d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar private boolean mStackFromEnd; 254d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 255d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int mOrientation = LinearLayoutManager.VERTICAL; 256d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 257d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar boolean mReverseLayout = false; 258d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 259d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar int mItemCount = DEFAULT_ITEM_COUNT; 260d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 261d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Config(int orientation, boolean reverseLayout, boolean stackFromEnd) { 262d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mOrientation = orientation; 263d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mReverseLayout = reverseLayout; 264d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mStackFromEnd = stackFromEnd; 265d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 266d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 267d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public Config() { 268d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 269d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 270d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 271d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Config orientation(int orientation) { 272d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mOrientation = orientation; 273d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return this; 274d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 275d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 276d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Config stackFromBottom(boolean stackFromBottom) { 277d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mStackFromEnd = stackFromBottom; 278d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return this; 279d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 280d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 281d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar Config reverseLayout(boolean reverseLayout) { 282d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mReverseLayout = reverseLayout; 283d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return this; 284d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 285d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 286d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public Config itemCount(int itemCount) { 287d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar mItemCount = itemCount; 288d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return this; 289d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 290d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 291d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar @Override 292d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar public String toString() { 293d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar return "Config{" + 294d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar "mStackFromEnd=" + mStackFromEnd + 295d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", mOrientation=" + mOrientation + 296d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", mReverseLayout=" + mReverseLayout + 297d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar ", mItemCount=" + mItemCount + 298d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar '}'; 299d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 300d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar } 301d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar} 302