【问题标题】:Pan gesture interferes with scroll平移手势干扰滚动
【发布时间】:2013-11-27 22:27:23
【问题描述】:

我有三个视图控制器,它们是 UIScrollView 的一部分。我希望能够在三者之间滑动,尽管其中一个视图控制器具有 UIPanGestureRecognizer。我使用这个平移手势识别器允许用户上下拖动手指来增加和减少矩形 UIView 的高度。因此,这个 UIPanGestureRecognizer 只需要知道向上/向下平移,滚动视图可以使用水平平移。

这方面的一个例子,比如主屏幕;您可以向左或向右滑动,也可以向下滑动以获得聚光灯。我想要这种机制。

这是我的平底锅代码:

- (void)pan:(UIPanGestureRecognizer *)aPan; // When pan guesture is recognised
{
CGPoint location = [aPan locationInView:self.view]; // Location of finger on screen
CGRect secondRect = CGRectMake(210.0, 45.0, 70.0, 325.0); // Rectangles of maximimum bar area
CGRect minuteRect = CGRectMake(125.0, 45.0, 70.0, 325.0);
CGRect hourRect = CGRectMake(41.0, 45.0, 70.0, 325.0);

if (CGRectContainsPoint(secondRect, location)) { // If finger is inside the 'second' rectangle

    CGPoint currentPoint = [aPan locationInView:self.view];

    currentPoint.y -= 80;  // Make sure animation doesn't go outside the bars' rectangle

    if (currentPoint.y < 0) {
    currentPoint.y = 0;
    }
    else if (currentPoint.y > 239) {
    currentPoint.y = 239;
    }

    currentPoint.y = 239.0 - currentPoint.y;

    CGFloat pointy = currentPoint.y - fmod(currentPoint.y, 4.0);

    [UIView animateWithDuration:0.01f  // Animate the bars to rise as the finger moves up and down
                     animations:^{
                         CGRect oldFrame = secondBar.frame;
                         secondBar.frame = CGRectMake(oldFrame.origin.x, (oldFrame.origin.y - (pointy - secondBar.frame.size.height)), oldFrame.size.width, (pointy));
                     }];

    CGFloat result = secondBar.frame.size.height - fmod(secondBar.frame.size.height, 4.0);

    secondInt = (result / 4.0); // Update labels with new time

    self->secondLabel.text = [NSString stringWithFormat:@"%02d", secondInt];
}

代码基本上是针对三个独立的矩形 UIView 重复的。

如果有人能告诉我如何让主屏幕式平移/滑动进入我的应用程序,那就太好了!!

【问题讨论】:

  • 您能否分享一个指向您的项目的链接(github/dropbox),以便我看一下?很难说这些条和标签是什么。
  • 这里是 DropBox 中整个项目的链接:dropbox.com/sh/9jqry6y2kr5kltr/VklDgKvoYe 希望对您有所帮助!另外,我在将所有三个视图控制器都放入滚动视图时遇到了麻烦,我不确定 ScrollViewController.m 中的代码是否正确,所以如果你也能帮助我解决这个问题,那就太好了!
  • 我无法打开该项目。 Bars.xcodeproj 文件似乎有问题。 XCode 无法打开它,当我用 TextEdit 打开它时它是空的。
  • 是的,那个正在工作。不错的应用程序。让我看看是什么问题,我会回复你

标签: ios objective-c uiscrollview swipe uipangesturerecognizer


【解决方案1】:

好的,下面是简短的回答:

你必须使用UIGestureRecognizer的方法-requireGestureRecognizerToFail:

下面是长答案:

只有在TimerViewController 的平移手势识别器失败时,您必须使滚动视图的平移手势识别器成功。但是,该手势(TimerViewController 的手势)应该初始移动是垂直的情况下成功。如果它是水平的,它应该会失败。 为此,我们必须继承UIPanGestureRecognizer 并对其进行修改以适应这些需求。 这是你必须做的:

  1. 忽略您对我之前的回答所做的所有更改
  2. VerticalPanGestureRecognizer 添加到您的项目中。
  3. 修改TimerViewController如图。
  4. 修改ScrollViewController如图。

VerticalPanGestureRecognizer.h

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>

@interface VerticalPanGestureRecognizer : UIPanGestureRecognizer

@end

VerticalPanGestureRecognizer.m

#import "VerticalPanGestureRecognizer.h"

@interface VerticalPanGestureRecognizer ()

@property (nonatomic, assign) CGPoint origLoc;

@end

@implementation VerticalPanGestureRecognizer

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

    self.origLoc = [[touches anyObject] locationInView:self.view.superview];
    [super touchesBegan:touches withEvent:event];
}

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

    if (self.state == UIGestureRecognizerStatePossible) {
        CGPoint loc = [[touches anyObject] locationInView:self.view.superview];
        CGFloat deltaX = fabs(loc.x - self.origLoc.x);
        CGFloat deltaY = fabs(loc.y - self.origLoc.y);
        if (deltaY < deltaX)
            self.state = UIGestureRecognizerStateFailed;
    }

    [super touchesMoved:touches withEvent:event];
}

