如何设置UIScrollView为3D正方形

11
我正在开发一款照片编辑App,其中有3个带UIImageview的滚动视图,我想将滚动视图设置如下图所示:

enter image description here

我尝试了“Scenekit”,但是它不起作用,因为我需要滚动视图。
基本上,我想创建一个3D拼贴画。是否有其他方法可以实现这个效果?
是否有可能把UIScrollView设置成像3D正方形那样的形状?
3个回答

6
我用以下代码通过CATransform3D实现了这个目标:

我在StoryBoard中创建了3个带有UIImageview的滚动视图。

@IBOutlet var faces: [UIView]!

ViewDidiLoad

    var perspective: CATransform3D = CATransform3DIdentity
    perspective.m34 = -1.0 / 500.0

    self.view?.layer.sublayerTransform = perspective

    perspective = CATransform3DRotate(perspective, CGFloat(-Double.pi / 4), 1, 0, 0)
    perspective = CATransform3DRotate(perspective, CGFloat(-Double.pi / 4), 0, 1, 0)

    print(perspective)

    self.view.layer.sublayerTransform = perspective

    //add cube face 1
    var transform: CATransform3D = CATransform3DMakeTranslation(0, 0, 50)
    addFace(0, withTransform: transform)

    //add cube face 2
    transform = CATransform3DMakeTranslation(50, 0, 0)
    transform = CATransform3DRotate(transform, CGFloat(Double.pi / 2), 0, 1, 0)

    addFace(1, withTransform: transform)

    //add cube face 3
    transform = CATransform3DMakeTranslation(0, -50, 0)
    transform = CATransform3DRotate(transform, CGFloat(Double.pi / 2), 1, 0, 0)

    addFace(2, withTransform: transform)

addFace Function

func addFace(_ index: Int, withTransform transform: CATransform3D) {
    let face: UIView? = faces[index]

    if let aFace = face {
        self.view.addSubview(aFace)
    }

    let containerSize: CGSize? = self.view.bounds.size

    face?.center = CGPoint(x: (containerSize?.width ?? 0.0) / 2.0, y: (containerSize?.height ?? 0.0) / 2.0)
    face?.layer.transform = transform
}

输出

在此输入图片描述


4
似乎你需要使用手势旋转立方体以调整拼贴。所以,你不能仅使用UIKit来实现相同的效果。
在你的需求中,将UIKit坐标系转换为SceneKit坐标系是有挑战性的。
相反,你需要同时利用SceneKit和UIKit来完成这个任务。
请按照以下步骤操作:

使用SceneKit创建立方体UI

import UIKit
import SceneKit

class ViewController: UIViewController {

@IBOutlet weak var mySceneView: SCNView!
override func viewDidLoad() {
    super.viewDidLoad()
    mySceneView.allowsCameraControl = true
    //Create instance of scene
    let scene = SCNScene()
    mySceneView.scene = scene
    //Add cube to scnview
    AddCubeToScene()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func AddCubeToScene()
{
    //Create a box of size 0.1 * 0.1 * 0.1
    let myBox = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
    myBox.firstMaterial?.diffuse.contents = UIColor.red
    myBox.firstMaterial?.isDoubleSided = true
    //Create SCnnode of from geometry and specified its position
    let cubeNode = SCNNode(geometry: myBox)
    //Add created scnnode to scene
    mySceneView.scene?.rootNode.addChildNode(cubeNode)
}
}

Create a UIScrollView using UIKit

weak var scrollView: UIScrollView?

override func viewDidLoad() {
super.viewDidLoad()

let scrollView = UIScrollView(frame: CGRect.zero)
scrollView.contentSize = contentSize
scrollView.delegate = self
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 3
scrollView.indicatorStyle = .white
self.scrollView = scrollView

let clearContentView = UIView(frame: CGRect(x: 0, y: 0, width: contentSize.width, height: contentSize.height))
    clearContentView.backgroundColor = UIColor.clear
    scrollView.addSubview(clearContentView)
    self.clearContentView = clearContentView
    clearContentView.addObserver(self, forKeyPath: "transform", options: .new, context: &ViewTransformChangedObservationContext)
    skView.addSubview(scrollView)
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    scrollView?.frame = view.bounds
    scene?.size = view.bounds.size
    if let scrollView = scrollView {
        adjustContent(scrollView: scrollView)
    }
}

func adjustContent(scrollView: UIScrollView) {
    let zoomScale = scrollView.zoomScale
    scene?.setContentScale(scale: zoomScale)
    let contentOffset = scrollView.contentOffset
    let contentSize = scrollView.contentSize
    let scrollAreaHeight: CGFloat = contentSize.height - scrollView.bounds.height
    let yUIKit: CGFloat = contentOffset.y

    // Convert from UIKit coordinates to SpriteKit coordinates
    // UIKit has 0,0 in the top-left corner
    // SpriteKit has 0,0 in the bottom-left corner
    let ySpriteKit = scrollAreaHeight - yUIKit
    let contentOffsetSpriteKit = CGPoint(x: contentOffset.x, y: ySpriteKit)
    scene?.contentOffset = contentOffsetSpriteKit
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    adjustContent(scrollView: scrollView)
}

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
    return clearContentView
}

func scrollViewDidTransform(scrollView: UIScrollView) {
    adjustContent(scrollView: scrollView)
}

// scale between minimum and maximum. called after any 'bounce' animations
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
    adjustContent(scrollView: scrollView)
}

现在将UIScrollView实例添加到立方体的每个面(即,子节点)中。
完成了!

2
你所需要的解决方案可能是一个框架。 你可以看看这些开源项目。 MKCubeControllerCubeControllerGemini
CubeController 是最符合你要求的,你可能需要稍微修改一下。 Gemini 也有魔方实现。

嘿,我认为这一切都与导航有关。我不想浏览它。我正在创建照片编辑应用程序,所以现在你可能明白我想要什么了。 - Khushbu Desai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接