From 095e7562a4e342c0f11d43520cfc1c059b09c489 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Thu, 6 May 2021 13:55:27 +0100 Subject: [PATCH] Fix UI overlapping and void space in the full widgets picker The issue is caused by not updating the header container after widgets recycler view items changed due to item click. Test: Expand / collapse items in the full widgets picker. No UI overlapping or void space is observed. Bug: 186121915 Change-Id: I6a12bbdcca921d66c6d62601bb59cea66a33640b --- ...rchAndRecommendationsScrollController.java | 31 ++++++++--- .../widget/picker/WidgetsRecyclerView.java | 54 +++++++++++++------ 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java index 2ca0d96eec..317fd03afe 100644 --- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java +++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java @@ -48,6 +48,8 @@ final class SearchAndRecommendationsScrollController implements private WidgetsRecyclerView mCurrentRecyclerView; + private OnContentChangeListener mOnContentChangeListener = () -> applyVerticalTransition(); + /** * The vertical distance, in pixels, until the search is pinned at the top of the screen when * the user scrolls down the recycler view. @@ -82,19 +84,21 @@ final class SearchAndRecommendationsScrollController implements mViewHolder.mContainer.setSearchAndRecommendationScrollController(this); mSearchAndRecommendationViewParent = (View) mViewHolder.mContainer.getParent(); mPrimaryRecyclerView = primaryRecyclerView; - mCurrentRecyclerView = mPrimaryRecyclerView; mWorkRecyclerView = workRecyclerView; mSearchRecyclerView = searchRecyclerView; mPrimaryWorkTabsView = personalWorkTabsView; mPrimaryWorkViewPager = primaryWorkViewPager; - mCurrentRecyclerView = mPrimaryRecyclerView; mTabsHeight = tabsHeight; + setCurrentRecyclerView(mPrimaryRecyclerView); } /** Sets the current active {@link WidgetsRecyclerView}. */ public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) { + if (mCurrentRecyclerView != null) { + mCurrentRecyclerView.setOnContentChangeListener(null); + } mCurrentRecyclerView = currentRecyclerView; - mCurrentRecyclerView = currentRecyclerView; + mCurrentRecyclerView.setOnContentChangeListener(mOnContentChangeListener); mViewHolder.mHeaderTitle.setTranslationY(0); mViewHolder.mRecommendedWidgetsTable.setTranslationY(0); mViewHolder.mSearchBar.setTranslationY(0); @@ -216,12 +220,16 @@ final class SearchAndRecommendationsScrollController implements return hasMarginOrPaddingUpdated; } - /** - * Changes the displacement of collapsible views (e.g. title & widget recommendations) and fixed - * views (e.g. recycler views, tabs) upon scrolling. - */ @Override public void onScrollChanged() { + applyVerticalTransition(); + } + + /** + * Changes the displacement of collapsible views (e.g. title & widget recommendations) and fixed + * views (e.g. recycler views, tabs) upon scrolling / content changes in the recycler view. + */ + private void applyVerticalTransition() { // Always use the recycler view offset because fast scroller offset has a different scale. int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY(); if (recyclerViewYOffset < 0) return; @@ -299,4 +307,13 @@ final class SearchAndRecommendationsScrollController implements return view.getMeasuredHeight() + marginLayoutParams.bottomMargin + marginLayoutParams.topMargin; } + + /** + * A listener to be notified when there is a content change in the recycler view that may affect + * the relative position of the search and recommendation container. + */ + public interface OnContentChangeListener { + /** Notifies a content change in the recycler view. */ + void onContentChanged(); + } } diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index eb821d4eab..e981906774 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -23,6 +23,8 @@ import android.view.MotionEvent; import android.view.View; import android.widget.TableLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener; @@ -35,6 +37,7 @@ import com.android.launcher3.widget.model.WidgetsListBaseEntry; import com.android.launcher3.widget.model.WidgetsListContentEntry; import com.android.launcher3.widget.model.WidgetsListHeaderEntry; import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry; +import com.android.launcher3.widget.picker.SearchAndRecommendationsScrollController.OnContentChangeListener; /** * The widgets recycler view. @@ -50,6 +53,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch private boolean mTouchDownOnScroller; private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider; private int mLastVisibleWidgetContentTableHeight = 0; + @Nullable private OnContentChangeListener mOnContentChangeListener; public WidgetsRecyclerView(Context context) { this(context, null); @@ -86,6 +90,22 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch mAdapter = (WidgetsListAdapter) adapter; } + @Override + public void onChildAttachedToWindow(@NonNull View child) { + super.onChildAttachedToWindow(child); + if (mOnContentChangeListener != null) { + mOnContentChangeListener.onContentChanged(); + } + } + + @Override + public void onChildDetachedFromWindow(@NonNull View child) { + super.onChildDetachedFromWindow(child); + if (mOnContentChangeListener != null) { + mOnContentChangeListener.onContentChanged(); + } + } + /** * Maps the touch (from 0..1) to the adapter position that should be visible. */ @@ -207,6 +227,25 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch mHeaderViewDimensionsProvider = headerViewDimensionsProvider; } + @Override + public void scrollToTop() { + if (mScrollbar != null) { + mScrollbar.reattachThumbToScroll(); + } + + if (getLayoutManager() instanceof LinearLayoutManager) { + if (getCurrentScrollY() == 0) { + // We are at the top, so don't scrollToPosition (would cause unnecessary relayout). + return; + } + } + scrollToPosition(0); + } + + public void setOnContentChangeListener(@Nullable OnContentChangeListener listener) { + mOnContentChangeListener = listener; + } + /** * Returns the sum of the height, in pixels, of this list adapter's items from index 0 until * {@code untilIndex}. @@ -244,19 +283,4 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch */ int getHeaderViewHeight(); } - - @Override - public void scrollToTop() { - if (mScrollbar != null) { - mScrollbar.reattachThumbToScroll(); - } - - if (getLayoutManager() instanceof LinearLayoutManager) { - if (getCurrentScrollY() == 0) { - // We are at the top, so don't scrollToPosition (would cause unnecessary relayout). - return; - } - } - scrollToPosition(0); - } }