ios拖拽手势,iphone五指手势怎么操作
免责声明(必读!):本博客提供的所有教程翻译稿件均来自互联网,仅供学习交流。不要在商业上传播它们。同时,转载时不要删除此声明。如果出现任何争议,与本博客的所有者或发布翻译的人无关。谢谢您的合作!
original:3358 www . raywenderlich . com/6567/uigesturecognizer-tutorial-in-IOs-5-pinches-pan-and-more
5 iOS手势识别教程:双指拨号、拖动和更多手势
制造iniTyran,由Benna提供动力,查看
由艾文,紫龙山人。
如果您需要在应用程序中检测手势,比如点击、挤压、平移和旋转,那么通过创建UIGestureRecognizer类就可以非常简单地做到这一点。
在本教程中,我们将向您展示如何通过简单的编程在您的应用程序中添加手势识别,同时使用IOS 5中的故事板编辑器。
我们将创建一个简单的应用程序,在其中您可以使用手势识别器通过拖动、旋转和旋转来移动猴子和香蕉。
我们还将展示一些很酷的东西,如下所示:
添加减速动作设置手势识别器依赖于添加自定义UIGestureRecognizer,这样就可以逗猴子了!J
本教程要求你熟悉IOS 5中ARC和故事板的基本概念。如果你是这些概念的新手,你可以先阅读我们的ARC和故事板教程。
我想那只猴子刚刚对我们竖起了大拇指,所以我们现在就开始吧!J
入门指南
打开Xcode,新建一个项目,点击文件-新建-新建项目,选择IOS-应用下的单视图应用应用模板。将项目命名为“MonkeyPinch”,选择iPhone by Device Family,勾选下面的“使用故事板”和“使用自动引用计数”选择框。
首先,下载这个项目的资源,并将这4个文件添加到您的项目中。如果你对此感到好奇,本教程中的所有图片都来自我可爱老婆的免费游戏素材包。我们还用麦克风制作了音效材料。P
接下来,打开MainStoryboard.storyboard并将图像视图拖到视图控制器。将图像设置为monkey_1.png,并通过Editor- Size调整图像视图大小以适应内容。然后将第二个图像视图拖动到视图控制器中,将图像设置为object_banababunch.png,并调整大小。将这两个图像视图随机放置在视图控制器中,您将看到下图:
这是这个应用程序的用户界面,现在让我们添加手势识别器来拖动这些图像视图!
UIGestureRecognizer概述
在我们开始之前,让我们给你一个简要的概述来说明如何使用UIGestureRecognizers以及为什么它们非常容易使用。
在过去没有UIGestureRecognizers的日子里,如果你想检测一个手势,如滑动,你必须在UIView中注册每个触摸的通知,如触摸开始、触摸移动和触摸结束。每个程序员都检测到touch的写法略有不同,会导致应用出现奇怪的bug和不一致。
在IOS 3.0中,苹果使用了新的UIGestureRecognizer类来解决这个问题!它提供了基本手势的默认实现(点击、用两个手指捏、旋转、滑动、拖移、长按)。使用它们后,不仅为您节省了大量代码,还能让您的应用程序更正确地工作!
使用UIGestureRecognizers非常简单。您只需完成以下步骤:
创建手势识别器。当您创建手势识别器时,您需要指定一个回调函数,以便当手势开始、更改和结束时,手势识别器可以发送您的更新。将手势识别器添加到视图中。每个手势识别器需要与一个(且只有一个)视图连接。当在视图边界内发生触摸时,手势识别器将检查触摸事件是否符合手势的预定义类型,如果符合,它将调用回调函数。
您可以以编程方式完成这两个步骤(我们将在本教程的后面解释),但是在故事板编辑器中直观地添加手势识别器更容易。然后,让我们看看它是如何工作的,并将我们的第一个手势识别器添加到这个项目中。
拖动手势
或者打开MainStoryboard.storyboard,在对象库中找到平移手势识别器,拖动到猴子图像视图。这样就创建了表盘手势识别器,它链接了猴子图像视图。如果要确认手势识别器和视图是否连接,可以单击monkey image视图,检查连接检查器,并确保平移手势识别器在gestureRecognizers集合中:
您可能想知道为什么我们将识别器与这个图像视图而不是整个视图相关联。两种方式都可以,但是上面的方法更适合你的项目。当我们把识别器和猴子关联起来,就可以知道猴子边界内的任何触摸事件,这样就可以很好的处理了。这种方法的缺点是,有时您可能希望将接触延伸到边界之外。在这种情况下,您可以将手势识别器添加到整个视图中,但您必须编写更多代码来确认用户触摸了猴子或香蕉边界,然后进行相应的处理。
既然我们已经创建了平移(切换)手势识别器并将其关联到图像视图,我们只需要编写回调函数,以便在发生双指切换时可以做一些实际的事情。
打开ViewCotroller.h并添加以下语句:
-(I action)handle pan:(UIPanGestureRecognizer *)识别器;
然后在ViewController.m中实现如下:
-(I action)handle pan:(UIPanGestureRecognizer *)识别器{
CG point translation=[recognizer translation view:self . view];
recognizer . view . center=CGPointMake(recognizer . view . center . x translation . x,recognizer . view . center . y translation . y);
[recognizer set translation:CGPointMake(0,0)in view:self . view];
}
复制代码
当第一次检测到平移手势时,UIPanGestureRecognizer会调用这个方法,然后这个方法会在用户不断拨号时继续,直到最后一次拨号完成(通常是用户举起手指)。
UIPanGestureRecognizer将其自身作为参数传递给此方法。您可以检索用户移动手指调用的translationInView方法的数量值。这里,我们用手指拖动的量来移动猴子图像的中心。
注意,一旦完成以上动作,将平移复位到0是非常重要的。不然每次都会叠加翻译,很快你的猴子就撤屏了!
注意,与通过硬编码将猴子图像视图直接写入该方法相比,我们在调用recognizer.view时获得了一个猴子图像视图的关联,这可以使我们的代码更具通用性,所以我们将在下一个香蕉图像视图中再次使用该方法。
好了,现在这个方法已经完成了,让我们把它和UIPanGestureRecognizer关联起来。在界面构建器中选择UIPanGestureRecognizer,打开连接检查器,并从选择器中拖动一条线以查看控制器。将出现一个弹出框,选择手柄。此时,平移手势识别器的连接检查器应该如下所示:
编译并尝试拖动猴子。等等,它还是不动。
之所以不动,是因为通常视图不接受触摸,默认触摸无法使用,就像图像视图一样。因此,选择所有图像视图,打开属性检查器,并选中“启用用户交互”。
编译再运行,这次可以拖动屏幕上的猴子了!
小心不能拖香蕉。这是因为手势识别器连接到一个(仅一个)视图。所以继续为香蕉添加另一个视图。实施步骤如下:
将平移手势识别器拖到香蕉图像视图上。选择一个新的平移手势识别器,选择“连接”检查器,将一条线从选择器拖到视图控制器,并将其连接到手柄。
现在试一下,你应该能够拖动这两个图像在屏幕上查看。一个相当简单的实现就可以获得如此酷而有趣的效果。
无端减速
在大多数苹果应用和控件中,当你停止移动某个东西时,它会在结束移动时稍微慢下来,比如滚动网页视图。在应用程序中想要这种行为是很常见的。
有很多种方法可以做到这一点,我们就用很简单的方法来做,看起来粗糙但实际效果很美。这个想法是计算当我们检测到手势结束时触摸移动的速度,并根据触摸的速度将对象动画化到最终目的地。
手势检测结束:当手势识别器将状态更改为开始、更改或结束时,传递给手势识别器的回调可能会被多次调用。通过查看手势识别器的状态属性,我们可以简单地知道它处于什么状态。检测触摸速度:一些手势识别器返回一个额外的消息——。看看API向导就知道能得到什么了。在UIPanGestureRecognizer的使用中,有一个非常方便的方法叫做velocityInView!
将以下代码添加到handlePan方法的末尾:
if(recognizer . state==UIGestureRecognizerStateEnded){
CG point velocity=[recognizer velocity inview:self . view];
CGFloat星等=sqrtf((velocity . x * velocity . x)(velocity . y * velocity . y));
CGFloat slideMult=星等/200;
NSLog(@magnitude: %f,slideMult: %f ,magnitude,slide mult);
float slide factor=0.1 * slide mult;//增加更多的幻灯片
CG point final point=CGPointMake(recognizer . view . center . x(velocity . x * slide factor),
recognizer . view . center . y(velocity . y * slide factor));
final point . x=MIN(MAX(final point . x,0),self . view . bounds . size . width);
final point . y=MIN(MAX(final point . y,0),self . view . bounds . size . height);
[ui view animatewithduration:slide factor * 2 delay:0 options:uiview animationoptions curveeaseout animations:^{
recognizer . view . center=final point;
}完成情况:无];
}
复制代码
这是我为这个教程写的一个非常简单的模拟减速的方法。它遵循以下策略:
计算速度矢量的长度(即大小)。如果长度小于200,则降低基本速度,否则提高基本速度。基于速度和滑动因子计算终点以确定终点。让视图使用动画到达视图边界内的最终静态点。使用“减缓”动画参数来降低移动速度。
编译和运行,现在你有一些基本的,但美丽的减速!让我们更自由地发挥,然后改进它!如果你想到了更好的实现方式,请分享到本文末尾的论坛。
UIPinchGestureRecognizer和UIRotationGestureRecognizer
到目前为止,我们的应用程序已经取得了很好的进展,但是如果您可以缩放和旋转图像视图,它会更酷!
让我们首先添加回调函数,将下面的声明添加到ViewController.h中:
-(I action)handle pinch:(UIPinchGestureRecognizer *)识别器;
-(I action)handle rotate:(UIRotationGestureRecognizer *)识别器;
复制代码
将以下实现添加到ViewController.m中:
-(I action)handle pinch:(UIPinchGestureRecognizer *)recognizer {
recognizer . view . transform=cgaffinitetransformscale(recognizer . view . transform,recognizer.scale,recognizer . scale);
recognizer . scale=1;
-(I action)handle rotate:(UIRotationGestureRecognizer *)识别器{
recognizer . view . transform=cgaffinitetransformrotate(recognizer . view . transform,recognizer . rotation);
recognizer . rotation=0;
}
复制代码
正如我们可以从平移手势识别器获得平移一样,我们也可以从UIPinchGestureRecognizer和UIRotationGestureRecognizer获得缩放和旋转。
通过应用视图的旋转、缩放和平移中的信息,一些变换将被应用于每个视图。苹果建立了大量的方法让变换更容易,比如CGAffineTransformScale(给予缩放变换)和CGAffineTransformRotate(给予旋转变换)。这里我们只使用这些来更新基于手势的视图转换。
还是那句话,当我们在每次手势更新后更新视图时,将缩放和旋转重置为默认状态是非常重要的,这样我们接下来就不会发疯了。
现在让我们在故事板编辑器中建立关联。打开MainStoryboard.storyboard并执行以下步骤:
将挤压手势识别器和旋转手势识别器拖到猴子上,并在香蕉上做同样的操作。将收缩手势识别器的选择器连接到视图控制器的handlePinch方法。将旋转手势识别器的选择器连接到视图控制器的handleRotate方法。
编译运行(有条件的话我建议在真机设备上运行,因为双指拨号和旋转在模拟器上有点难做到)。现在你应该可以缩放和旋转猴子和香蕉了!
同步手势识别器
你可能已经注意到,如果你把一个手指放在猴子上,另一个放在香蕉上,你可以同时拖动它们。有点酷,不是吗?
然而,你会注意到,如果你试图在中间拖动猴子,如果你放下你的第二个手指,并试图用两个手指缩放猴子,这将不起作用。默认情况下,一旦视图上的一个手势识别器“声明”了这个手势,其他手势识别器就不能识别这个手势。
但是,您可以通过在UIGestureRecognizer委托中重写方法来更改这种情况。来看看怎么实现吧!
打开ViewController.h并标记此类以实现UIGestureRecognizerDelegate,如下所示:
@ interface view controller:uiview controller UIGestureRecognizerDelegate
然后转到ViewController.m并实现一个可以覆盖的可选方法:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer should recognize simultaneous with gestureRecognizer:(UIGestureRecognizer *)other gestureRecognizer {
返回YES
}
复制代码
该方法描述了当一个(给定的)手势识别器检测到手势时,另一个手势识别器将识别该手势是否可以。
接下来,打开MainStoryboard.storyboard,并将每个手势识别器连接到视图上它自己的代理出口。
编译并再次运行该应用程序。现在你应该可以拖动这只猴子,用两个手指放大它,然后继续拖动!你甚至可以自然地同时缩放和旋转,这样可以让用户有更好的体验。
程序化的手势识别器(实用的手势识别器)
到目前为止,我们已经在Storyboard editor上创建了一个手势识别器,但是如果您想用程序实现它呢?
也很简单,我们来添加一个点击手指识别器,在点击任意图像视图时播放音效。
由于将播放声音效果,我们需要将AVFoundation.framework添加到我们的项目中。为此,首先在项目导航中选择您的项目,MonkeyPinch target,Build Phases选项卡,展开Link Binary with Libraries partition,单击“Add”按钮,然后选择AVFoundation.framework。现在您的框架列表应该如下所示:
打开ViewCotroller.h并进行以下更改:
//添加到文件顶部
#导入AVFoundation/AVFoundation.h
//添加在@interface之后
@ property(strong)AVAudioPlayer * chomp player;
-(void)handle tap:(UITapGestureRecognizer *)识别器;
复制代码
向ViewController.m添加以下修改
//在@实现之后
@ synthesize chompPlayer
//在viewDidLoad之前
-(AVAudioPlayer *)load wav:(ns string *)filename {
NSURL * URL=[[ns bundle main bundle]URLForResource:filename with extension:@ wav ];
NSError *错误;
AVAudioPlayer * player=[[AVAudioPlayer alloc]initwithcontentsourl:URL error:error];
如果(!玩家){
NSLog(@ 加载%@: %@ 时出错,url,Error . localized description);
}否则{
[player prepareToPlay];
回报玩家;
//用以下内容替换viewDidLoad
- (void)viewDidLoad
【超级viewDidLoad】;
for(ui view * view in self . view . sub views){
UITapGestureRecognizer * recognizer=[[UITapGestureRecognizer alloc]initWithTarget:self action:@ selector(handle tap:)];
recognizer.delegate=self
[查看addGestureRecognizer:recognizer];
//TODO:也添加自定义手势识别器
self . chomp player=[self load wav:@ chomp ];
//添加到文件底部
-(void)handle tap:(UITapGestureRecognizer *)识别器{
【self.chompPlayer播放】;
}
复制代码
这个声音播放代码不在本教程讨论范围内,我们就不讨论了(虽然也很简单)。
ViewDidLoad这部分很重要。我们遍历了所有子视图(只有猴子和香蕉图像视图)并为每个子视图添加了一个UITapGestureRecognizer,还做了一个回调函数。我们通过代码设置委托,并将识别器添加到视图中。
就是这样!编译运行,现在可以听到点击图像查看时的音效了!
UIGestureRecognizer依赖项
除了一个小缺陷,这个应用程序运行得很好。如果你拖动一个对象一点点的距离,它就会被拖动并播放音效,但我们真正想要的是不拖动的情况下播放音效。
为了解决这个问题,我们可以删除或修改代理回调,以在触摸和挤压同时发生时表现不同。但是我想用这个例子来证明另一个很有用的东西。——您可以使用手势识别器来完成此操作:设置相关性。
有一个名为requireGestureRecognizerToFail的方法,您可以在手势识别器上调用它。猜猜它能做什么?]
让我们试试。打开MainStoryboard.storyboard,打开助理编辑器,并确保ViewController.h显示在此处。然后,将猴子的平移手势识别器控件拖到@interface文件中,并创建一个名为monkeyPan的输出端口。对香蕉的平移手势识别器做同样的操作,输出端口被命名为bananaPan。
然后只需在viewDidLoad中添加两行,在TODO之前更正确:
[recognizer requiremesturerecognizertofail:monkey pan];
[recognizer requireGestureRecognizerToFail:banana pan];
复制代码
如果现在没有识别出平移,将调用点击识别器。很酷,不是吗?您可能会发现这项技术在您的项目中非常有用。
自定义UIGestureRecognizer
现在,您已经了解了很多关于在应用程序中使用内部手势识别器的知识。但是如果你想检测一些内部识别器不支持的手势类型呢?
当然可以自己写手势识别器!让我们试着写一个非常简单的手势识别器,通过多次左右移动手指来检测你给猴子或香蕉挠痒痒。
新建一个文件,使用IOS\Cocoa Touch\Objective-C模板,命名为TickleGestureRecognizer,这样就继承了UIGestureRecognizer。
然后根据以下内容替换TickleGestureRecognizer.h:
#导入UIKit/UIKit.h
@ interface tickle gesturerecognizer:UIGestureRecognizer
@ property(assign)int tick count;
@ property(assign)CG point curTickleStart;
@ property(assign)Direction last Direction;
@end
复制代码
现在我们声明三个信息属性来记录和检测这个手势。我们记录:
TickleCount:用户改变手指方向的次数(移动最少点数时)。一旦用户移动手指方向三次,我们就把它当成一个挠痒痒的手势。CurTickleStart:用户在挠痒痒手势中开始移动的点。我们每次都会更新用户方向(移动点数最少的时候)。LastDirection:最后一个手指移动的方向。从方向未知开始,用户移动最少点数后,我们会看手指是会向左还是像向右,然后适当更新。
当然这些属性是针对我们检测到的手势3354如果你针对不同类型的手势做识别器,你会有自己的属性,但是这里可以得到大概的思路。
现在转到TickleGestureRecognizer.m并用以下内容替换它:
# import tickle gesture recognizer . h
# import ui kit/uigesturerecognizersublic . h
-(void)touches begin:(ns set *)touches with event:(ui event *)event {
ui touch * touch=[触摸任何对象];
self . curticklestart=[touch location in view:self . view];
-(void)touches moved:(ns set *)touches with event:(ui event *)event {
//确保自curTickleStart以来我们移动了最小金额
ui touch * touch=[触摸任何对象];
CG point tickle point=[touch location in view:self . view];
CG float move AMT=tickle point . x-curticklestart . x;
方向curDirection
if(移动金额0) {
curDirection=DirectionLeft
}否则{
curDirection=DirectionRight
if(ABS(移动金额)MOVE _ AMT _ PER _ TICKLE)返回;
如果(自我。最后方向==未知方向
(自我。最后方向==向左弯曲方向==向右方向)
(自我。最后方向==右转弯方向==左转弯方向){
//w00t我们挠痒痒了!
自我。滴答计数;
自我。curticklestart=挠痒痒点;
自我。最后方向=弯曲方向;
//一旦我们获得了所需的备忘录数量,就将状态切换到结束了.
//这样做的结果是,回调将被调用。
如果(自我。state==uigesturerecognizerstate可能的自我。需要挠痒痒计数_挠痒痒){
[自我设定状态:UIGestureRecognizerStateEnded];
自我。最后方向=方向未知;
如果(自我。state==uigesturerecognizerstateuble){
[自我设置状态:UIGestureRecognizerStateFailed];
这儿的代码比较多,但是为不准备重温这些细节,因为坦白地说它们并不相当重要。最重要的部分是它怎么运作的普遍想法:我们实现了触摸开始,触摸移动,触摸结束和触摸取消,写自定义代码查看这些触控和检测我们的手势。
一旦我们发现这个手势,我们想传送更新到回调方法。你可以通过转换手势识别器的状态来做到。通常一旦一个手势开始,你想要设置状态为UIGestureRecognizerStateBegin,传送任意更新时为UIGestureRecognizerStateChanged,完成时为UIGestureRecognizerStateEnded。
但是对这个简单的手势识别器而言,一旦用户对某个物体挠痒痒,我们就标注它结束。这个回调将会被调用,将在那儿编写实现代码。
好了,现在使用新的手势识别器。打开ViewController.h并做如下更改:
//添加到文件顶部
# import’tickle手势识别器。 h
-(void)手柄触划:(触划手势识别器*)识别器;
复制代码
接着到ViewController.m中:
//在@实现之后
@合成何合层
TickleGestureRecognizer * recognizer 2=[[TickleGestureRecognizer alloc]initWithTarget:self action:@ selector(handle tickle:)];
识别器2。代表=自己;
[查看addGestureRecognizer:recognizer 2];
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。