Fix scrolling issue in the full widgets picker
Before this change, the widgets recommendation table handles all the touch events. The table doesn't distinguish a touch event from a scroll event. This change forwards the motion event to the active recycler view. If the recycler view doesn't handle the event, it will then forward the event back to the view hierarchy. Test: Open the full widgets picker, then start scrolling on the recommended widgets UI. The full widgets picker scrolls perfectly. Drag-n-drop a recommended widget Bug: 186567644 Change-Id: I89d473179796c516d2394332dd75f8e9a1d8b388
This commit is contained in:
parent
e80a0caa81
commit
edfec2fc0b
|
@ -13,7 +13,7 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout
|
||||
<com.android.launcher3.widget.picker.SearchAndRecommendationsView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/search_and_recommendations_container"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -49,4 +49,4 @@
|
|||
android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</com.android.launcher3.widget.picker.SearchAndRecommendationsView>
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.widget.RelativeLayout;
|
||||
|
@ -33,9 +35,11 @@ final class SearchAndRecommendationsScrollController implements
|
|||
RecyclerViewFastScroller.OnFastScrollChangeListener {
|
||||
private final boolean mHasWorkProfile;
|
||||
private final SearchAndRecommendationViewHolder mViewHolder;
|
||||
private final View mSearchAndRecommendationViewParent;
|
||||
private final WidgetsRecyclerView mPrimaryRecyclerView;
|
||||
private final WidgetsRecyclerView mSearchRecyclerView;
|
||||
private final int mTabsHeight;
|
||||
private final Point mTempOffset = new Point();
|
||||
|
||||
// The following are only non null if mHasWorkProfile is true.
|
||||
@Nullable private final WidgetsRecyclerView mWorkRecyclerView;
|
||||
|
@ -62,6 +66,8 @@ final class SearchAndRecommendationsScrollController implements
|
|||
*/
|
||||
private int mCollapsibleHeightForTabs = 0;
|
||||
|
||||
private boolean mShouldForwardToRecyclerView = false;
|
||||
|
||||
SearchAndRecommendationsScrollController(
|
||||
boolean hasWorkProfile,
|
||||
int tabsHeight,
|
||||
|
@ -73,6 +79,8 @@ final class SearchAndRecommendationsScrollController implements
|
|||
@Nullable PersonalWorkPagedView primaryWorkViewPager) {
|
||||
mHasWorkProfile = hasWorkProfile;
|
||||
mViewHolder = viewHolder;
|
||||
mViewHolder.mContainer.setSearchAndRecommendationScrollController(this);
|
||||
mSearchAndRecommendationViewParent = (View) mViewHolder.mContainer.getParent();
|
||||
mPrimaryRecyclerView = primaryRecyclerView;
|
||||
mCurrentRecyclerView = mPrimaryRecyclerView;
|
||||
mWorkRecyclerView = workRecyclerView;
|
||||
|
@ -245,6 +253,43 @@ final class SearchAndRecommendationsScrollController implements
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a touch event should be intercepted by this controller.
|
||||
*/
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
calculateMotionEventOffset(mTempOffset);
|
||||
event.offsetLocation(mTempOffset.x, mTempOffset.y);
|
||||
try {
|
||||
mShouldForwardToRecyclerView = mCurrentRecyclerView.onInterceptTouchEvent(event);
|
||||
return mShouldForwardToRecyclerView;
|
||||
} finally {
|
||||
event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this controller has intercepted and consumed a touch event.
|
||||
*/
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mShouldForwardToRecyclerView) {
|
||||
calculateMotionEventOffset(mTempOffset);
|
||||
event.offsetLocation(mTempOffset.x, mTempOffset.y);
|
||||
try {
|
||||
return mCurrentRecyclerView.onTouchEvent(event);
|
||||
} finally {
|
||||
event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void calculateMotionEventOffset(Point p) {
|
||||
p.x = mViewHolder.mContainer.getLeft() - mCurrentRecyclerView.getLeft()
|
||||
- mSearchAndRecommendationViewParent.getLeft();
|
||||
p.y = mViewHolder.mContainer.getTop() - mCurrentRecyclerView.getTop()
|
||||
- mSearchAndRecommendationViewParent.getTop();
|
||||
}
|
||||
|
||||
/** private the height, in pixel, + the vertical margins of a given view. */
|
||||
private static int measureHeightWithVerticalMargins(View view) {
|
||||
if (view.getVisibility() != View.VISIBLE) {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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.widget.picker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* A {@link LinearLayout} container for holding search and widgets recommendation.
|
||||
*
|
||||
* <p>This class intercepts touch events and dispatch them to the right view.
|
||||
*/
|
||||
public class SearchAndRecommendationsView extends LinearLayout {
|
||||
private SearchAndRecommendationsScrollController mController;
|
||||
|
||||
public SearchAndRecommendationsView(Context context) {
|
||||
this(context, /* attrs= */ null);
|
||||
}
|
||||
|
||||
public SearchAndRecommendationsView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, /* defStyleAttr= */ 0);
|
||||
}
|
||||
|
||||
public SearchAndRecommendationsView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, /* defStyleRes= */ 0);
|
||||
}
|
||||
|
||||
public SearchAndRecommendationsView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
public void setSearchAndRecommendationScrollController(
|
||||
SearchAndRecommendationsScrollController controller) {
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return mController.onInterceptTouchEvent(event) || super.onInterceptTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return mController.onTouchEvent(event) || super.onTouchEvent(event);
|
||||
}
|
||||
}
|
|
@ -709,13 +709,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||
}
|
||||
|
||||
final class SearchAndRecommendationViewHolder {
|
||||
final ViewGroup mContainer;
|
||||
final SearchAndRecommendationsView mContainer;
|
||||
final View mCollapseHandle;
|
||||
final WidgetsSearchBar mSearchBar;
|
||||
final TextView mHeaderTitle;
|
||||
final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
|
||||
|
||||
SearchAndRecommendationViewHolder(ViewGroup searchAndRecommendationContainer) {
|
||||
SearchAndRecommendationViewHolder(
|
||||
SearchAndRecommendationsView searchAndRecommendationContainer) {
|
||||
mContainer = searchAndRecommendationContainer;
|
||||
mCollapseHandle = mContainer.findViewById(R.id.collapse_handle);
|
||||
mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
|
||||
|
|
Loading…
Reference in New Issue