简体   繁体   English

通过改变x位置来拉起和放下UIView

[英]Pull up and drop UIView with a change in the x position

Edit 编辑

This is what I want visualised (ignore the ugly red line, it just indicates the movement of the UIView): 这就是我想要的可视化(忽略丑陋的红线,它只是表明UIView的运动):

在此输入图像描述

I want to have a UIView that is initialised in the middle of the screen. 我想要一个在屏幕中间初始化的UIView。 After that, I want to give it a push upwards and the gravity pulls it down till it is off the screen. 在那之后,我想向上推,然后重力将其拉下,直到它离开屏幕。 My old question works with a UIPushBehaviour, UIDynamicBehaviour and a UIGravityBehaviour (see below). 我的老问题适用于UIPushBehaviour,UIDynamicBehaviour和UIGravityBehaviour(见下文)。 Matt pointed out a UIPushBehaviour is maybe not the right choice, since it not work out well across every screen size available on iOS. Matt指出,UIPushBehaviour可能不是正确的选择,因为它在iOS上可用的每个屏幕尺寸上都不能很好地运行。

I can do this with a UIView.animate function, but it is really static and does not look natural. 我可以使用UIView.animate函数执行此操作,但它实际上是静态的,看起来并不自然。 With the UIPushBehaviour, UIDynamicBehaviour and UIGravityBehaviour, it looks really nice but the UIPushBehaviour's magnitude can not be calculated across every screen size to give the same ending point of the UIView's x and y position. 使用UIPushBehaviour,UIDynamicBehaviour和UIGravityBehaviour,看起来非常不错,但无法在每个屏幕尺寸上计算UIPushBehaviour的幅度,以获得UIView的x和y位置的相同终点。

Question

How can I initialise a UIView in the middle of the screen, 'pull up' that UIView (with some change in the x position) and let the gravity (or something else) pulls it down until it is off the screen? 如何在屏幕中间初始化UIView,“拉起”UIView(x位置有一些变化)并让重力(或其他东西)将其拉下直到它离开屏幕? It is important that the change in the x and y position will be the same on every screen size. 重要的是,x和y位置的变化在每个屏幕尺寸上都是相同的。

Below is my old question 以下是我的老问题

I have a UIPushBehaviour with instantaneous as mode in which I push some UIView s around. 我有一个UIPushBehaviour具有instantaneous模式,我可以推动一些UIView The greater the screen size, the less it pushes. 屏幕尺寸越大,推动的越少。
I also have a UIDynamicItemBehavior with resistance set to 1 , I think this is one the main reasons it is different in each screen size (correct me if I am wrong). 我也有一个UIDynamicItemBehaviorresistance设置为1 ,我认为这是每个屏幕尺寸不同的主要原因之一(如果我错了,请纠正我)。

I want a function that will push the UIView to the same ending point, with the same speed, duration and ending point regardless of the screen size. 我想要一个能够将UIView推到相同终点的功能,无论屏幕大小如何,都具有相同的速度,持续时间和终点。

I tried to make a relative magnitude without any luck: 我试图在没有任何运气的情况下做出相对规模:

For the iPhone 5S, let's say a magnitude of 0.5 would touch a UIView from the middle to the top. 对于iPhone 5S,让我们说0.5magnitude会从中间到顶部触及UIView I wanted to calculate the magnitude across all devices like this: 我想计算所有设备的幅度,如下所示:

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

For the iPhone 8, it has a very different output and is not working. 对于iPhone 8,它有一个非常不同的输出,并没有工作。 When reading the docs , I thought I would understand it. 在阅读文档时 ,我想我会理解它。 I thought 1 magnitude represents 100 pixels, but it is clearly not that case. 我认为1幅度代表100像素,但显然不是这种情况。
Is there any way I can calculate a magnitude to, for example, move a UIView from the middle to the right? 有什么方法可以计算出一个幅度,例如,从中间向右移动UIView

I made a project here . 我在这里了一个项目 There is a black UIView that get's pushed to the edges on an iPhone 5, but not on the iPhone 8. 有一个黑色UIView可以在iPhone 5上被推到边缘,但在iPhone 8上没有。

Solution

You need to scale the push amount relative to the size of the screen so your view always ends in the same place. 您需要相对于屏幕大小缩放推送量,以便视图始终在同一位置结束。 To do this, adjusting the UIPushBehavior 's pushDirection vector works quite well. 为此,调整UIPushBehaviorpushDirection向量非常有效。 In this case, I set the push direction to be proportional to the bounds of the view, and scaled it down by a constant factor. 在这种情况下,我将推动方向设置为与视图的边界成比例,并将其按常数因子缩小。

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)

You may need to adjust some constants to get the exact animation you want. 您可能需要调整一些常量以获得所需的精确动画。 The constants you can adjust are: 您可以调整的常量是:

  • Gravity magnitude (currently 0.3) 重力等级(目前为0.3)
  • Push factor (currently 0.01) 推动因子(目前为0.01)

Depending on your needs, you may need to scale the gravity magnitude proportional to the size of the screen as well. 根据您的需要,您可能需要缩放与屏幕大小成比例的重力大小。

Note: These constants will need to change based on the size of your animated view, since UIKit Dynamics treats the size of the view as its mass. 注意:这些常量需要根据动画视图的大小进行更改,因为UIKit Dynamics会将视图的大小视为质量。 If your view needs to be dynamically sized, you will need to scale your constants according to the size of the animated view. 如果您的视图需要动态调整大小,则需要根据动画视图的大小缩放常量。

Edit regarding comments on the original question: 编辑有关原始问题的评论:

  • Views of varying sizes: Like I mentioned in my note above, you'll need to apply an additional factor to account for the "mass" of the views. 不同大小的视图:就像我在上面的注释中提到的那样,您需要应用一个额外的因子来解释视图的“质量”。 Something like view.frame.height * view.frame.width * someConstant should work well. view.frame.height * view.frame.width * someConstant应该运行良好。

  • iPad screen size: Currently the pushFactor is applied to both the dx and dy components of the vector. iPad屏幕尺寸:目前pushFactor应用于矢量的dxdy组件。 Because iPads have a different aspect ratio, you'll need to split this into two constants, maybe xPushFactor and yPushFactor , which can account for the differences in aspect ratio. 由于iPad具有不同的宽高比,因此您需要将其拆分为两个常量,可能是xPushFactoryPushFactor ,它们可以解释宽高比的差异。

Examples 例子

iPhone 8 iPhone 8

iPhone 8屏幕尺寸的解决方案的GIF

iPhone SE iPhone SE

iPhone SE大小的解决方案的GIF

Full Playground Source Code 完整的游乐场源代码

Copy and paste this code into a Swift playground to see it in action. 将此代码复制并粘贴到Swift操场中以查看其运行情况。 I've included the sizes of various iPhone screens, so just uncomment the size you want to easily test the animation on different device sizes. 我已经包含了各种iPhone屏幕的尺寸,因此只需取消注释您希望在不同设备尺寸上轻松测试动画的尺寸。 Most of the interesting/relevant code is in viewDidAppear . 大多数有趣/相关的代码都在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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM