如何将UIButton以列表形式插入UITextView避免位置重叠
重叠问题根因
按钮全部落在同一位置互相重叠,是两个核心问题叠加导致的:
- 跨父视图迁移时未做坐标系转换:原本UIButton的frame是相对于原scrollView坐标系定义的,直接添加到UITextView上时,两套坐标系不匹配,没有做位置修正的话,所有按钮都会错位到相同的原点位置
- 未给按钮设置独立布局:新添加的子视图如果没有明确的frame或者Auto Layout约束,系统会默认将其放置在父视图的(0, 0)初始位置,自然会全部堆叠在一起
另外需要注意:UITextView本身是可滚动容器,如果希望按钮跟随文本内容一起滚动,不能直接把按钮添加到UITextView的根视图层级,否则按钮会固定在可视区域,不会随内容滚动。
落地解决步骤
方案1:保留按钮在原scrollView中的相对位置
如果需要保持按钮原本的排列顺序和间距,迁移时必须做坐标系转换,将按钮位置对齐到UITextView的内容坐标系:
// 遍历原scrollView中的所有UIButton for button in scrollView.subviews.compactMap({ $0 as? UIButton }) { // 把按钮的bounds从原scrollView坐标系,转换到UITextView的文本容器坐标系 let targetFrame = button.convert(button.bounds, to: textView.textContainer) // 从原父视图移除按钮 button.removeFromSuperview() // 添加到UITextView上 textView.addSubview(button) // 赋值转换后的正确frame button.frame = targetFrame }
方案2:自定义按钮在UITextView内的排列规则
如果不需要保留原scrollView的位置,可以手动为每个按钮设置独立的位置,避免重叠,比如按垂直顺序排列所有按钮:
// 记录当前按钮的Y轴偏移量 var yOffset: CGFloat = 0 let buttonHeight: CGFloat = 44 let horizontalMargin: CGFloat = 16 for button in buttonList { button.removeFromSuperview() textView.addSubview(button) // 为每个按钮设置独立的frame,Y值随按钮高度累加,避免重叠 button.frame = CGRect( x: horizontalMargin, y: yOffset, width: textView.bounds.width - horizontalMargin * 2, height: buttonHeight ) // 累加偏移量,给下一个按钮预留位置 yOffset += buttonHeight }
如果使用Auto Layout布局按钮,需要为每个按钮设置独立的顶部约束常量,依次累加每个按钮的高度,不能让所有按钮的顶部约束都对齐到同一参照位置,否则同样会出现重叠。
收尾:适配UITextView的滚动范围
UITextView的可滚动区域由contentSize决定,添加完所有按钮后,需要手动更新contentSize,确保所有按钮都在可滚动范围内,不会被截断:
// 内容高度对齐到最后一个按钮的底部,加上文本容器的底部内边距 textView.contentSize = CGSize( width: textView.bounds.width, height: yOffset + textView.textContainerInset.bottom )
内容的提问来源于stack exchange,提问作者Aviav Sabag
相关产品推荐
相关产品推荐