@end

TimerViewController.h

// Your imports here

@interface TimerViewController : UIViewController

{
    // Your ivars here
}

// Add the following property
@property (nonatomic, strong) UIPanGestureRecognizer *pan;

// Your methods here

@end

TimerViewController.m

#import "TimerViewController.h"
#import "VerticalPanGestureRecognizer.h"

@implementation TimerViewController
@synthesize pan = _pan;

// prefersStatusBarHidden method here

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // Initialise view controller
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        // Instantiate the pan gesture as "VerticalPanGestureRecognizer"
        self.pan = [[VerticalPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; // Create recogniser for a pan guesture
        self.pan.maximumNumberOfTouches = self.pan.minimumNumberOfTouches = 1;
        [self.view addGestureRecognizer:self.pan];
    }

    return self;
}

// The rest of your code here

@end

ScrollViewController.m

- (void)viewDidLoad
{
    // Your code here

    TimerViewController *tvc = [[TimerViewController alloc]init];
    CGRect frame = tvc.view.frame;
    frame.origin.x = 320;
    tvc.view.frame = frame;

    // Add the following line 
    [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];

    [self addChildViewController:tvc];
    [self.scrollView addSubview:tvc.view];
    [tvc didMoveToParentViewController:self];

    // More code here
}

这种新方法非常有效。我测试了它。 如果您还有其他问题,请告诉我。

干杯!

更新

要回答您在 cmets 上发布的问题,您必须执行以下操作:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    BarsViewController *bvc = [[BarsViewController alloc]init];
    [self addChildViewController:bvc];
    [self.scrollView addSubview:bvc.view];
    [bvc didMoveToParentViewController:self];

    TimerViewController *tvc = [[TimerViewController alloc]init];
    CGRect frame = tvc.view.frame;
    frame.origin.x = 320;
    tvc.view.frame = frame;

    [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];
    [self addChildViewController:tvc];
    [self.scrollView addSubview:tvc.view];
    [tvc didMoveToParentViewController:self];

    StopwatchViewController *svc = [[StopwatchViewController alloc] init];
    frame = svc.view.frame;
    frame.origin.x = 320*2;
    svc.view.frame = frame;

    [self addChildViewController:svc];
    [self.scrollView addSubview:svc.view];
    [svc didMoveToParentViewController:self];

    self.scrollView.contentSize = CGSizeMake(320*3, self.view.frame.size.height);
    self.scrollView.pagingEnabled = YES;

    [self.scrollView setShowsHorizontalScrollIndicator:NO];
}

我再次对其进行了测试,并且它可以正常工作。您只需为条形添加手势识别器

【讨论】:

  • 这很好用,谢谢!然而,Pan 手势似乎不那么敏感。例如,只有当您松开屏幕时,该栏才会改变高度,而之前,它会随着您的手指移动而移动。此外,如果我移动条形图,滚动视图也会移动。是否有可能让滚动视图仅在手指在 x 方向上的移动多于在 y 方向上移动时才会移动,而对于条形图,反之亦然?我认为这可能会产生我正在寻找的主屏幕风格的效果。除此之外,非常感谢你!!!
  • @user2397282 请查看我的更新答案。新方法非常有效。请不要忘记接受答案。
  • 哇!!这正是我想要的!我不想显得粗鲁,但如果我能请求一点帮助?在 scrollViewController.m 中,如何添加我的第三个视图控制器 StopwatchViewController?你太棒了!!非常感谢!
  • @user2397282 我对我的回答进行了另一次更新以回复您的问题。也许您应该将您的项目迁移到 GitHub,这样我就可以为您的应用程序做出贡献。
  • 谢谢!!好的,我明天会考虑上 Github;我刚要睡觉!我不敢相信你今天对我有多大帮助,谢谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多