无法为SwipeableContainer设置宽度约束及容器重复添加报错求助
问题解决:SwipeableContainer宽度约束与样式优化
错误根源分析
原代码抛出Component is already contained in Container异常,核心原因是循环内重复将同一个lsd、rsd容器实例添加到contactsForm——Codename One中组件不能同时存在于多个容器,也不能在同一容器中重复添加。同时原逻辑试图在循环中为每个联系人单独构建三列布局,不符合TableLayout的使用逻辑,导致仅能显示首个联系人。
彻底解决宽度约束的方案
核心调整点
- 仅在循环外初始化一次左右空白容器与中间列表容器,统一添加到
contactsForm的TableLayout中,确保布局结构唯一。 - 循环内仅将单个联系人的
SwipeableContainer添加到中间列表容器,避免重复组件添加。 - 修正删除逻辑:操作单个
SwipeableContainer而非整个列表容器,保证删除动画正常执行。
修正后的完整代码
private void showContactsList(boolean forward) { try { Contact c = new Contact(); List<PropertyBusinessObject> contacts = sm.select(c, c.name, true, 1000, 0); // 初始化布局容器:左右空白+中间可滚动列表容器 Container leftSpacer = new Container(); Container rosterList = new Container(BoxLayout.y()); rosterList.setScrollableY(true); // 开启垂直滚动,适配大量球员数据 Container rightSpacer = new Container(); // 为contactsForm设置三列布局:左25%空白,中50%列表,右25%空白,实现居中效果 contactsForm.add(tL.createConstraint().heightPercentage(100).widthPercentage(25), leftSpacer); contactsForm.add(tL.createConstraint().heightPercentage(100).widthPercentage(50), rosterList); contactsForm.add(tL.createConstraint().heightPercentage(100).widthPercentage(25), rightSpacer); for(PropertyBusinessObject currentContact : contacts) { String name = ((Contact)currentContact).name.get(); if(name == null || name.isEmpty()) { name = "[null]"; } // 创建球员姓名按钮 MultiButton contactBtn = new MultiButton(name); contactBtn.setUIID("RosterMultiButton"); // 自定义UIID用于样式配置 contactBtn.addActionListener(e -> editContact((Contact)currentContact)); // 创建删除按钮 Button deleteBtn = new Button(""); FontImage.setMaterialIcon(deleteBtn, FontImage.MATERIAL_DELETE, 6); // 创建可滑动容器 SwipeableContainer swipeItem = new SwipeableContainer(deleteBtn, contactBtn); // 删除逻辑修正:操作当前滑动项而非整个列表 deleteBtn.addActionListener(e -> { try { sm.delete(currentContact); // 执行删除动画 swipeItem.setX(contactsForm.getWidth()); contactsForm.getContentPane().animateUnlayoutAndWait(200, 255); rosterList.remove(swipeItem); contactsForm.getContentPane().animateLayout(180); } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("删除失败: "+ err); } }); // 将单个滑动项添加到列表容器 rosterList.add(swipeItem); } if(forward) { contactsForm.show(); } else { contactsForm.showBack(); } } catch(Exception err) { Log.e(err); } }
界面样式完善建议
1. MultiButton字体样式调整
可以通过代码直接设置,或通过主题编辑器配置UIID:
- 代码方式:
// 自定义字体大小与样式 Font customFont = Font.createTrueTypeFont("native:MainLight", "native:MainLight").derive(20f, Font.STYLE_PLAIN); contactBtn.getUnselectedStyle().setFont(customFont); contactBtn.getSelectedStyle().setFont(customFont); // 设置文本居中对齐 contactBtn.getAllStyles().setAlignment(Component.CENTER);
- 主题UIID方式:在
theme.res中为RosterMultiButton设置:font:选择合适的字体与大小alignment:居中对齐padding:调整上下左右内边距,优化项间距
2. 列表项视觉优化
- 为
SwipeableContainer设置UIID,添加背景色或边框区分列表项:
swipeItem.setUIID("RosterSwipeItem");
在主题中为RosterSwipeItem配置bgColor(背景色)、border(边框)属性,提升视觉层次感。
3. 平板适配细节
- 中间列表容器的宽度百分比可根据平板尺寸调整(如40%-60%区间),保证视觉舒适。
- 为删除按钮添加红色背景,增强滑动后的操作提示:
deleteBtn.getAllStyles().setBgColor(0xffcc0000); deleteBtn.getAllStyles().setBgTransparency(255);
内容的提问来源于stack exchange,提问作者curtjacobs1
相关产品推荐
相关产品推荐

