如何在 NSObject 类中添加动态行为:Swift

Posted

技术标签:

【中文标题】如何在 NSObject 类中添加动态行为:Swift【英文标题】:How do i add dynamic behaviour in NSObject class : Swift 【发布时间】:2016-05-04 06:39:57 【问题描述】:

我正在尝试使用 swift 在 NSObject 类中使用 UIDynamicAnimator 创建具有动态行为的自定义警报视图,而将 UISnapBehaviour 添加到 NSObject 类 init 方法中的视图捕捉行为不起作用,例如查看下面的代码

import UIKit

class DynamicBehaviour: NSObject 

var Animator:UIDynamicAnimator!
var TargetView:UIView!
var TestView:UIView!

override init() 
    super.init()


init(SourceViews:UIView) 
    super.init()

    TestView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    TestView.backgroundColor = UIColor.blueColor()
    TargetView.addSubview(TestView)

    Animator = UIDynamicAnimator(referenceView: TargetView)
    let snapBehavior: UISnapBehavior = UISnapBehavior(item: TestView, snapToPoint: TargetView.center)
    Animator.addBehavior(snapBehavior)

  

“TestView”作为子视图添加到“Target”,但捕捉行为不起作用。

我在 ObjectiveC 中尝试了相同的代码

#import "DynamicBehaviour.h"
#import <UIKit/UIKit.h>

@interface DynamicBehaviour ()
@property(nonatomic,strong)UISnapBehavior * Snap_behaviour;
@property (nonatomic,strong)UIDynamicAnimator * Animator;


@end
@implementation DynamicBehaviour

-(instancetype)initWithSourceView:(UIView *)TargetView
   if (self = [super init]) 
      UIView * TestView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100,     100)];
      TestView.backgroundColor = [UIColor blueColor];
      [TargetView addSubview:TestView];

      self.Animator = [[UIDynamicAnimator    alloc]initWithReferenceView:TargetView];
       self.Snap_behaviour = [[UISnapBehavior alloc]initWithItem:TestView snapToPoint:TargetView.center];
       [self.Animator addBehavior:self.Snap_behaviour];
   
  return self;
  


 @end

它工作正常,“TestView”捕捉到 TargetView 的中心。我不知道 swift 代码有什么问题。

这是我尝试过的:

    在 UIViewController 类中编码时动态效果工作正常,问题仅在 swift 中子类化 NSObject 时存在。 我已经尝试过其他动态行为,例如 UIGravityBehavior,Swift 中也存在同样的问题。 在 ObjectiveC 对象类中完成了相同的示例工作,它工作正常,我也附上了工作的 ObjC 代码。

似乎问题可能存在于 init 方法或变量 decleration 不确定 但是,我不知道如何解决这个问题。我已经阅读了互联网上的许多文章。我也搜索过 ***。请帮忙。

【问题讨论】:

【参考方案1】:

您在 Swift 中的代码与 Objective-C 代码并不完全相同:Objective-C 代码具有强引用 Snap_behaviour,但 Swift 代码只有本地只读变量。 这是 Swift 的等价物:

class DynamicBehaviour: NSObject 

    var Animator:UIDynamicAnimator!
    var snapBehaviour:UISnapBehavior!
    var TargetView:UIView!
    var TestView:UIView!

    override init() 
        super.init()
    

    init(SourceViews:UIView) 
        super.init()

        TestView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        TestView.backgroundColor = UIColor.blueColor()
        TargetView.addSubview(TestView)

        Animator = UIDynamicAnimator(referenceView: TargetView)
        snapBehaviour = UISnapBehavior(item: TestView, snapToPoint: TargetView.center)
        Animator.addBehavior(snapBehaviour)

    

通常我使用 UIDynamicBehaviour 作为这样的组合行为的基类

class CombinedBehavior: UIDynamicBehavior 

    lazy var collider: UICollisionBehavior = 
        let lazilyCreatedCollider = UICollisionBehavior()
        lazilyCreatedCollider.translatesReferenceBoundsIntoBoundary = true
        lazilyCreatedCollider.collisionMode = UICollisionBehaviorMode.Everything
        return lazilyCreatedCollider
    ()

    lazy var itemBehavior: UIDynamicItemBehavior = 
        let lazilyCreatedBehavior = UIDynamicItemBehavior()
        lazilyCreatedBehavior.allowsRotation = true
        lazilyCreatedBehavior.elasticity = 0
        lazilyCreatedBehavior.resistance = 100
        lazilyCreatedBehavior.angularResistance = 100
        lazilyCreatedBehavior.friction = 100
        return lazilyCreatedBehavior
    ()

    override init() 
        super.init()
        addChildBehavior(collider)
        addChildBehavior(itemBehavior)
    

    func addBarrier(path: UIBezierPath, named name: String) 
        collider.removeBoundaryWithIdentifier(name)
        collider.addBoundaryWithIdentifier(name, forPath: path)
    

    func addView(view: UIView) 
        dynamicAnimator?.referenceView?.addSubview(view)
        collider.addItem(view)
        itemBehavior.addItem(view)
    

    func removeView(view: UIView) 
        collider.removeItem(view)
        itemBehavior.removeItem(view)
        view.removeFromSuperview()
    

将此代码放入您的控制器中

lazy var animator: UIDynamicAnimator = 
    let lazilyCreatedDynamicAnimator = UIDynamicAnimator(referenceView: self.view) // or any view you needed
    // if you need delegate in your controller uncomment this
    //        lazilyCreatedDynamicAnimator.delegate = self
    return lazilyCreatedDynamicAnimator
()

var combinedBehavior = CombinedBehavior()

override func viewDidLoad() 
    // your other code
    animator.addBehavior(combinedBehavior)

【讨论】:

感谢 Andriy 的回复,现在我已经强烈声明“Snap_behaviour”,但我仍然无法对我的代码产生动态影响。那么您推荐的代码运行完美。我有将 UIGravityBehaviour 添加到您的“CombinedBehavior”类中,它工作正常。当我尝试添加 UISnapBehaviour 时,它会引发运行时错误 init is undefined for objects of type UISnapBehavior 。你能帮我解决吗? var snap: UISnapBehavior? willSet if snap != nil animator.removeBehavior(snap!) didSet if snap != nil animator.addBehavior(snap!) // 把这个放在你需要捕捉的地方,通常在 UILongPressGestureRecognazier 中: snap = UISnapBehavior(item: selectedDrop!, snapToPoint: point) // 完成后删除 snap: snap = nil

以上是关于如何在 NSObject 类中添加动态行为:Swift的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中单击 NSObject 内部的 tableView 中的项目时,如何在 NSObject 类中的 UIViewController 上的 UIView 之间正确切换?

iOS9如何调用NSObject类中的UIAlertviewController?

如何在 Swift 4 的 NSObject 类中初始化 json 内的数组?

在 NSObject 类中设置协议并在 UIViewController 类中调用它们

objective-c 中如何在一个函数中调用自己类中的另外一个函数

NSObject 类中的委托