mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 16:26:47 +00:00
Merge "Revert "Updating the scroll calculation from recyclerView to avoid view inflation"" into tm-qpr-dev
This commit is contained in:
@@ -24,6 +24,7 @@ import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
@@ -91,7 +92,8 @@ public abstract class FastScrollRecyclerView extends RecyclerView {
|
||||
protected int getAvailableScrollHeight() {
|
||||
// AvailableScrollHeight = Total height of the all items - first page height
|
||||
int firstPageHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
|
||||
int availableScrollHeight = computeVerticalScrollRange() - firstPageHeight;
|
||||
int totalHeightOfAllItems = getItemsHeight(/* untilIndex= */ getAdapter().getItemCount());
|
||||
int availableScrollHeight = totalHeightOfAllItems - firstPageHeight;
|
||||
return Math.max(0, availableScrollHeight);
|
||||
}
|
||||
|
||||
@@ -144,7 +146,10 @@ public abstract class FastScrollRecyclerView extends RecyclerView {
|
||||
|
||||
// IF scroller is at the very top OR there is no scroll bar because there is probably not
|
||||
// enough items to scroll, THEN it's okay for the container to be pulled down.
|
||||
return computeVerticalScrollOffset() == 0;
|
||||
if (getCurrentScrollY() == 0) {
|
||||
return true;
|
||||
}
|
||||
return getAdapter() == null || getAdapter().getItemCount() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,6 +159,53 @@ public abstract class FastScrollRecyclerView extends RecyclerView {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scroll top of this recycler view.
|
||||
*/
|
||||
public int getCurrentScrollY() {
|
||||
Adapter adapter = getAdapter();
|
||||
if (adapter == null) {
|
||||
return -1;
|
||||
}
|
||||
if (adapter.getItemCount() == 0 || getChildCount() == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int itemPosition = NO_POSITION;
|
||||
View child = null;
|
||||
|
||||
LayoutManager layoutManager = getLayoutManager();
|
||||
if (layoutManager instanceof LinearLayoutManager) {
|
||||
// Use the LayoutManager as the source of truth for visible positions. During
|
||||
// animations, the view group child may not correspond to the visible views that appear
|
||||
// at the top.
|
||||
itemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
|
||||
child = layoutManager.findViewByPosition(itemPosition);
|
||||
}
|
||||
|
||||
if (child == null) {
|
||||
// If the layout manager returns null for any reason, which can happen before layout
|
||||
// has occurred for the position, then look at the child of this view as a ViewGroup.
|
||||
child = getChildAt(0);
|
||||
itemPosition = getChildAdapterPosition(child);
|
||||
}
|
||||
if (itemPosition == NO_POSITION) {
|
||||
return -1;
|
||||
}
|
||||
return getPaddingTop() + getItemsHeight(itemPosition)
|
||||
- layoutManager.getDecoratedTop(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of the height, in pixels, of this list adapter's items from index
|
||||
* 0 (inclusive) until {@code untilIndex} (exclusive). If untilIndex is same as the itemCount,
|
||||
* it returns the full height of all the items.
|
||||
*
|
||||
* <p>If the untilIndex is larger than the total number of items in this adapter, returns the
|
||||
* sum of all items' height.
|
||||
*/
|
||||
protected abstract int getItemsHeight(int untilIndex);
|
||||
|
||||
/**
|
||||
* Maps the touch (from 0..1) to the adapter position that should be visible.
|
||||
* <p>Override in each subclass of this base class.
|
||||
|
||||
@@ -2790,7 +2790,7 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
View v = getFirstMatch(Collections.singletonList(activeRecyclerView),
|
||||
preferredItem, packageAndUserAndApp);
|
||||
|
||||
if (v != null && activeRecyclerView.computeVerticalScrollOffset() > 0) {
|
||||
if (v != null && activeRecyclerView.getCurrentScrollY() > 0) {
|
||||
RectF locationBounds = new RectF();
|
||||
FloatingIconView.getLocationBoundsForView(this, v, false, locationBounds,
|
||||
new Rect());
|
||||
|
||||
@@ -26,9 +26,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityRecordCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
|
||||
import com.android.launcher3.util.ScrollableLayoutManager;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.List;
|
||||
@@ -68,10 +66,10 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
/**
|
||||
* A subclass of GridLayoutManager that overrides accessibility values during app search.
|
||||
*/
|
||||
public class AppsGridLayoutManager extends ScrollableLayoutManager {
|
||||
public class AppsGridLayoutManager extends GridLayoutManager {
|
||||
|
||||
public AppsGridLayoutManager(Context context) {
|
||||
super(context);
|
||||
super(context, 1, GridLayoutManager.VERTICAL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,15 +129,6 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
}
|
||||
return extraRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
|
||||
AllAppsGridAdapter.AdapterItem item = mApps.getAdapterItems().get(position);
|
||||
// only account for the first icon in the row since they are the same size within a row
|
||||
return (isIconViewType(item.viewType) && item.rowAppIndex != 0)
|
||||
? heightUntilLastPos
|
||||
: (heightUntilLastPos + mCachedSizes.get(item.viewType));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static android.view.View.MeasureSpec.UNSPECIFIED;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
|
||||
@@ -24,6 +26,7 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@@ -46,10 +49,40 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_LATENCY = Utilities.isPropertyEnabled(SEARCH_LOGGING);
|
||||
|
||||
protected AlphabeticalAppsList<?> mApps;
|
||||
protected final int mNumAppsPerRow;
|
||||
|
||||
// The specific view heights that we use to calculate scroll
|
||||
private final SparseIntArray mViewHeights = new SparseIntArray();
|
||||
private final SparseIntArray mCachedScrollPositions = new SparseIntArray();
|
||||
private final AllAppsFastScrollHelper mFastScrollHelper;
|
||||
|
||||
protected AlphabeticalAppsList<?> mApps;
|
||||
|
||||
private final AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
|
||||
public void onChanged() {
|
||||
mCachedScrollPositions.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeChanged(int positionStart, int itemCount) {
|
||||
onChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
onChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
onChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
|
||||
onChanged();
|
||||
}
|
||||
};
|
||||
|
||||
public AllAppsRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
@@ -89,8 +122,12 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows
|
||||
* (mNumAppsPerRow + 1));
|
||||
|
||||
mViewHeights.clear();
|
||||
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, grid.allAppsCellHeightPx);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas c) {
|
||||
if (DEBUG) {
|
||||
@@ -162,6 +199,17 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
mFastScrollHelper.onFastScrollCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(Adapter adapter) {
|
||||
if (getAdapter() != null) {
|
||||
getAdapter().unregisterAdapterDataObserver(mObserver);
|
||||
}
|
||||
super.setAdapter(adapter);
|
||||
if (adapter != null) {
|
||||
adapter.registerAdapterDataObserver(mObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPaddingOffsetRequired() {
|
||||
return true;
|
||||
@@ -183,13 +231,13 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
|
||||
|
||||
// Skip early if there are no items or we haven't been measured
|
||||
if (items.isEmpty() || mNumAppsPerRow == 0 || getChildCount() == 0) {
|
||||
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
||||
mScrollbar.setThumbOffsetY(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip early if, there no child laid out in the container.
|
||||
int scrollY = computeVerticalScrollOffset();
|
||||
int scrollY = getCurrentScrollY();
|
||||
if (scrollY < 0) {
|
||||
mScrollbar.setThumbOffsetY(-1);
|
||||
return;
|
||||
@@ -244,6 +292,51 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemsHeight(int position) {
|
||||
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
|
||||
AllAppsGridAdapter.AdapterItem posItem = position < items.size()
|
||||
? items.get(position) : null;
|
||||
int y = mCachedScrollPositions.get(position, -1);
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
for (int i = 0; i < position; i++) {
|
||||
AllAppsGridAdapter.AdapterItem item = items.get(i);
|
||||
if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
|
||||
// Break once we reach the desired row
|
||||
if (posItem != null && posItem.viewType == item.viewType &&
|
||||
posItem.rowIndex == item.rowIndex) {
|
||||
break;
|
||||
}
|
||||
// Otherwise, only account for the first icon in the row since they are the same
|
||||
// size within a row
|
||||
if (item.rowAppIndex == 0) {
|
||||
y += mViewHeights.get(item.viewType, 0);
|
||||
}
|
||||
} else {
|
||||
// Rest of the views span the full width
|
||||
int elHeight = mViewHeights.get(item.viewType);
|
||||
if (elHeight == 0) {
|
||||
ViewHolder holder = findViewHolderForAdapterPosition(i);
|
||||
if (holder == null) {
|
||||
holder = getAdapter().createViewHolder(this, item.viewType);
|
||||
getAdapter().onBindViewHolder(holder, i);
|
||||
holder.itemView.measure(UNSPECIFIED, UNSPECIFIED);
|
||||
elHeight = holder.itemView.getMeasuredHeight();
|
||||
|
||||
getRecycledViewPool().putRecycledView(holder);
|
||||
} else {
|
||||
elHeight = holder.itemView.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
y += elHeight;
|
||||
}
|
||||
}
|
||||
mCachedScrollPositions.put(position, y);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
public int getScrollBarTop() {
|
||||
return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding);
|
||||
}
|
||||
|
||||
@@ -106,8 +106,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
updateHeaderScroll(
|
||||
((AllAppsRecyclerView) recyclerView).computeVerticalScrollOffset());
|
||||
updateHeaderScroll(((AllAppsRecyclerView) recyclerView).getCurrentScrollY());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
mAnimator.cancel();
|
||||
}
|
||||
|
||||
int current = -mCurrentRV.computeVerticalScrollOffset();
|
||||
int current = -mCurrentRV.getCurrentScrollY();
|
||||
boolean headerCollapsed = mHeaderCollapsed;
|
||||
moved(current);
|
||||
applyVerticalMove();
|
||||
|
||||
@@ -112,12 +112,12 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||
|
||||
case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
|
||||
return getLauncherUIProperty(Bundle::putInt,
|
||||
l -> l.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset());
|
||||
l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
|
||||
return getLauncherUIProperty(Bundle::putInt,
|
||||
l -> WidgetsFullSheet.getWidgetsView(l).computeVerticalScrollOffset());
|
||||
l -> WidgetsFullSheet.getWidgetsView(l).getCurrentScrollY());
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_TARGET_INSETS: {
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
import androidx.recyclerview.widget.RecyclerView.State;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
/**
|
||||
* Extension of {@link GridLayoutManager} with support for smooth scrolling
|
||||
*/
|
||||
public class ScrollableLayoutManager extends GridLayoutManager {
|
||||
|
||||
// keyed on item type
|
||||
protected final SparseIntArray mCachedSizes = new SparseIntArray();
|
||||
|
||||
private RecyclerView mRv;
|
||||
|
||||
/**
|
||||
* Precalculated total height keyed on the item position. This is always incremental.
|
||||
* Subclass can override {@link #incrementTotalHeight} to incorporate the layout logic.
|
||||
* For example all-apps should have same values for items in same row,
|
||||
* sample values: 0, 10, 10, 10, 10, 20, 20, 20, 20
|
||||
* whereas widgets will have strictly increasing values
|
||||
* sample values: 0, 10, 50, 60, 110
|
||||
*/
|
||||
|
||||
//
|
||||
private int[] mTotalHeightCache = new int[1];
|
||||
private int mLastValidHeightIndex = 0;
|
||||
|
||||
public ScrollableLayoutManager(Context context) {
|
||||
super(context, 1, GridLayoutManager.VERTICAL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow(RecyclerView view) {
|
||||
super.onAttachedToWindow(view);
|
||||
mRv = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutDecorated(@NonNull View child, int left, int top, int right, int bottom) {
|
||||
super.layoutDecorated(child, left, top, right, bottom);
|
||||
mCachedSizes.put(
|
||||
mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutDecoratedWithMargins(@NonNull View child, int left, int top, int right,
|
||||
int bottom) {
|
||||
super.layoutDecoratedWithMargins(child, left, top, right, bottom);
|
||||
mCachedSizes.put(
|
||||
mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollExtent(State state) {
|
||||
return mRv == null ? 0 : mRv.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollOffset(State state) {
|
||||
Adapter adapter = mRv == null ? null : mRv.getAdapter();
|
||||
if (adapter == null) {
|
||||
return 0;
|
||||
}
|
||||
if (adapter.getItemCount() == 0 || getChildCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
View child = getChildAt(0);
|
||||
ViewHolder holder = mRv.findContainingViewHolder(child);
|
||||
if (holder == null) {
|
||||
return 0;
|
||||
}
|
||||
int itemPosition = holder.getLayoutPosition();
|
||||
if (itemPosition < 0) {
|
||||
return 0;
|
||||
}
|
||||
return getPaddingTop() + getItemsHeight(adapter, itemPosition) - getDecoratedTop(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeVerticalScrollRange(State state) {
|
||||
Adapter adapter = mRv == null ? null : mRv.getAdapter();
|
||||
return adapter == null ? 0 : getItemsHeight(adapter, adapter.getItemCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of the height, in pixels, of this list adapter's items from index
|
||||
* 0 (inclusive) until {@code untilIndex} (exclusive). If untilIndex is same as the itemCount,
|
||||
* it returns the full height of all the items.
|
||||
*
|
||||
* <p>If the untilIndex is larger than the total number of items in this adapter, returns the
|
||||
* sum of all items' height.
|
||||
*/
|
||||
private int getItemsHeight(Adapter adapter, int untilIndex) {
|
||||
final int totalItems = adapter.getItemCount();
|
||||
if (mTotalHeightCache.length < (totalItems + 1)) {
|
||||
mTotalHeightCache = new int[totalItems + 1];
|
||||
mLastValidHeightIndex = 0;
|
||||
}
|
||||
if (untilIndex > totalItems) {
|
||||
untilIndex = totalItems;
|
||||
} else if (untilIndex < 0) {
|
||||
untilIndex = 0;
|
||||
}
|
||||
if (untilIndex <= mLastValidHeightIndex) {
|
||||
return mTotalHeightCache[untilIndex];
|
||||
}
|
||||
|
||||
int totalItemsHeight = mTotalHeightCache[mLastValidHeightIndex];
|
||||
for (int i = mLastValidHeightIndex; i < untilIndex; i++) {
|
||||
totalItemsHeight = incrementTotalHeight(adapter, i, totalItemsHeight);
|
||||
mTotalHeightCache[i + 1] = totalItemsHeight;
|
||||
}
|
||||
mLastValidHeightIndex = untilIndex;
|
||||
return totalItemsHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current implementation assumes a linear list with every item taking up the whole row.
|
||||
* Subclasses should override this method to account for any spanning logic
|
||||
*/
|
||||
protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
|
||||
return heightUntilLastPos + mCachedSizes.get(adapter.getItemViewType(position));
|
||||
}
|
||||
|
||||
private void invalidateScrollCache() {
|
||||
mLastValidHeightIndex = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
|
||||
super.onItemsAdded(recyclerView, positionStart, itemCount);
|
||||
invalidateScrollCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemsChanged(RecyclerView recyclerView) {
|
||||
super.onItemsChanged(recyclerView);
|
||||
invalidateScrollCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
|
||||
super.onItemsRemoved(recyclerView, positionStart, itemCount);
|
||||
invalidateScrollCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
|
||||
super.onItemsMoved(recyclerView, from, to, itemCount);
|
||||
invalidateScrollCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount,
|
||||
Object payload) {
|
||||
super.onItemsUpdated(recyclerView, positionStart, itemCount, payload);
|
||||
invalidateScrollCache();
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,7 @@ public class RecyclerViewFastScroller extends View {
|
||||
// prevent jumping, this offset is applied as the user scrolls.
|
||||
protected int mTouchOffsetY;
|
||||
protected int mThumbOffsetY;
|
||||
protected int mRvOffsetY;
|
||||
|
||||
// Fast scroller popup
|
||||
private TextView mPopupView;
|
||||
@@ -206,11 +207,16 @@ public class RecyclerViewFastScroller extends View {
|
||||
|
||||
public void setThumbOffsetY(int y) {
|
||||
if (mThumbOffsetY == y) {
|
||||
int rvCurrentOffsetY = mRv.getCurrentScrollY();
|
||||
if (mRvOffsetY != rvCurrentOffsetY) {
|
||||
mRvOffsetY = mRv.getCurrentScrollY();
|
||||
}
|
||||
return;
|
||||
}
|
||||
updatePopupY(y);
|
||||
mThumbOffsetY = y;
|
||||
invalidate();
|
||||
mRvOffsetY = mRv.getCurrentScrollY();
|
||||
}
|
||||
|
||||
public int getThumbOffsetY() {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.launcher3.widget.picker;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
@@ -27,7 +28,6 @@ import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
|
||||
|
||||
import com.android.launcher3.FastScrollRecyclerView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.ScrollableLayoutManager;
|
||||
|
||||
/**
|
||||
* The widgets recycler view.
|
||||
@@ -42,6 +42,14 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte
|
||||
private boolean mTouchDownOnScroller;
|
||||
private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
|
||||
|
||||
/**
|
||||
* There is always 1 or 0 item of VIEW_TYPE_WIDGETS_LIST. Other types have fixes sizes, so the
|
||||
* the size can be used for all other items of same type. Caching the last know size for
|
||||
* VIEW_TYPE_WIDGETS_LIST allows us to use it to estimate full size even when
|
||||
* VIEW_TYPE_WIDGETS_LIST is not visible on the screen.
|
||||
*/
|
||||
private final SparseIntArray mCachedSizes = new SparseIntArray();
|
||||
|
||||
public WidgetsRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -60,7 +68,9 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setLayoutManager(new ScrollableLayoutManager(getContext()));
|
||||
// create a layout manager with Launcher's context so that scroll position
|
||||
// can be preserved during screen rotation.
|
||||
setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +114,7 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte
|
||||
}
|
||||
|
||||
// Skip early if, there no child laid out in the container.
|
||||
int scrollY = computeVerticalScrollOffset();
|
||||
int scrollY = getCurrentScrollY();
|
||||
if (scrollY < 0) {
|
||||
mScrollbar.setThumbOffsetY(-1);
|
||||
return;
|
||||
@@ -153,6 +163,39 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte
|
||||
mHeaderViewDimensionsProvider = headerViewDimensionsProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of the height, in pixels, of this list adapter's items from index 0 until
|
||||
* {@code untilIndex}.
|
||||
*
|
||||
* <p>If the untilIndex is larger than the total number of items in this adapter, returns the
|
||||
* sum of all items' height.
|
||||
*/
|
||||
@Override
|
||||
protected int getItemsHeight(int untilIndex) {
|
||||
// Initialize cache
|
||||
int childCount = getChildCount();
|
||||
int startPosition;
|
||||
if (childCount > 0
|
||||
&& ((startPosition = getChildAdapterPosition(getChildAt(0))) != NO_POSITION)) {
|
||||
int loopCount = Math.min(getChildCount(), getAdapter().getItemCount() - startPosition);
|
||||
for (int i = 0; i < loopCount; i++) {
|
||||
mCachedSizes.put(
|
||||
mAdapter.getItemViewType(startPosition + i),
|
||||
getChildAt(i).getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
if (untilIndex > mAdapter.getItems().size()) {
|
||||
untilIndex = mAdapter.getItems().size();
|
||||
}
|
||||
int totalItemsHeight = 0;
|
||||
for (int i = 0; i < untilIndex; i++) {
|
||||
int type = mAdapter.getItemViewType(i);
|
||||
totalItemsHeight += mCachedSizes.get(type);
|
||||
}
|
||||
return totalItemsHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides dimensions of the header view that is shown at the top of a
|
||||
* {@link WidgetsRecyclerView}.
|
||||
|
||||
@@ -537,7 +537,7 @@ public abstract class AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
protected int getAllAppsScroll(Launcher launcher) {
|
||||
return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset();
|
||||
return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
|
||||
}
|
||||
|
||||
private void checkLauncherIntegrity(
|
||||
|
||||
@@ -302,7 +302,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
private int getWidgetsScroll(Launcher launcher) {
|
||||
return getWidgetsView(launcher).computeVerticalScrollOffset();
|
||||
return getWidgetsView(launcher).getCurrentScrollY();
|
||||
}
|
||||
|
||||
private boolean isOptionsPopupVisible(Launcher launcher) {
|
||||
|
||||
Reference in New Issue
Block a user