上海互联网企业100强/深圳关键词优化软件
问题:MTK android 8.1 Launcher3 横屏状态长按图标 弹框位置居中分析.
现象:竖屏状态下正常,横屏状态下,长按最右边的apk图标弹出的信息框会显示在屏幕中间的位置.
期望:参考竖屏,应该显示在apk上方或者下方,方向偏向左边.
问题如图:
分析:
1.从Launcher3长按开始分析.
Luancher.java
@Overridepublic boolean onLongClick(View v) {if (!isDraggingEnabled()) return false;if (isWorkspaceLocked()) return false;if (mState != State.WORKSPACE) return false;boolean ignoreLongPressToOverview =mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEventX);if (v instanceof Workspace) {if (!mWorkspace.isInOverviewMode()) {if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) {getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,Action.Direction.NONE, ContainerType.WORKSPACE,mWorkspace.getCurrentPage());showOverviewMode(true);mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);return true;} else {return false;}} else {return false;}}CellLayout.CellInfo longClickCellInfo = null;View itemUnderLongClick = null;if (v.getTag() instanceof ItemInfo) {ItemInfo info = (ItemInfo) v.getTag();longClickCellInfo = new CellLayout.CellInfo(v, info);itemUnderLongClick = longClickCellInfo.cell;mPendingRequestArgs = null;}// The hotseat touch handling does not go through Workspace, and we always allow long press// on hotseat items.if (!mDragController.isDragging()) {if (itemUnderLongClick == null) {// User long pressed on empty spaceif (mWorkspace.isInOverviewMode()) {mWorkspace.startReordering(v);getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,Action.Direction.NONE, ContainerType.OVERVIEW);} else {if (ignoreLongPressToOverview) {return false;}getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,Action.Direction.NONE, ContainerType.WORKSPACE,mWorkspace.getCurrentPage());showOverviewMode(true);}mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);} else {final boolean isAllAppsButton =!FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) &&mDeviceProfile.inv.isAllAppsButtonRank(mHotseat.getOrderInHotseat(longClickCellInfo.cellX, longClickCellInfo.cellY));if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {// User long pressed on an itemmWorkspace.startDrag(longClickCellInfo, new DragOptions());}}}return true;}
经过打Log,确认跑了这个代码 mWorkspace.startDrag(longClickCellInfo, new DragOptions());
startDrag()-->beginDragShared()
if (child instanceof BubbleTextView && !dragOptions.isAccessibleDrag) {PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon((BubbleTextView) child);if (popupContainer != null) {dragOptions.preDragCondition = popupContainer.createPreDragCondition();mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();}}
调用了PopupContainerWithArrow.java的showForIcon().
showForIcon()-->populateAndShow().
populateAndShow()中有两个方法orientAboutIcon()和addArrowView()相关.
private void orientAboutIcon(BubbleTextView icon, int arrowHeight) {int width = getMeasuredWidth();int height = getMeasuredHeight() + arrowHeight;DragLayer dragLayer = mLauncher.getDragLayer();dragLayer.getDescendantRectRelativeToSelf(icon, mTempRect);Rect insets = dragLayer.getInsets();// Align left (right in RTL) if there is room.int leftAlignedX = mTempRect.left + icon.getPaddingLeft();int rightAlignedX = mTempRect.right - width - icon.getPaddingRight();int x = leftAlignedX;boolean canBeLeftAligned = leftAlignedX + width + insets.left< dragLayer.getRight() - insets.right;boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {x = rightAlignedX;}mIsLeftAligned = x == leftAlignedX;if (mIsRtl) {x -= dragLayer.getWidth() - width;}// Offset x so that the arrow and shortcut icons are center-aligned with the original icon.int iconWidth = icon.getWidth() - icon.getTotalPaddingLeft() - icon.getTotalPaddingRight();iconWidth *= icon.getScaleX();Resources resources = getResources();int xOffset;if (isAlignedWithStart()) {// Aligning with the shortcut icon.int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);int shortcutPaddingStart = resources.getDimensionPixelSize(R.dimen.popup_padding_start);xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;} else {// Aligning with the drag handle.int shortcutDragHandleWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_drag_handle_size);int shortcutPaddingEnd = resources.getDimensionPixelSize(R.dimen.popup_padding_end);xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;}x += mIsLeftAligned ? xOffset : -xOffset;// Open above icon if there is room.int iconHeight = icon.getIcon() != null? icon.getIcon().getBounds().height(): icon.getHeight();int y = mTempRect.top + icon.getPaddingTop() - height;mIsAboveIcon = y > dragLayer.getTop() + insets.top;if (!mIsAboveIcon) {y = mTempRect.top + icon.getPaddingTop() + iconHeight;}// Insets are added later, so subtract them now.if (mIsRtl) {x += insets.right;} else {x -= insets.left;}y -= insets.top;mGravity = 0;if (y + height > dragLayer.getBottom() - insets.bottom) {// The container is opening off the screen, so just center it in the drag layer instead.mGravity = Gravity.CENTER_VERTICAL;// Put the container next to the icon, preferring the right side in ltr (left in rtl).int rightSide = leftAlignedX + iconWidth - insets.left;int leftSide = rightAlignedX - iconWidth - insets.left;if (!mIsRtl) {if (rightSide + width < dragLayer.getRight()) {x = rightSide;mIsLeftAligned = true;} else {x = leftSide;mIsLeftAligned = false;}} else {if (leftSide > dragLayer.getLeft()) {x = leftSide;mIsLeftAligned = false;} else {x = rightSide;mIsLeftAligned = true;}}mIsAboveIcon = true;}setX(x);setY(y);}
在orientAboutIcon()经过一些方法的计算,最终确认setX(x)和setY(y).打印这两个值,未发现异常.均是长按图标的位置.
但是实际效果却是x,y的值不对.即显示位置不对,那么应该用其他地方重新设置了位置坐标x,y.经过搜索setX和setY.
PopupContainerWithArrow.java中,有enforceContainedWithinScreen()方法,很明显是这里修改了x,y的值.
private void enforceContainedWithinScreen(int left, int right) {DragLayer dragLayer = mLauncher.getDragLayer();if (getTranslationX() + left < 0 ||getTranslationX() + right > dragLayer.getWidth()) {// If we are still off screen, center horizontally too.mGravity |= Gravity.CENTER_HORIZONTAL;}if (Gravity.isHorizontal(mGravity)) {setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);}if (Gravity.isVertical(mGravity)) {setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);}}
经过打印Log:getTranslationX() + right>dragLayer.getWidth().
屏蔽enforceContainedWithinScreen()的setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
长按位置正确,但是方向不对.且屏蔽的改法是有风险的,当显示的信息框超出屏幕显示位置的时候,有部分不显示.这个跟屏幕的分辨率,Launcher桌面布局有关,所以不能在这里修改.
那么在这个判断之前,应该做的是让信息框整体不超过屏幕分辨率,如同竖屏那样.在apk图标的左边.
那么修改的地方应在populateAndShow()的两个方法orientAboutIcon()和addArrowView().
查看orientAboutIcon()方法,mIsLeftAligned这个变量经过翻译是:左对齐.
打印Log,显示横屏状态下,这个值一直为true.而在竖屏时,长按最右边的apk按钮是false,其他为true.
分析上面的判断,根据弹出框的大小,位置,显示屏的大小判断的.
原有的代码逻辑没有变动,我在这里增加了一个判断.
}x += mIsLeftAligned ? xOffset : -xOffset;+ //Add Begin :Modify the long click icon to display the
+ //information position.
+ int shortcutItemWidth =
+ resources.getDimensionPixelSize(R.dimen.bg_popup_item_width);
+ if( x + shortcutItemWidth > dragLayer.getWidth()){
+ mIsLeftAligned = false;
+ x = x - shortcutItemWidth + xOffset;
+ }
+ //Add End
+// Open above icon if there is room.int iconHeight = icon.getIcon() != null? icon.getIcon().getBounds().height()
这个判断为:x + shortcutItemWidth > dragLayer.getWidth().点击apk的位置的x值加上弹出框的宽度大于屏幕显示宽度时:
左对齐mIsLeftAligned为false,即为右对齐.同时需要重新调整x的位置.x = x - shortcutItemWidth + xOffset;
经过测试,问题解决.
如有更好的修改方法,欢迎交流.