MatchedGeometryEffect中isHidden失效:多视图插入错误排查
问题原因分析
- 视图与数据不同步:
Board视图里的arr是初始化时赋值的常量,后续dm.wordArray更新时,arr不会自动同步,导致视图依然渲染旧数据,原选中瓷砖无法被正确移除。 matchedGeometryEffectID冲突:
执行wordArray[row][col] = temp后,顶部瓷砖的对象同时存在于原顶部位置和选中位置,两个视图共用同一个word作为matchedGeometryEffect的ID,触发了"多个source视图匹配同一ID"的错误,最终出现瓷砖重叠。- 隐藏逻辑失效:
你先给原选中瓷砖设置isHidden = true,但随后用temp替换了该位置的对象,此时设置的隐藏状态只对被替换的旧对象生效,新赋值的temp对象isHidden为false,所以选中位置的新瓷砖不会隐藏,旧瓷砖因视图未同步还在渲染,导致重叠。
解决方案
1. 修复视图数据同步问题
直接在Board视图中使用dm.wordArray,去掉初始化时的常量arr,确保数据变化时视图实时刷新:
struct Board: View { @ObservedObject var dm: DataModel @Namespace var namespace var body: some View { ZStack{ VStack(spacing: 10) { ForEach(0 ..< 4) { i in HStack(spacing: 10) { ForEach(0 ..< 4) { j in Tile(word: dm.wordArray[i][j]!, dm: dm) .modifier(Shake(animatableData: CGFloat(dm.shakes[i][j] ? 1 : 0))) .opacity(dm.wordArray[i][j]!.isHidden ? 0 : 1) .matchedGeometryEffect(id: dm.wordArray[i][j]!.word, in: namespace) } } } } } } }
2. 调整数据更新逻辑,避免ID冲突
同时处理顶部位置的瓷砖状态,确保同一个ID只对应一个视图:
if row != topmostRow { let temp = wordArray[topmostRow][leftmostCol] let oldSelectedTile = wordArray[row][col] withAnimation(.linear(duration: 0.4)) { // 隐藏原选中瓷砖 oldSelectedTile?.isHidden = true // 隐藏顶部原位置的瓷砖(或替换为新瓷砖,根据业务需求) wordArray[topmostRow][leftmostCol]?.isHidden = true // 将顶部瓷砖移动到选中位置 wordArray[row][col] = temp } }
如果顶部位置需要生成新瓷砖,直接替换wordArray[topmostRow][leftmostCol]为新的Word对象,彻底避免同一ID重复出现。
3. 确保matchedGeometryEffect ID唯一
给Word模型添加唯一UUID标识,替代word字符串作为ID,从根源避免重复:
// 修改Word模型 struct Word: Identifiable { let id = UUID() var word: String var isHidden: Bool = false // 其他属性 } // 在Board视图中使用唯一ID .matchedGeometryEffect(id: dm.wordArray[i][j]!.id, in: namespace)
内容的提问来源于stack exchange,提问作者hstutea
相关产品推荐
相关产品推荐

