SwiftUI/UIKit实现支持图片及iOS 16贴纸粘贴的画布方案咨询
SwiftUI 实现方案
基础视图选型
- 画布核心用
ZStack:底层放置白色背景作为空白画布,上层叠加所有可交互的贴纸/图片视图 - 可拖动贴纸封装为自定义
DraggableStickerView:通过DragGesture绑定位置,支持自由拖拽 - 上下文菜单用
.contextMenu修饰符:绑定画布背景,触发后读取系统粘贴板内容
实现步骤
- 画布与粘贴逻辑
- 定义
StickerItem结构体存储贴纸的位置和内容:struct StickerItem: Identifiable { let id = UUID() var position: CGPoint var content: Any // 存储Image或PKSticker,按需处理 } - 用
@State var stickers: [StickerItem] = []管理所有贴纸,给画布背景添加上下文菜单:ZStack { Color.white .contextMenu { Button("粘贴") { handlePaste() } } ForEach($stickers) { $item in DraggableStickerView(item: $item) } } - 实现
handlePaste()读取粘贴板内容,判断类型后添加到贴纸数组
- 定义
- 可拖动视图实现
- 自定义
DraggableStickerView,通过DragGesture更新绑定的位置:struct DraggableStickerView: View { @Binding var item: StickerItem var body: some View { if let image = item.content as? Image { image .resizable() .scaledToFit() .frame(width: 200, height: 200) .position(item.position) .gesture( DragGesture() .onChanged { value in item.position = value.location } ) } else if let sticker = item.content as? PKSticker { PKStickerViewRepresentable(sticker: sticker) .frame(width: 150, height: 150) .position(item.position) .gesture( DragGesture() .onChanged { value in item.position = value.location } ) } } } - 注:
PKStickerView需要通过UIViewRepresentable封装才能在SwiftUI中使用
- 自定义
- 粘贴板内容解析
- 处理图片和iOS16贴纸的核心逻辑:
func handlePaste() { let pasteboard = UIPasteboard.general // 处理图片 if let uiImage = pasteboard.image { let image = Image(uiImage: uiImage) stickers.append(StickerItem(position: CGPoint(x: 100, y: 100), content: image)) } // 处理iOS16贴纸 else if let provider = pasteboard.itemProviders.first(where: { $0.canLoadObject(ofClass: PKSticker.self) }) { provider.loadObject(ofClass: PKSticker.self) { result, error in guard let sticker = result as? PKSticker else { return } DispatchQueue.main.async { stickers.append(StickerItem(position: CGPoint(x: 100, y: 100), content: sticker)) } } } }
- 处理图片和iOS16贴纸的核心逻辑:
UIKit 实现方案
基础视图选型
- 画布用
UIView作为容器:底层添加白色背景视图,所有贴纸作为子视图叠加 - 可拖动贴纸用自定义
DraggableStickerView子类:通过触摸事件实现拖拽 - 上下文菜单用
UILongPressGestureRecognizer触发:唤起自定义菜单或系统UIMenuController - iOS16贴纸直接用
PKStickerView(需导入PhotosUI框架)
实现步骤
- 画布与粘贴菜单
- 创建画布容器
UIView,添加长按手势触发粘贴菜单:class CanvasViewController: UIViewController { let canvasView = UIView() var stickers: [DraggableStickerView] = [] override func viewDidLoad() { super.viewDidLoad() setupCanvas() let longPress = UILongPressGestureRecognizer(target: self, action: #selector(showPasteMenu)) canvasView.addGestureRecognizer(longPress) } func setupCanvas() { canvasView.backgroundColor = .white canvasView.frame = view.bounds view.addSubview(canvasView) } @objc func showPasteMenu() { let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "粘贴", style: .default, handler: { [weak self] _ in self?.handlePaste() })) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) present(alert, animated: true) } }
- 创建画布容器
- 可拖动贴纸实现
- 自定义
DraggableStickerView,重写触摸事件实现拖拽:class DraggableStickerView: UIView { private var initialTouchPoint: CGPoint = .zero private var initialFrame: CGRect = .zero override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) guard let touch = touches.first else { return } initialTouchPoint = touch.location(in: superview) initialFrame = frame bringSubviewToFront(self) } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesMoved(touches, with: event) guard let touch = touches.first else { return } let currentPoint = touch.location(in: superview) let offsetX = currentPoint.x - initialTouchPoint.x let offsetY = currentPoint.y - initialTouchPoint.y frame = CGRect(x: initialFrame.origin.x + offsetX, y: initialFrame.origin.y + offsetY, width: initialFrame.width, height: initialFrame.height) } }
- 自定义
- 粘贴板内容处理
- 解析图片和贴纸并添加到画布:
func handlePaste() { let pasteboard = UIPasteboard.general // 添加图片贴纸 if let image = pasteboard.image { let stickerView = DraggableStickerView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) let imageView = UIImageView(image: image) imageView.frame = stickerView.bounds imageView.contentMode = .scaleAspectFit stickerView.addSubview(imageView) canvasView.addSubview(stickerView) stickers.append(stickerView) } // 添加iOS16贴纸 else if let provider = pasteboard.itemProviders.first(where: { $0.canLoadObject(ofClass: PKSticker.self) }) { provider.loadObject(ofClass: PKSticker.self) { [weak self] result, error in guard let self = self, let sticker = result as? PKSticker else { return } DispatchQueue.main.async { let stickerView = PKStickerView(sticker: sticker) stickerView.frame = CGRect(x: 100, y: 100, width: 150, height: 150) let draggableView = DraggableStickerView(frame: stickerView.frame) draggableView.addSubview(stickerView) self.canvasView.addSubview(draggableView) self.stickers.append(draggableView) } } } }
- 解析图片和贴纸并添加到画布:
内容的提问来源于stack exchange,提问作者charelf
相关产品推荐
相关产品推荐

