【问题标题】:Pull up and drop UIView with a change in the x position通过改变 x 位置来拉起和放下 UIView
【发布时间】:2017-10-12 00:23:56
【问题描述】:

编辑

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

我想要一个在屏幕中间初始化的 UIView。在那之后,我想向上推它,重力将它拉下来,直到它离开屏幕。我的旧问题适用于 UIPushBehaviour、UIDynamicBehaviour 和 UIGravityBehaviour(见下文)。 Matt 指出 UIPushBehaviour 可能不是正确的选择,因为它不能很好地适用于 iOS 上所有可用的屏幕尺寸。

我可以使用 UIView.animate 函数来做到这一点,但它确实是静态的,看起来不自然。使用 UIPushBehaviour、UIDynamicBehaviour 和 UIGravityBehaviour,它看起来非常不错,但 UIPushBehaviour 的大小无法在每个屏幕尺寸上计算,以给出 UIView 的 x 和 y 位置的相同结束点。

问题

如何在屏幕中间初始化一个 UIView,“拉起”该 UIView(x 位置发生一些变化)并让重力(或其他东西)将其拉下直到它离开屏幕?重要的是 x 和 y 位置的变化在每个屏幕尺寸上都是相同的。

下面是我的老问题

我有一个UIPushBehaviourinstantaneous 作为模式,我在其中推送一些UIViews。屏幕尺寸越大,推动的越少。
我还有一个UIDynamicItemBehaviorresistance 设置为1,我认为这是每个屏幕尺寸不同的主要原因之一(如果我错了,请纠正我)。

我想要一个功能,它将UIView 推送到相同的终点,无论屏幕大小如何,都具有相同的速度、持续时间和终点。

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

对于 iPhone 5S,假设magnitude 中的0.5 会从中间到顶部触摸UIView。我想像这样计算所有设备的大小:

let y = 0.5 / 520 // 5S screen height
magnitude = self.view.frame.height * y

对于 iPhone 8,它具有非常不同的输出并且无法正常工作。在阅读the docs 时,我以为我会理解它。我以为 1 级代表 100 个像素,但显然不是这样。
有什么方法可以计算幅度,例如,将UIView 从中间向右移动?

我制作了a project here。有一个黑色的UIView 在 iPhone 5 上被推到边缘,但在 iPhone 8 上没有。

【问题讨论】:

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

标签: ios swift uipushbehavior


【解决方案1】:

解决方案

您需要相对于屏幕大小缩放推送量,以便您的视图始终在同一个位置结束。为此,调整UIPushBehaviorpushDirection 向量效果很好。在这种情况下,我将推送方向设置为与视图的边界成比例,并将其缩小一个常数因子。

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 将视图的大小视为其质量。如果您的视图需要动态调整大小,则需要根据动画视图的大小缩放常量。

编辑关于原始问题的 cmets:

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

  • iPad 屏幕尺寸:目前pushFactor 应用于向量的dxdy 组件。由于 iPad 具有不同的纵横比,因此您需要将其拆分为两个常量,可能是 xPushFactoryPushFactor,这可以解释纵横比的差异。

示例

iPhone 8

iPhone SE

完整的游乐场源代码

将此代码复制并粘贴到 Swift Playground 中以查看其运行情况。我已经包含了各种 iPhone 屏幕的尺寸,因此只需取消注释您想要在不同设备尺寸上轻松测试动画的尺寸。大多数有趣/相关的代码都在viewDidAppear

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 2013-05-21
    相关资源
    最近更新 更多