From ded80076dbff226a3890d367ddbcb14417bcad9a Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Mon, 21 Jun 2021 14:47:04 +0000 Subject: [PATCH] Add spacing between items as decorations instead of margins There are bugs in the accounting for the margins if we manipulate the view directly, causing the wrong top to be reported and the view to be shifted when we call scrollToPosition. Item decorations ensure that the layout system for the recycler view always has the right details about the spacing. Fix: 191642682 Test: verified locally Change-Id: Ie80563757079e885c8178883ab16e314d01c5b32 --- res/layout/widgets_list_row_header.xml | 1 - res/layout/widgets_table_container.xml | 3 +-- res/values/dimens.xml | 2 +- res/values/id.xml | 1 + .../widget/picker/WidgetsListAdapter.java | 24 ++++++++++++++++++- .../widget/picker/WidgetsListHeader.java | 11 --------- .../widget/picker/WidgetsRecyclerView.java | 16 ++++++------- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml index 0bfa2b2a5e..3eaa7ea627 100644 --- a/res/layout/widgets_list_row_header.xml +++ b/res/layout/widgets_list_row_header.xml @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" - android:layout_marginBottom="@dimen/widget_list_entry_bottom_margin" android:paddingVertical="@dimen/widget_list_header_view_vertical_padding" android:orientation="horizontal" launcher:appIconSize="48dp"> diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml index 4f70a05374..fac21fdcf0 100644 --- a/res/layout/widgets_table_container.xml +++ b/res/layout/widgets_table_container.xml @@ -18,5 +18,4 @@ android:id="@+id/widgets_table" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="16dp" - android:layout_marginBottom="@dimen/widget_list_entry_bottom_margin"/> + android:layout_marginHorizontal="16dp"/> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 251f04a66e..416179e402 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -147,7 +147,7 @@ 4dp 20dp - 2dp + 2dp 0.5dp 1dp diff --git a/res/values/id.xml b/res/values/id.xml index 1bd40cec4a..1709c5961e 100644 --- a/res/values/id.xml +++ b/res/values/id.xml @@ -16,6 +16,7 @@ --> + diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index 5d9adf0e71..b668c90031 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -18,6 +18,7 @@ package com.android.launcher3.widget.picker; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_APP_EXPANDED; import android.content.Context; +import android.graphics.Rect; import android.os.Process; import android.util.Log; import android.util.Size; @@ -34,6 +35,7 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.Adapter; +import androidx.recyclerview.widget.RecyclerView.LayoutParams; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.android.launcher3.BaseActivity; @@ -107,7 +109,8 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Nullable private Predicate mFilter = null; @Nullable private RecyclerView mRecyclerView; @Nullable private PackageUserKey mPendingClickHeader; - private int mShortcutPreviewPadding; + private final int mShortcutPreviewPadding; + private final int mSpacingBetweenEntries; private final WidgetPreviewLoadedCallback mPreviewLoadedCallback = ignored -> updateVisibleEntries(); @@ -141,11 +144,28 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mShortcutPreviewPadding = 2 * context.getResources() .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); + mSpacingBetweenEntries = + context.getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing); } @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { mRecyclerView = recyclerView; + + mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets( + @NonNull Rect outRect, + @NonNull View view, + @NonNull RecyclerView parent, + @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); + boolean isHeader = + view.getTag(R.id.tag_widget_entry) instanceof WidgetsListBaseEntry.Header; + outRect.top += position > 0 && isHeader ? mSpacingBetweenEntries : 0; + } + }); } @Override @@ -329,7 +349,9 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Override public void onBindViewHolder(ViewHolder holder, int pos) { ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos)); + WidgetsListBaseEntry entry = mVisibleEntries.get(pos); viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), pos); + holder.itemView.setTag(R.id.tag_widget_entry, entry); } @Override diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java index cdab964279..ef2adbb809 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java @@ -30,7 +30,6 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; @@ -59,7 +58,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd @Nullable private HandlerRunnable mIconLoadRequest; @Nullable private Drawable mIconDrawable; private final int mIconSize; - private final int mBottomMarginSize; private ImageView mAppIcon; private TextView mTitle; @@ -86,8 +84,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0); mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize, grid.iconSizePx); - mBottomMarginSize = - getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin); } @Override @@ -146,13 +142,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd public void setExpanded(boolean isExpanded) { this.mIsExpanded = isExpanded; mExpandToggle.setChecked(isExpanded); - if (getLayoutParams() instanceof RecyclerView.LayoutParams) { - int bottomMargin = isExpanded ? 0 : mBottomMarginSize; - RecyclerView.LayoutParams layoutParams = - ((RecyclerView.LayoutParams) getLayoutParams()); - layoutParams.bottomMargin = bottomMargin; - setLayoutParams(layoutParams); - } } /** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */ diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index 3ee8b33b53..7671841878 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -52,7 +52,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider; private int mLastVisibleWidgetContentTableHeight = 0; private int mWidgetHeaderHeight = 0; - private final int mCollapsedHeaderBottomMarginSize; + private final int mSpacingBetweenEntries; @Nullable private OnContentChangeListener mOnContentChangeListener; public WidgetsRecyclerView(Context context) { @@ -72,9 +72,9 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch ActivityContext activity = ActivityContext.lookupContext(getContext()); DeviceProfile grid = activity.getDeviceProfile(); - // The bottom margin used when the header is not expanded. - mCollapsedHeaderBottomMarginSize = - getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin); + // The spacing used between entries. + mSpacingBetweenEntries = + getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing); } @Override @@ -270,16 +270,16 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch if (untilIndex > mAdapter.getItems().size()) { untilIndex = mAdapter.getItems().size(); } - int expandedHeaderPosition = mAdapter.getSelectedHeaderPosition().orElse(-1); int totalItemsHeight = 0; for (int i = 0; i < untilIndex; i++) { WidgetsListBaseEntry entry = mAdapter.getItems().get(i); if (entry instanceof WidgetsListHeaderEntry || entry instanceof WidgetsListSearchHeaderEntry) { totalItemsHeight += mWidgetHeaderHeight; - if (expandedHeaderPosition != i) { - // If the header is collapsed, include the bottom margin it will use. - totalItemsHeight += mCollapsedHeaderBottomMarginSize; + if (i > 0) { + // Each header contains the spacing between entries as top decoration, except + // the first one. + totalItemsHeight += mSpacingBetweenEntries; } } else if (entry instanceof WidgetsListContentEntry) { totalItemsHeight += mLastVisibleWidgetContentTableHeight;