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
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 0bfa2b2..3eaa7ea 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 4f70a05..fac21fd 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 251f04a..416179e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -147,7 +147,7 @@
<dimen name="widget_list_content_corner_radius">4dp</dimen>
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
- <dimen name="widget_list_entry_bottom_margin">2dp</dimen>
+ <dimen name="widget_list_entry_spacing">2dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index 1bd40ce..1709c59 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -16,6 +16,7 @@
-->
<resources>
<item type="id" name="apps_list_view_work" />
+ <item type="id" name="tag_widget_entry" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
<item type="id" name="view_type_widgets_search_header" />
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 5d9adf0..b668c90 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -18,6 +18,7 @@
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.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 @@
@Nullable private Predicate<WidgetsListBaseEntry> 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 @@
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 @@
@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 cdab964..ef2adbb 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -30,7 +30,6 @@
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 @@
@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 @@
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 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 3ee8b33..7671841 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -52,7 +52,7 @@
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 @@
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 @@
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;