Swift中

时间:2016-02-26 10:11:27

标签: ios swift uiview uiscrollview

问题很简单,与在scrollView中使用平移手势有关。

  1. 我有一个画布(这是一个UIView本身但尺寸更大),我正在绘制一些UIView对象,并在每个对象上启用平移手势(我正在谈论的每个小UIView对象,正在使用另一个UIView类)。

  2. 现在画布的高度和宽度可以更大......可以根据用户输入进行更改。

  3. 为了实现这一点,我已将画布放在UIScrollView中。现在画布平稳地增加或减少。

  4. 画布上的那些小UIView对象也可以旋转。

  5. 现在问题。

    1. 如果我没有更改画布大小(静态),即如果它不在scrollview中,那么画布内的每个UIView对象都会移动得非常好,并且所有内容都可以正常使用以下代码。

      < / LI>
    2. 如果画布在UIScrollView中,那么画布可以滚动吗?现在在scrollview中,如果我在画布上平移UIView对象,那么当触摸在画布上移动时,那些小UIView对象不会跟随手指触摸而不是移动到另一个点。

    3. N.B。 - 不知怎的,我发现我需要在任何子视图触摸时禁用滚动视图的滚动。为此,我已经实现了NSNotificationCenter将信号传递给父viewController。

      以下是代码。

      此函数在父viewController类

      中定义
      func canvusScrollDisable(){
          print("Scrolling Off")
          self.scrollViewForCanvus.scrollEnabled = false
      }
      func canvusScrollEnable(){
          print("Scrolling On")
          self.scrollViewForCanvus.scrollEnabled = true
      }
      
      override func viewDidLoad() {
          super.viewDidLoad()
          notificationUpdate.addObserver(self, selector: "canvusScrollEnable", name: "EnableScroll", object: nil)
          notificationUpdate.addObserver(self, selector: "canvusScrollDisable", name: "DisableScroll", object: nil)
       }
      

      这是画布的Subview类

      import UIKit
      
      class ViewClassForUIView: UIView {
      let notification: NSNotificationCenter = NSNotificationCenter.defaultCenter()
      
      var lastLocation: CGPoint = CGPointMake(0, 0)
      var lastOrigin = CGPoint()
      var myFrame = CGRect()
      var location = CGPoint(x: 0, y: 0)
      var degreeOfThisView = CGFloat()
      override init(frame: CGRect){
          super.init(frame: frame)
      
          let panRecognizer = UIPanGestureRecognizer(target: self, action: "detectPan:")
          self.backgroundColor = addTableUpperViewBtnColor
          self.multipleTouchEnabled = false
          self.exclusiveTouch = true
      }
      
      required init?(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
      
      func detectPan(recognizer: UIPanGestureRecognizer){
          let translation = recognizer.translationInView(self.superview!)
          self.center = CGPointMake(lastLocation.x + translation.x, lastLocation.y + translation.y)
          switch(recognizer.state){
          case .Began:
          break
          case .Changed:
          break
          case .Ended:
              notification.postNotificationName("EnableScroll", object: nil)
          default: break
          }
      }
      
      override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
          notification.postNotificationName("DisableScroll", object: nil) 
          self.superview?.bringSubviewToFront(self)
          lastLocation = self.center
          lastOrigin = self.frame.origin
          let radians:Double = atan2( Double(self.transform.b), Double(self.transform.a))
          self.degreeOfThisView = CGFloat(radians) * (CGFloat(180) / CGFloat(M_PI) )
          if self.degreeOfThisView != 0.0{
              self.transform = CGAffineTransformIdentity
              self.lastOrigin = self.frame.origin
              self.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))            
          }
          myFrame = self.frame
        }
      
      override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
          notification.postNotificationName("EnableScroll", object: nil)
        }
         }
      

      现在,只要其中一个UIView对象正在滚动视图内的画布上接触触摸,但有时那些UIView对象没有正确地跟踪画布/屏幕上的触摸位置,scrollView就会完全禁用其滚动。

      我正在使用Swift 2.1和Xcode 7,但任何人都可以告诉我我的遗漏或使用Objective-c / Swift的解决方案?

1 个答案:

答案 0 :(得分:1)

您在哪里设置lastLocation?我认为最好使用locationInView并自己计算翻译。然后在触发该方法的每个事件上保存lastLocation

此外,您可能还想处理取消状态以重新打开滚动。

所有这些看起来确实有些混乱。通知可能不是您的最佳选择,也不是将手势识别器放在子视图上。我认为你应该有一个处理所有这些小视图的视图;它还应该有一个手势识别器,可以同时与其他识别器进行交互。当识别出手势时,它应该检查是否有任何子视图被击中并决定是否应该移动它们中的任何一个。如果应该移动,则使用委托报告必须禁用滚动。如果没有,则取消识别器(禁用+启用)。此外,在滚动视图中放置可移动内容的大多数情况下,您通常需要长按手势识别器而不是平移手势识别器。只需使用那个并设置一些非常小的最小印刷持续时间。请注意,此手势与平移手势完全相同,但可以检测到较小的延迟。它在这种情况下非常有用。

更新(架构):

层次结构应为:

查看控制器 - &gt; Scrollview - &gt;画布视图 - &gt;小视图

画布视图应包含控制小视图的手势识别器。当手势开始时,您应该通过简单地遍历子视图并检查其框架是否包含一个点来检查是否有任何视图被其位置命中。如果是这样,它应该开始移动命中小视图,它应该通知它的代表它已经开始移动它。如果不是,它应该取消手势识别器。

由于canvas视图具有自定义委托,因此视图控制器应实现其协议并将其自身作为委托分配给画布视图。当画布视图报告视图拖动已开始时,它应禁用滚动视图滚动。当画布视图报告它已停止移动视图时,它应该重新启用滚动视图的滚动。

  • 创建此类视图层次结构
  • 创建画布视图的自定义协议,其中包含&#34;确实开始拖动&#34;和#34;确实结束了拖拽&#34;
  • 当视图控制器变为活动状态时,将self指定为画布视图的委托。实现2个方法以启用或禁用滚动视图的滚动。
  • 画布视图应该为自身添加手势识别器,并且应该包含所有小型可移动子视图的数组。识别器应该能够同时与其他识别器进行交互,这是通过其代表完成的。
  • Canvas手势识别器目标应该在开始检查是否有任何小视图被击中并将其保存为属性时,它还应该保存手势的当前位置。当手势改变时,它应根据最后和当前手势位置移动抓取的视图,并将当前位置重新保存到属性。当手势结束时,它应该清除当前拖动的视图。在开始和结束时,它应该调用委托来通知状态的变化。
  • 根据要委派的画布视图,禁用或启用视图控制器中的滚动。

我认为这应该是全部。