当前位置: 首页 > 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.lryc.cn/news/576471.html

相关文章:

  • 前端react面试题之实现网页多选搜索框
  • 【学习笔记】深入理解Java虚拟机学习笔记——第12章 Java内存模型与线程
  • python中学物理实验模拟:瞬间推力与摩擦力作用下的物体运动
  • 力扣网C语言编程题:在数组中查找目标值位置之二分查找法
  • 解决cursor无法下载插件等网络问题
  • 深入详解:随机森林算法——概念、原理、实现与应用场景
  • screen用法
  • Gradio全解13——MCP详解(4)——TypeScript包命令:npm与npx
  • 服务器的维护技术都有哪些?
  • Flutter基础(Isolate)
  • 【论文阅读笔记】知网SCI——基于主成分分析的空间外差干涉数据校正研究
  • 开疆智能CCLinkIE转ModbusTCP网关连接傲博机器人配置案例
  • 舵机在不同类型机器人中的应用
  • JVM调优实战 Day 10:性能指标采集与可视化
  • 【闲谈】技术债:软件开发的隐形杀手
  • Redis高级数据结构深度解析:BitMap、布隆过滤器、HyperLogLog与Geo应用实践
  • JWT认证性能优化实战指南
  • 《剖开WebAssembly 2.0:C++/Rust内存管理困局与破局》
  • 剑指offer48_两个链表的第一个公共节点
  • 叉车考试真题(含答案)pdf下载
  • 告别脚本!用浏览器为 AWS CLI 实现真正的 Cognito 单点登录
  • 案例开发 - 日程管理系统 - 第一期
  • PostgreSQL对比Mysql
  • WPS之PPT镂空效果实现
  • Lua现学现卖
  • 数据湖 vs 数据仓库:数据界的“自来水厂”与“瓶装水厂”?
  • 如何利用好doctor
  • lambda、function基础/响应式编程基础
  • JSON简介及其应用
  • 【世纪龙科技】新能源汽车动力电池总成装调与检修教学软件