bug现象图
修正效果图
packages\apps\Launcher3\src\com\android\launcher3\popup\ArrowPopup.java
protected void orientAboutObject() {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = getMeasuredWidth();
....
//cczheng add
if (x > 1000) {
x = 835;
mIsLeftAligned = false;
}
setX(x);
Log.d("ArrowPopup"," setX x="+x);
if (Gravity.isVertical(mGravity)) {
return;
}
....
}
orientAboutObject 方法中 setX() 之前重新修正 x 坐标即可,具体分析思路看下面
思路分析图
AllAppContainer 中最后一列图标长按显示是ok的,到了workspace中显示就错位了,仔细观察发现 y 值是对的,
加日志打印对比
workspace 容器中
音乐APP
2020-05-16 08:21:39.552 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: shortcutCount=0
2020-05-16 08:21:39.572 1669-1669/com.android.launcher3 I/ArrowPopup: MeasureSpec x=1045 y=462
2020-05-16 08:21:39.572 1669-1669/com.android.launcher3 D/ArrowPopup: setX x=1045
2020-05-16 08:21:39.572 1669-1669/com.android.launcher3 I/ArrowPopup: arrowLp.gravity=80 lp.bottomMargin=168 arrowLp.bottomMargin=101
2020-05-16 08:21:39.580 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: showForIcon=
2020-05-16 08:21:39.600 1669-1669/com.android.launcher3 I/ArrowPopup: set Gravity.CENTER_HORIZONTAL
2020-05-16 08:21:39.601 1669-1669/com.android.launcher3 D/ArrowPopup: INVISIBLE mArrow503
浏览器APP
2020-05-16 08:28:51.636 1669-1669/com.android.launcher3 I/ArrowPopup: MeasureSpec x=825 y=462
2020-05-16 08:28:51.636 1669-1669/com.android.launcher3 D/ArrowPopup: setX x=825
2020-05-16 08:28:51.636 1669-1669/com.android.launcher3 I/ArrowPopup: arrowLp.gravity=80 lp.bottomMargin=168 arrowLp.bottomMargin=101
AllAppContainer 容器中
信息APP
2020-05-16 08:22:08.903 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: shortcutCount=0
2020-05-16 08:22:08.916 1669-1669/com.android.launcher3 I/ArrowPopup: MeasureSpec x=899 y=76
2020-05-16 08:22:08.917 1669-1669/com.android.launcher3 D/ArrowPopup: setX x=899
2020-05-16 08:22:08.917 1669-1669/com.android.launcher3 I/ArrowPopup: arrowLp.gravity=80 lp.bottomMargin=554 arrowLp.bottomMargin=487
2020-05-16 08:22:08.926 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: showForIcon=
设置APP
2020-05-16 08:33:06.663 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: shortcutCount=3
2020-05-16 08:33:06.692 1669-1669/com.android.launcher3 I/ArrowPopup: MeasureSpec x=899 y=201
2020-05-16 08:33:06.692 1669-1669/com.android.launcher3 D/ArrowPopup: setX x=899
2020-05-16 08:33:06.692 1669-1669/com.android.launcher3 E/ArrowPopup: arrowLp.gravity=48 lp.topMargin=231 arrowLp.topMargin=194
2020-05-16 08:33:06.698 1669-1669/com.android.launcher3 E/PopupContainerWithArrow: showForIcon=
从上面的日志分析得出,每次错位时,x的值都是大于1000,而 AllAppContainer 中最后一列X最大值为 899,
workspace 中倒数第二列X值为825,所以要想最后一列 ArrowPopup 正确显示,X 就得在 825 到 899 之间。
所以重新修正 X 值,当 x > 1000 时,重新赋值为 835(经过几次测试效果得出值)
mIsLeftAligned = false; 用来控制小箭头的位置在 ArrowPopup 居右
对应获取 popup_arrow_horizontal_center_end,同时修改 mArrow X 坐标,反之则在 ArrowPopup 居左
protected void reorderAndShow(int viewsToFlip) {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
orientAboutObject();
boolean reverseOrder = mIsAboveIcon;
if (reverseOrder) {
int count = getChildCount();
ArrayList<View> allViews = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
if (i == viewsToFlip) {
Collections.reverse(allViews);
}
allViews.add(getChildAt(i));
}
Collections.reverse(allViews);
removeAllViews();
for (int i = 0; i < count; i++) {
addView(allViews.get(i));
}
orientAboutObject();
}
onInflationComplete(reverseOrder);
// Add the arrow.
final Resources res = getResources();
final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
? R.dimen.popup_arrow_horizontal_center_start
: R.dimen.popup_arrow_horizontal_center_end);
final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
getPopupContainer().addView(mArrow);
DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
Log.e("ArrowPopup","getX() ="+getX()+" arrowCenterOffset="+arrowCenterOffset
+" halfArrowWidth="+halfArrowWidth+" getMeasuredWidth()="+getMeasuredWidth());
if (mIsLeftAligned) {
Log.i("ArrowPopup"," mIsLeftAligned ="+mIsLeftAligned);
mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
} else {
mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
}
if (Gravity.isVertical(mGravity)) {
// This is only true if there wasn't room for the container next to the icon,
// so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
mArrow.setVisibility(INVISIBLE);
} else {
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
arrowLp.width, arrowLp.height, !mIsAboveIcon));
Paint arrowPaint = arrowDrawable.getPaint();
arrowPaint.setColor(Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
// The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
arrowPaint.setPathEffect(new CornerPathEffect(radius));
mArrow.setBackground(arrowDrawable);
// Clip off the part of the arrow that is underneath the popup.
if (mIsAboveIcon) {
mArrow.setClipBounds(new Rect(0, -mArrowOffset, arrowLp.width, arrowLp.height));
} else {
mArrow.setClipBounds(new Rect(0, 0, arrowLp.width, arrowLp.height + mArrowOffset));
}
mArrow.setElevation(getElevation());
}
mArrow.setPivotX(arrowLp.width / 2);
mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
Log.i("ArrowPopup"," arrowLp.width ="+arrowLp.width +" arrowLp.height="+arrowLp.height);
Log.d("ArrowPopup"," mArrow.X ="+ mArrow.getX() +" mArrow.Y="+ mArrow.getY());
animateOpen();
}
效果图
packages/apps/Launcher3/res/layout/launcher.xml
+++ b/alps/packages/apps/Launcher3/res/layout/launcher.xml
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
- <com.android.launcher3.pageindicators.WorkspacePageIndicator
+ <!-- <com.android.launcher3.pageindicators.WorkspacePageIndicator -->
+ <com.android.launcher3.pageindicators.PageIndicatorDots
android:id="@+id/page_indicator"
android:layout_width="match_parent"
- android:layout_height="@dimen/vertical_drag_handle_size"
+ android:layout_height="4dp"
android:layout_gravity="bottom|center_horizontal"
android:theme="@style/HomeScreenElementTheme" />
packages/apps/Launcher3/src/com/android/launcher3/Workspace.java
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
+import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.testing.TestProtocol;
@@ -110,7 +111,8 @@ import java.util.function.Predicate;
* Each page contains a number of icons, folders or widgets the user can
* interact with. A workspace is meant to be used with a fixed width only.
*/
-public class Workspace extends PagedView<WorkspacePageIndicator>
+// public class Workspace extends PagedView
+public class Workspace extends PagedView<PageIndicatorDots>
implements DropTarget, DragSource, View.OnTouchListener,
DragController.DragListener, Insettable, LauncherStateManager.StateHandler,
WorkspaceLayoutManager {
packages/apps/Launcher3/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import android.widget.FrameLayout;
+import android.graphics.Rect;
+import android.view.Gravity;
/**
* {@link PageIndicator} which shows dots per page. The active page is shown with the current
* accent color.
*/
-public class PageIndicatorDots extends View implements PageIndicator {
+public class PageIndicatorDots extends View implements PageIndicator, Insettable {
private static final float SHIFT_PER_ANIMATION = 0.5f;
private static final float SHIFT_THRESHOLD = 0.1f;
@@ -97,6 +103,8 @@ public class PageIndicatorDots extends View implements PageIndicator {
private float[] mEntryAnimationRadiusFactors;
+ private final Launcher mLauncher;
+
public PageIndicatorDots(Context context) {
this(context, null);
}
@@ -117,6 +125,41 @@ public class PageIndicatorDots extends View implements PageIndicator {
mInActiveColor = Themes.getAttrColor(context, android.R.attr.colorControlHighlight);
mIsRtl = Utilities.isRtl(getResources());
+
+ mLauncher = Launcher.getLauncher(context);
+ }
+
+ //add for change WorkspacePageIndicator line to dot
+ @Override
+ public void setInsets(Rect insets) {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+
+ if (grid.isVerticalBarLayout()) {
+ Rect padding = grid.workspacePadding;
+ lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
+ lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
+ lp.bottomMargin = padding.bottom;
+ } else {
+ lp.leftMargin = lp.rightMargin = 0;
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
+ }
+ setLayoutParams(lp);
+ }
+
+ /**
+ * Pauses all currently running animations.
+ */
+ public void pauseAnimations() {
+ stopAllAnimations();
+ }
+
+ /**
+ * Force-ends all currently running or paused animations.
+ */
+ public void skipAnimationsToEnd() {
+ stopAllAnimations();
}
@Override
@@ -126,6 +169,10 @@ public class PageIndicatorDots extends View implements PageIndicator {
currentScroll = totalScroll - currentScroll;
}
int scrollPerPage = totalScroll / (mNumPages - 1);
+ //add for change WorkspacePageIndicator line to dot
+ if (scrollPerPage == 0) {
+ return;
+ }
int pageToLeft = currentScroll / scrollPerPage;
int pageToLeftScroll = pageToLeft * scrollPerPage;
int pageToRightScroll = pageToLeftScroll + scrollPerPage;
packages/apps/Launcher3/src/com/android/launcher3/states/SpringLoadedState.java
public void onStateEnabled(Launcher launcher) {
Workspace ws = launcher.getWorkspace();
ws.showPageIndicatorAtCurrentScroll();
- ws.getPageIndicator().setShouldAutoHide(false);
+ // ws.getPageIndicator().setShouldAutoHide(false);
// Prevent any Un/InstallShortcutReceivers from updating the db while we are
// in spring loaded mode
@@ -96,7 +97,8 @@ public class SpringLoadedState extends LauncherState {
@Override
public void onStateDisabled(final Launcher launcher) {
- launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true);
+ // launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true);
// Re-enable any Un/InstallShortcutReceiver and now process any queued items
InstallShortcutReceiver.disableAndFlushInstallQueue(