Swift实现拖动角落调整UITextView大小的方法咨询
实现UITextView拖动角落调整尺寸的Swift解决方案
核心实现思路
- 给需要调整尺寸的UITextView添加4个角落的拖动触发视图(推荐大小24x24,支持超出UITextView边界响应点击,降低用户操作门槛)
- 给每个拖动视图绑定
UIPanGestureRecognizer手势,识别拖动位移 - 根据拖动的角落位置动态计算UITextView的新frame,同时设置最小尺寸限制,避免控件被拉到过小无法操作
- 额外添加选中状态逻辑,仅当文本视图被选中时显示拖动手柄和边框,契合主流照片编辑App的交互习惯
具体实现代码
第一步:自定义可调整尺寸的TextView子类
import UIKit class ResizableTextView: UITextView { // 拖动手柄尺寸 private let dragHandleSize: CGFloat = 24 // 文本视图最小允许尺寸 private let minTextViewSize: CGSize = CGSize(width: 60, height: 40) // 四个角落的拖动手柄 private var topLeftHandle: UIView! private var topRightHandle: UIView! private var bottomLeftHandle: UIView! private var bottomRightHandle: UIView! // 记录拖动开始时的原始frame private var initialFrame: CGRect = .zero override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) commonSetup() setupDragHandles() setHandlesHidden(true) } required init?(coder: NSCoder) { super.init(coder: coder) commonSetup() setupDragHandles() setHandlesHidden(true) } private func commonSetup() { isUserInteractionEnabled = true layer.borderColor = UIColor.systemBlue.cgColor layer.borderWidth = 0 clipsToBounds = false } private func setupDragHandles() { // 统一创建拖动手柄 func createHandle(action: Selector) -> UIView { let handle = UIView() handle.backgroundColor = .systemBlue handle.layer.cornerRadius = 4 handle.isUserInteractionEnabled = true let pan = UIPanGestureRecognizer(target: self, action: action) handle.addGestureRecognizer(pan) addSubview(handle) return handle } topLeftHandle = createHandle(action: #selector(handleTopLeftDrag(_:))) topRightHandle = createHandle(action: #selector(handleTopRightDrag(_:))) bottomLeftHandle = createHandle(action: #selector(handleBottomLeftDrag(_:))) bottomRightHandle = createHandle(action: #selector(handleBottomRightDrag(_:))) updateHandlesPosition() } private func updateHandlesPosition() { topLeftHandle.frame = CGRect(x: -dragHandleSize/2, y: -dragHandleSize/2, width: dragHandleSize, height: dragHandleSize) topRightHandle.frame = CGRect(x: bounds.width - dragHandleSize/2, y: -dragHandleSize/2, width: dragHandleSize, height: dragHandleSize) bottomLeftHandle.frame = CGRect(x: -dragHandleSize/2, y: bounds.height - dragHandleSize/2, width: dragHandleSize, height: dragHandleSize) bottomRightHandle.frame = CGRect(x: bounds.width - dragHandleSize/2, y: bounds.height - dragHandleSize/2, width: dragHandleSize, height: dragHandleSize) } private func setHandlesHidden(_ isHidden: Bool) { topLeftHandle.isHidden = isHidden topRightHandle.isHidden = isHidden bottomLeftHandle.isHidden = isHidden bottomRightHandle.isHidden = isHidden layer.borderWidth = isHidden ? 0 : 1 } // 选中状态切换手柄显示 override var isFirstResponder: Bool { didSet { setHandlesHidden(!isFirstResponder) } } override func layoutSubviews() { super.layoutSubviews() updateHandlesPosition() } // 四个角落拖动逻辑 @objc private func handleTopLeftDrag(_ gesture: UIPanGestureRecognizer) { processDrag(gesture: gesture, adjustTop: true, adjustLeft: true) } @objc private func handleTopRightDrag(_ gesture: UIPanGestureRecognizer) { processDrag(gesture: gesture, adjustTop: true, adjustLeft: false) } @objc private func handleBottomLeftDrag(_ gesture: UIPanGestureRecognizer) { processDrag(gesture: gesture, adjustTop: false, adjustLeft: true) } @objc private func handleBottomRightDrag(_ gesture: UIPanGestureRecognizer) { processDrag(gesture: gesture, adjustTop: false, adjustLeft: false) } private func processDrag(gesture: UIPanGestureRecognizer, adjustTop: Bool, adjustLeft: Bool) { let translation = gesture.translation(in: superview) if gesture.state == .began { initialFrame = frame } var newFrame = initialFrame if adjustTop { newFrame.origin.y = initialFrame.origin.y + translation.y newFrame.size.height = initialFrame.size.height - translation.y } else { newFrame.size.height = initialFrame.size.height + translation.y } if adjustLeft { newFrame.origin.x = initialFrame.origin.x + translation.x newFrame.size.width = initialFrame.size.width - translation.x } else { newFrame.size.width = initialFrame.size.width + translation.x } // 限制最小尺寸 if newFrame.width < minTextViewSize.width { newFrame.size.width = minTextViewSize.width if adjustLeft { newFrame.origin.x = initialFrame.origin.x + initialFrame.width - minTextViewSize.width } } if newFrame.height < minTextViewSize.height { newFrame.size.height = minTextViewSize.height if adjustTop { newFrame.origin.y = initialFrame.origin.y + initialFrame.height - minTextViewSize.height } } frame = newFrame } // 新增整体拖动移动位置的方法 func enableMoveGesture() { let movePan = UIPanGestureRecognizer(target: self, action: #selector(handleMoveDrag(_:))) addGestureRecognizer(movePan) } @objc private func handleMoveDrag(_ gesture: UIPanGestureRecognizer) { let translation = gesture.translation(in: superview) if gesture.state == .began { initialFrame = frame } frame = CGRect(x: initialFrame.origin.x + translation.x, y: initialFrame.origin.y + translation.y, width: initialFrame.width, height: initialFrame.height) } }
第二步:调用示例
在你的编辑页ViewController中使用:
// 画布视图为你承载相框、照片、文本的父视图 let textView = ResizableTextView(frame: CGRect(x: 100, y: 100, width: 160, height: 80)) textView.text = "自定义文本" textView.font = .systemFont(ofSize: 16) textView.enableMoveGesture() canvasView.addSubview(textView)
可选优化点
- 给拖动手柄添加阴影效果,提升视觉辨识度
- 调整尺寸时同步计算缩放比例,动态修改字体大小,实现文本与控件等比缩放效果
- 支持多文本选中后批量调整尺寸
内容的提问来源于stack exchange,提问作者aqeedat zameer
相关产品推荐
相关产品推荐

