讲解iOS开发中拖动视图的实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了讲解iOS开发中拖动视图的实现相关的知识,希望对你有一定的参考价值。

参考技术A

   预备知识

  ios处理屏幕上的触摸动作,主要涉及到以下几个方法:

   复制代码 代码如下:

  touchesBegan:withEvent: //触摸屏幕的最开始被调用

  touchesMoved:withEvent: //移动过程中被调用

  touchesEnded:withEvent: //动作结束时被调用

  touchesCancelled:WithEvent:

  从方法的命名可以清晰的看出该方法何时被调用,最后一个比较特殊。touchesCancelled:WithEvent:在Cocoa Touch必须响应持续触摸事件的系统中断时调用。

  我们只要重写这些方法,来作我们想要作的`事情就可以了。

   如何实现拖动视图?

  1.设置userInteractionEnabled属性为YES,允许用户交互。

  2.在触摸动作开始时记录起始点。

  3.在移动过程中,计算当前位置坐标与起始点的差值,即偏移量,并且移动视图中心点至偏移量大小的地方。

  4.分别限制x坐标、与y坐标,保证用户不可将视图托出屏幕

  备注:分别限制x坐标与y坐标的原因是,即使向右拖动不了了,仍需保证可以向下拖动。

  其实,功能比较简单,就是iOS手势动画中的拖动。来看一下基本的写法:

   1.注册拖动动画

  复制代码 代码如下:

  UIPanGestureRecognizer * panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self

  action:@selector(doHandlePanAction:)];

  [self.vLight addGestureRecognizer:panGestureRecognizer];

  注:vLight就是要加入拖动的View子类。

   2.拖动处理函数

  复制代码 代码如下:

  - (void) doHandlePanAction:(UIPanGestureRecognizer *)paramSender

  CGPoint point = [paramSender translationInView:self.view];

  NSLog(@"X:%f;Y:%f",point.x,point.y);

  paramSender.view.center = CGPointMake(paramSender.view.center.x + point.x, paramSender.view.center.y + point.y);

  [paramSender setTranslation:CGPointMake(0, 0) inView:self.view];

  

  实现代码

  以子类化UIImageView为例

  复制代码 代码如下:

  #import

  @interface GragView : UIImageView

  

  CGPoint startPoint;

  

  @end

  #import "GragView.h"

  @implementation GragView

  - (id)initWithFrame:(CGRect)frame

  

  self = [super initWithFrame:frame];

  if (self)

  // Initialization code

  //允许用户交互

  self.userInteractionEnabled = YES;

  

  return self;

  

  - (id)initWithImage:(UIImage *)image

  

  self = [super initWithImage:image];

  if (self)

  //允许用户交互

  self.userInteractionEnabled = YES;

  

  return self;

  

  - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

  

  //保存触摸起始点位置

  CGPoint point = [[touches anyObject] locationInView:self];

  startPoint = point;

  //该view置于最前

  [[self superview] bringSubviewToFront:self];

  

  -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

  

  //计算位移=当前位置-起始位置

  CGPoint point = [[touches anyObject] locationInView:self];

  float dx = point.x - startPoint.x;

  float dy = point.y - startPoint.y;

  //计算移动后的view中心点

  CGPoint newcenter = CGPointMake(self.center.x + dx, self.center.y + dy);

  /* 限制用户不可将视图托出屏幕 */

  float halfx = CGRectGetMidX(self.bounds);

  //x坐标左边界

  newcenter.x = MAX(halfx, newcenter.x);

  //x坐标右边界

  newcenter.x = MIN(self.superview.bounds.size.width - halfx, newcenter.x);

  //y坐标同理

  float halfy = CGRectGetMidY(self.bounds);

  newcenter.y = MAX(halfy, newcenter.y);

  newcenter.y = MIN(self.superview.bounds.size.height - halfy, newcenter.y);

  //移动view

  self.center = newcenter;

  

  /*

  // Only override drawRect: if you perform custom drawing.

  // An empty implementation adversely affects performance during animation.

  - (void)drawRect:(CGRect)rect

  

  // Drawing code

  

  */

  @end

Swift 中类似控制中心的滑动视图实现

【中文标题】Swift 中类似控制中心的滑动视图实现【英文标题】:Control Center-like sliding view implementation in Swift 【发布时间】:2016-10-05 13:28:24 【问题描述】:

我正在尝试在 App 上创建交互式滑动过渡。

目标是当视图控制器从底部拖动时呈现一个 uiview(而不是从底部边缘,因此它不会与控制中心冲突)并将部分覆盖主视图控制器(就像 iOS控制中心)。过渡应该是交互式的,即根据用户的拖动。

很高兴听到有关可用 API 的想法。

【问题讨论】:

我之前做过这个,我没有密码,但是如果你仍然没有答案,我可以在我回家时将它发送给你。 感谢@JacobKing 的快速回复,我正在等待您的答复。 @JacobKing 能否分享一下代码 @user6520705 我不再为该公司工作,所以我无法访问他们的源代码控制存储库......我可能有一个旧的本地副本,但我怀疑它,会看看什么时候我有机会。 【参考方案1】:

以下代码将执行在 Xcode 8 中测试并工作的简单 slideView 动画代码..

 import UIKit

class ViewController: UIViewController,UIGestureRecognizerDelegate 

// I am using VisualView as a slideView
@IBOutlet weak var slideView: UIVisualEffectView!

//Button to open slideView
@IBOutlet weak var button: UIBarButtonItem!

override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // setting background for sideView
       slideView.backgroundColor = UIColor(patternImage: UIImage(named: "original.jpg")!)

    //Initial hide so it won't show.when the mainView loads...
      slideView.isHidden = true

    // DownSwipe to hide slideView
       let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(_:)))
       downSwipe.direction = .down
       view.addGestureRecognizer(downSwipe)
    

   // set UIButton to open slideVie...(I am using UIBarButton)
     @IBAction func sdrawButton(_ sender: AnyObject) 

      self.slideView.isHidden = false
      slideView.center.y += view.frame.height

      UIView.animate(withDuration: 0.7, delay: 0, options: UIViewAnimationOptions.curveEaseIn, animations:
        self.slideView.center.y -= self.view.frame.height
        self.button.isEnabled = false
        , completion: nil)  


   func handleSwipes(_ sender:UISwipeGestureRecognizer) 
    if (sender.direction == .down) 
        print("Swipe Down")

        self.slideView.isHidden = true

        self.slideView.center.y -= self.view.frame.height
        UIView.animate(withDuration: 0.7, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations:
            self.slideView.center.y += self.view.frame.height
            self.button.isEnabled = true
            , completion: nil)
    
  
  

让我知道代码对你有用...

【讨论】:

【参考方案2】:

对不起,如果这个问题有点老了。 您可以继承 UIView 并覆盖 touchesBegan(_ , with) 以保存原始触摸位置

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
  guard let  touch = touches.first else  print("No touch"); return 
      startPoint = touch.location(in: self)
      startHeight = heightConstraint.constant
      slideDirection = .none
      super.touchesBegan(touches, with: event)
   

和 touchesMoved(_,with) 在手指滑动视图时更新高度约束。

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
  guard let touch = touches.first else  print("touchesMovedno touches"); return 

  let endPoint = touch.location(in: self)
  let diff = endPoint.y - startPoint.y

  // This causes the view to move along the drag
  switch anchorLocation 
  case .top :
     heightConstraint.constant = startHeight + diff
  case .bottom :
     heightConstraint.constant = startHeight - diff
  
  self.layoutIfNeeded()

  // Update direction
  if diff == 0.0 
     self.slideDirection = .none
   else 
     self.slideDirection = (diff > 0) ? .down : .up
  
  super.touchesMoved(touches, with: event) 

如果您愿意,可以覆盖 touchesEnded(_, with) 以添加动画

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) 

  self.modifyHeightConstraints()
  self.animateViewTransition(duration: animDuration, delay: animDelay, clearance: animClearance, springDampingRatio: animSpringDampingRatio, initialSpringVelocity: animInitialSpringVelocity, complete: 
     self.slideDirection = .none
  )
  super.touchesEnded(touches, with: event)

我创建了一个组件,它可能具有您想要的确切功能。该组件包括可调整的动画弹跳。您可以在情节提要中的视图上布局和设计子视图。

查看 GitHub 中的链接

https://github.com/narumolp/NMPAnchorOverlayView

【讨论】:

以上是关于讲解iOS开发中拖动视图的实现的主要内容,如果未能解决你的问题,请参考以下文章

通知模式实现两个textField传值及模态视图——iOS开发

iOS开发 - 啰嗦讲解 Runloop

iOS 11开发教程(二十二)iOS11应用视图实现按钮的响应

iOS开发 Masonry的简单使用

ios开发(表视图)

游戏开发教程Unity iOS平台接入微信SDK,实现微信登录等功能(教程 | 流程讲解)