Ios 上拉并放下UIView,改变x位置

Ios 上拉并放下UIView,改变x位置,ios,swift,uipushbehavior,Ios,Swift,Uipushbehavior,编辑 这就是我想要可视化的内容(忽略丑陋的红线,它只是指示UIView的移动): 我希望在屏幕中间有一个初始化的UIVIEW。在那之后,我想向上推它,重力把它拉下来,直到它离开屏幕。我的老问题适用于UIPushBehavior、UIDynamicBehaviour和UIGravityBehaviour(见下文)。马特指出,一个新的行为可能不是正确的选择,因为它不适合iOS上所有可用的屏幕大小 我可以使用UIView.animate函数来实现这一点,但它实际上是静态的,看起来不自然。使用UIPu

编辑

这就是我想要可视化的内容(忽略丑陋的红线,它只是指示UIView的移动):

我希望在屏幕中间有一个初始化的UIVIEW。在那之后,我想向上推它,重力把它拉下来,直到它离开屏幕。我的老问题适用于UIPushBehavior、UIDynamicBehaviour和UIGravityBehaviour(见下文)。马特指出,一个新的行为可能不是正确的选择,因为它不适合iOS上所有可用的屏幕大小

我可以使用UIView.animate函数来实现这一点,但它实际上是静态的,看起来不自然。使用UIPushBehavior、UIDynamicBehaviour和UIGravityBehaviour,它看起来真的很不错,但是UIPushBehavior的大小不能在每个屏幕大小上计算,以给出UIView的x和y位置的相同终点

问题:

我如何在屏幕中间初始化UIVIEW“UpVIEW”(X位置的一些改变),让重力(或其他东西)把它拉下来,直到它脱离屏幕?重要的是,x和y位置的变化在每个屏幕尺寸上都是相同的

下面是我的老问题

我有一个
uipushbehavior
instantial
作为模式,在该模式下,我推送一些
UIView
s。屏幕尺寸越大,推动的力度越小。
我还有一个
uidynamictembehavior
,将
电阻设置为
1
,我认为这是每个屏幕大小不同的主要原因之一(如果我错了,请纠正我)

我想要一个功能,它可以将
ui视图
推到相同的结束点,速度、持续时间和结束点与屏幕大小无关

我试图在没有任何运气的情况下得出一个相对大小:

对于iphone5s,假设
0.5
magnity
会从中间到顶部触及
UIView
。我想计算所有设备的大小,如下所示:

let y = 0.5 / 520 // 5S screen height
magnitude = self.view.frame.height * y
对于iPhone8,它的输出非常不同,无法工作。当我阅读的时候,我想我会理解的。我认为1个大小代表100个像素,但显然不是这样。
是否有任何方法可以计算震级,例如,将
ui视图
从中间向右移动

我做了。iPhone 5上有一个黑色的
UIView
,但iPhone 8上没有。

解决方案 您需要相对于屏幕大小缩放推送量,以便视图始终在同一位置结束。为此,调整
UIPushBehavior
pushDirection
向量非常有效。在本例中,我将推动方向设置为与视图的边界成比例,并按常量因子将其缩小

let push = UIPushBehavior(items: [pushView], mode: .instantaneous)
let pushFactor: CGFloat = 0.01
push.pushDirection = CGVector(dx: -view.bounds.width * pushFactor, dy: -view.bounds.height * pushFactor)
animator.addBehavior(push)
您可能需要调整一些常量以获得所需的精确动画。可以调整的常数包括:

  • 重力震级(目前为0.3)
  • 推力系数(目前为0.01)
根据您的需要,您可能还需要根据屏幕大小按比例缩放重力大小

注意:这些常量需要根据动画视图的大小进行更改,因为UIKit Dynamics将视图的大小视为其质量。如果视图需要动态调整大小,则需要根据动画视图的大小缩放常量

编辑关于原始问题的评论:

  • 不同大小的视图:正如我在上面的注释中提到的,您需要应用一个额外的因子来解释视图的“质量”。类似于
    view.frame.height*view.frame.width*someConstant
    的东西应该可以正常工作

  • iPad屏幕大小:目前,
    pushFactor
    应用于向量的
    dx
    dy
    组件。由于iPad具有不同的纵横比,您需要将其拆分为两个常量,可能是
    xPushFactor
    yPushFactor
    ,这可以解释纵横比的差异

例子 iPhone8

iPhone SE

完整的源代码 将此代码复制并粘贴到Swift游乐场中,以查看其运行情况。我已经包括了各种iPhone屏幕的大小,所以只需取消注释您想要在不同大小的设备上轻松测试动画的大小。大多数有趣/相关的代码都在
viewdide

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let pushView = UIView()
    var animator: UIDynamicAnimator!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.frame = CGRect(x: 0, y: 0, width: 568, height: 320) // iPhone SE
//        view.frame = CGRect(x: 0, y: 0, width: 667, height: 375) // iPhone 8
//        view.frame = CGRect(x: 0, y: 0, width: 736, height: 414) // iPhone 8+
//        view.frame = CGRect(x: 0, y: 0, width: 812, height: 375) // iPhone X

        view.backgroundColor = .white
        let pushViewSize = CGSize(width: 200, height: 150)
        pushView.frame = CGRect(x: view.bounds.midX - pushViewSize.width / 2, y: view.bounds.midY - pushViewSize.height / 2, width: pushViewSize.width, height: pushViewSize.height)
        pushView.backgroundColor = .red
        view.addSubview(pushView)

        animator = UIDynamicAnimator(referenceView: self.view)
        let dynamic = UIDynamicItemBehavior()
        dynamic.resistance = 1
        animator.addBehavior(dynamic)

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let gravity = UIGravityBehavior(items: [pushView])
        gravity.magnitude = 0.3
        animator.addBehavior(gravity)

        let push = UIPushBehavior(items: [pushView], mode: .instantaneous)
        let pushFactor: CGFloat = 0.01
        push.pushDirection = CGVector(dx: -view.bounds.width * pushFactor, dy: -view.bounds.height * pushFactor)
        animator.addBehavior(push)

    }

}

let vc = ViewController()
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = vc.view

推行为不会推到某个地方;它推动了一定的量。不管这是什么样的iPhone,你都在保持同样的距离,这才是最重要的。如果这不是你想要的,那么你选择了错误的行为。@matt O我不知道,但是这个数量不能与屏幕大小相关吗?我只想推一个UIView,给它增加一些重力。我从这个问题中得到了推送行为:。使用UIView.animate函数更改原点时,重力仅在动画之后应用,这不是我想要的。UIBezierPath看起来很麻烦,因为UIView可以在任何地方设置动画,我需要创建很多UIBezierPath。什么样的方法才是正确的,让一个有重力推动的UIView?你想要的最终结果是什么?可能有一个更简单的解决方案。为什么不使用字段将视图拉到位?不清楚你想做什么(因为你没有解释)。就目前而言,这是一个x-y问题:你对如何实现一个目标做出了错误的假设,现在你希望它能变成一个真实的假设。相反,告诉我们目标是什么。@nathan好的,谢谢你,我明天会看一看:)现在不要把这个项目和我在一起