当前位置: 首页 > news >正文

Launcher3中的CellLayout 和ShortcutAndWidgetContainer 的联系和各自职责

1. CellLayout(网格布局容器)

/*** 网格布局的核心容器,负责划分单元格和管理占用状态*/
public class CellLayout extends ViewGroup {private int mCellWidth = 100;  // 单元格宽度(像素)private int mCellHeight = 100; // 单元格高度private int mCountX = 4;      // 列数private int mCountY = 4;      // 行数!!!一个二维的boolean类型数据的数组,里面的每个数据都是boolean类型!!!private boolean[][] mOccupied = new boolean[mCountX][mCountY]; // 占用状态表private ShortcutsAndWidgetsContainer mContainer; // 子容器public CellLayout(Context context) {super(context);mContainer = new ShortcutsAndWidgetsContainer(context);addView(mContainer); // 添加唯一子容器}/*** 添加子View到指定单元格* @return 是否添加成功*/public boolean addViewToCell(View child, int cellX, int cellY, int spanX, int spanY) {// 1. 检查边界和占用状态if (!isRegionVacant(cellX, cellY, spanX, spanY)) {return false; // 区域被占用或越界}// 2. 标记单元格为已占用markCells(cellX, cellY, spanX, spanY, true);// 3. 生成布局参数并添加ViewLayoutParams lp = new LayoutParams(cellX, cellY, spanX, spanY);!!!	addView() 内部会调用 requestLayout() + invalidate(),强制容器更新 UI!!!这里的view ,以下的这些都可以添加进去!!!--->(基础控件	✅	TextViewButtonImageView 等可直接添加并显示。自定义 View	✅	继承自 View 或现有控件,需正确实现 onDraw()onMeasure()ViewGroup 容器	✅	如 LinearLayoutFrameLayout,可作为子容器嵌套。)mContainer.addView(child, lp);return true;}/** 检查目标区域是否全部空闲 */private boolean isRegionVacant(int cellX, int cellY, int spanX, int spanY) {for (int x = cellX; x < cellX + spanX; x++) {for (int y = cellY; y < cellY + spanY; y++) {if (x >= mCountX || y >= mCountY || mOccupied[x][y]) {return false; // 越界或已被占用}}}return true;}/** 标记/清除单元格占用状态 */private void markCells(int cellX, int cellY, int spanX, int spanY, boolean occupied) {for (int x = cellX; x < cellX + spanX; x++) {for (int y = cellY; y < cellY + spanY; y++) {mOccupied[x][y] = occupied;}}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 计算总宽高(单元格尺寸 × 数量)int width = mCellWidth * mCountX;int height = mCellHeight * mCountY;setMeasuredDimension(width, height);mContainer.measure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mContainer.layout(0, 0, r - l, b - t); // 子容器填满父布局}/** 自定义LayoutParams,携带单元格信息 */public static class LayoutParams extends ViewGroup.LayoutParams {public int cellX, cellY; // 起始单元格坐标public int spanX, spanY; // 跨单元格数public LayoutParams(int cellX, int cellY, int spanX, int spanY) {super(0, 0);this.cellX = cellX;this.cellY = cellY;this.spanX = spanX;this.spanY = spanY;}}
}

2. ShortcutsAndWidgetsContainer(子View容器)

/*** 实际承载所有子View的容器,负责具体布局*/
public class ShortcutsAndWidgetsContainer extends ViewGroup {private int mCellWidth, mCellHeight; // 从CellLayout接收的单元格尺寸public ShortcutsAndWidgetsContainer(Context context) {super(context);}/** 接收CellLayout传递的网格参数 */public void setCellDimensions(int cellWidth, int cellHeight) {mCellWidth = cellWidth;mCellHeight = cellHeight;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 测量所有子View(根据跨单元格数计算实际尺寸)for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();int childWidth = lp.spanX * mCellWidth;int childHeight = lp.spanY * mCellHeight;child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 遍历所有子View,根据单元格坐标计算实际位置for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();int left = lp.cellX * mCellWidth;int top = lp.cellY * mCellHeight;child.layout(left,top,left + child.getMeasuredWidth(),top + child.getMeasuredHeight());}}@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof CellLayout.LayoutParams; // 只接受自定义LayoutParams}
}

3. 使用示例

// 初始化CellLayout(4x4网格)
CellLayout cellLayout = new CellLayout(context);
setContentView(cellLayout);// 添加一个1x1的图标到(1,2)位置
ImageView icon = new ImageView(context);
icon.setImageResource(R.drawable.ic_launcher);
cellLayout.addViewToCell(icon, 1, 2, 1, 1);// 添加一个2x2的小部件到(0,0)位置
View widget = new View(context);
widget.setBackgroundColor(Color.BLUE);
cellLayout.addViewToCell(widget, 0, 0, 2, 2);

关键交互流程图

User CellLayout ShortcutsAndWidgetsContainer icon 调用addViewToCell(icon, 1, 2, 1, 1) 检查mOccupied[1][2]是否空闲 标记mOccupied[1][2]=true addView(icon, LayoutParams) 计算实际像素位置(x=100,y=200) layout(100,200,200,300) User CellLayout ShortcutsAndWidgetsContainer icon

总结

组件职责
CellLayout管理网格参数、占用状态、处理高层的交互逻辑(如拖拽)
ShortcutsAndWidgetsContainer实际承载子View,负责具体的测量和布局(像素级计算)
mOccupied二维数组快速记录单元格占用状态,避免遍历所有子View
http://www.lqws.cn/news/558271.html

相关文章:

  • 剑指offer50_0到n-1中缺失的数字
  • python -日期与天数的转换
  • autoas/as 工程的RTE静态消息总线实现与端口数据交换机制详解
  • 解决flash-attn安装报错的问题
  • 【C】陷波滤波器
  • 鸿蒙开发:资讯项目实战之底部导航封装
  • MySQL之MVCC实现原理深度解析
  • 类和对象(中)
  • springboot+Vue驾校管理系统
  • 开疆智能ModbusTCP转CClinkIE网关连接台达DVP-ES3 PLC配置案例
  • Java-正则表达式
  • 测量 Linux 中进程上下文切换需要的时间
  • cocos creator 3.8 - 精品源码 - 挪车超人(挪车消消乐)
  • 同步日志系统深度解析【链式调用】【宏定义】【固定缓冲区】【线程局部存储】【RAII】
  • 蚂蚁百宝箱体验:如何快速创建“旅游小助手”AI智能体
  • LINUX628 NFS 多web;主从dns;ntp;samba
  • AlphaGenome:基因组学领域的人工智能革命
  • Linux离线搭建Redis (centos7)详细操作步骤
  • 深入解析 Electron 核心模块:构建跨平台桌面应用的关键
  • 《Go语言高级编程》玩转RPC
  • Vue.js 中的 v-model 和 :value:理解父子组件的数据绑定
  • 网络 : 传输层【UDP协议】
  • (线性代数)矩阵的奇异值Singular Value
  • WPS之PPT镂空效果实现
  • 笔记07:网表的输出与导入
  • spring中maven缺少包如何重新加载,报错java: 程序包org.springframework.web.reactive.function不存在
  • FPGA产品
  • 深入理解Java四大引用:强引用、软引用、弱引用与虚引用
  • 2.2.3、CAN总线-位时间特性、中断
  • 开源项目推荐:MCP Registry——管理MCP服务器的利器