基于 Launcher3 的 iOS 风格桌面 04 拖拽和移位

查看效果图

  • 删除自动补位

  • 拖拽自动排位

  • 跨页拖拽自动排位

需要做的 todo list

  • 删除移位
    • 删除图标时后方应用前移
  • 拖拽移位
    • 页面内拖拽
      • 应用前移/后移
    • 跨页拖拽
      • 拖拽到满屏页面

删除移位

  • 删除应用时后方应用前移
  • 修改 Workspace.javaremoveItemsByMatcher 方法:
java 复制代码
public void removeItemsByMatcher(final Predicate<ItemInfo> matcher) {
  // RemoveItem used to save the removed item
  ItemInfo removedItem = null;
  for (int i = container.getChildCount() - 1; i >= 0; i--) {
    View child = container.getChildAt(i);
    ItemInfo info = (ItemInfo) child.getTag();
    if (matcher.test(info)) {
      layout.removeViewInLayout(child);
      if (child instanceof DropTarget) {
          mDragController.removeDropTarget((DropTarget) child);
      }
      // Save the remove item
      removedItem = info;
    }
    ...
  }

  if (removedItem != null) {
    // Move children forward, start from the removed empty cell
    ReorderManager.moveChildrenForward(workspace, positionProvider, removedItem);
  }
}

拖拽移位

页面内拖拽-应用前移/后移

  • ReorderAlgorithm.java 中修改 findReorderSolution 方法:
java 复制代码
fun findReorderSolution(
  pixelX: Int, pixelY: Int, minSpanX: Int,
  minSpanY: Int, spanX: Int, spanY: Int, direction: IntArray?, dragView: View?, decX: Boolean,
  solution: ItemConfiguration
): ItemConfiguration {
  ...
  val success: Boolean = if (dragView is AppWidgetHostView) {
    mCellLayout.rearrangementExists(
        result[0], result[1], spanX, spanY, direction,
        dragView, solution
    )
  } else {
    // Rearrange children in the cell layout
    mCellLayout.rearrangeChildren(result[0], result[1], dragView, solution)
  }
  ...
}
  • CellLayout.java 中添加 rearrangeChildren 方法:
java 复制代码
public boolean rearrangeChildren(int cellX, int cellY, View dragView, ItemConfiguration solution) {
  // Return early if get invalid cell positions
  if (cellX < 0 || cellY < 0) return false;

  // Get all views in this cell layout
  Comparator<View> comparator = ReorderManager.getComparator();
  List<View> views = solution.map.keySet().stream().filter(view -> view instanceof CellView || view instanceof FolderIcon).sorted(comparator).collect(Collectors.toList());

  // Get target cell index and dragging cell index
  int targetIndex = ReorderManager.findItemIndex(views, new CellPos(cellX, cellY, getWorkspace().getIdForScreen(this)));
  int dragIndex = views.indexOf(dragView);
  if (targetIndex < 0 || dragIndex < 0) return false;

  // If target index > drag index, move views forward, otherwise move backward
  boolean isMovingForward = targetIndex > dragIndex;

  // Get all views to be moved
  int fromIndex = Math.min(targetIndex, dragIndex);
  int toIndex = Math.max(targetIndex, dragIndex);
  List<View> moveViews = views.subList(fromIndex, toIndex + 1);

  // Calc new cell positions for the views to be moved
  moveViews.forEach(view -> {
    CellAndSpan cellAndSpan = solution.map.get(view);
    if (cellAndSpan == null) {
        return;
    }
    
    int currentIndex = moveViews.indexOf(view);
    // Moving forwards, ignore the first dragView
    if (isMovingForward && currentIndex == 0) {
      return;
    }
    // Moving backwards, ignore the last targetView
    if (!isMovingForward && currentIndex == moveViews.size() - 1) {
      return;
    }
    // Calc the new cell position
    CellPos newPos;
    if (isMovingForward) {
      newPos = ReorderManager.calcNewForwardPosition(view);
    } else {
      newPos = ReorderManager.calcNewBackwardPosition(view);
    }
    cellAndSpan.cellX = newPos.cellX;
    cellAndSpan.cellY = newPos.cellY;
  });

  // Set the dragging view's target cell position
  if (dragView != null) {
    CellAndSpan c = solution.map.get(dragView);
    if (c != null) {
      c.cellX = cellX;
      c.cellY = cellY;
    }
  }

  return true;
}

跨页拖拽

  • SpringLoadedDragController.java 中修改 onAlarm 方法:
java 复制代码
override fun onAlarm(alarm: Alarm) {
  mScreen?.let { targetScreen ->
  // Snap to the screen that we are hovering over now
  val w = mLauncher.workspace
  if (!w.isVisible(targetScreen)) {
      // If the target screen is full, we need to prepare an empty cell for the dragging view
      if (!targetScreen.existsEmptyCell()) {
          ReorderManager.prepareEmptyCell(w, targetScreen)
      }
      w.snapToPage(w.indexOfChild(targetScreen))
  }
  } ?: run {
      mLauncher.dragController.cancelDrag()
  }
}
相关推荐
李堇44 分钟前
android滚动列表VerticalRollingTextView
android·java
lxysbly2 小时前
n64模拟器安卓版带金手指2026
android
游戏开发爱好者85 小时前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
王码码20355 小时前
Flutter for OpenHarmony 实战之基础组件:第三十一篇 Chip 系列组件 — 灵活的标签化交互
android·flutter·交互·harmonyos
黑码哥5 小时前
ViewHolder设计模式深度剖析:iOS开发者掌握Android列表性能优化的实战指南
android·ios·性能优化·跨平台开发·viewholder
亓才孓6 小时前
[JDBC]元数据
android
独行soc6 小时前
2026年渗透测试面试题总结-17(题目+回答)
android·网络·安全·web安全·渗透测试·安全狮
金融RPA机器人丨实在智能6 小时前
Android Studio开发App项目进入AI深水区:实在智能Agent引领无代码交互革命
android·人工智能·ai·android studio
科技块儿6 小时前
利用IP查询在智慧城市交通信号系统中的应用探索
android·tcp/ip·智慧城市
独行soc6 小时前
2026年渗透测试面试题总结-18(题目+回答)
android·网络·安全·web安全·渗透测试·安全狮