2

我试图让用户能够通过将 a 附加到 the并随后将约束的常量从其视图的顶部更改为来UILabel在视图中上下移动。所以基本上,如果手势识别器检测到它们向下移动 12pts,则将约束的常量移动 12pts 以移动.UIPanGestureRecognizerUILabelUILabelUILabel

但是,我希望它们在到达某个垂直点(太高或太低)时停止移动。我可以只检查平移手势的翻译,但我的UILabel可以是任意数量的行,所以如果是五行而不是一条,显然它不能平移那么远,所以我不能依赖翻译平移手势,我必须考虑标签的大小。

所以我开始监视它的框架,它运行良好,但在我的实现中,有一个烦人的结果,如果它们完全平移到底部极限,它们必须在UILabel“赶上”并附带它之前平移很远(尽管当它们到达顶部边界时不存在这样的问题)。基本上,它们向下平移到下限,当它们向上平移时(这都是在同一个手势中),它会暂时“粘住”,直到它们向上平移足够远,然后用手指向上跳。

这是我用来完成此操作的代码:

- (void)textLabelPanned:(UIPanGestureRecognizer *)panGestureRecognizer {
    if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
        _textDistanceFromTopBeforeMove = self.textToReadLabelPositionFromTopConstraint.constant;
    }
    else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) {
        NSNumber *textDistanceFromTop = @(self.textToReadLabelPositionFromTopConstraint.constant);
        [[NSUserDefaults standardUserDefaults] setObject:textDistanceFromTop forKey:@"TextDistanceFromTop"];
    }
    else {
        if (CGRectGetMinY(self.textToReadLabel.frame) >= [UIScreen mainScreen].bounds.origin.y + CLOSEST_TEXT_DISTANCE_TO_TOP && CGRectGetMaxY(self.textToReadLabel.frame) <= [UIScreen mainScreen].bounds.size.height - CLOSEST_TEXT_DISTANCE_TO_BOTTOM) {
                self.textToReadLabelPositionFromTopConstraint.constant = _textDistanceFromTopBeforeMove + [panGestureRecognizer translationInView:self.mainView].y;
        }
        else if ([panGestureRecognizer translationInView:self.mainView].y > 0) {
            if (CGRectGetMaxY(self.textToReadLabel.frame) + _textDistanceFromTopBeforeMove + [panGestureRecognizer translationInView:self.mainView].y < [UIScreen mainScreen].bounds.size.height - CLOSEST_TEXT_DISTANCE_TO_BOTTOM) {
                self.textToReadLabelPositionFromTopConstraint.constant = _textDistanceFromTopBeforeMove + [panGestureRecognizer translationInView:self.mainView].y;
            }
        }
        else if ([panGestureRecognizer translationInView:self.mainView].y < 0) {
            if (CGRectGetMinY(self.textToReadLabel.frame) + _textDistanceFromTopBeforeMove + [panGestureRecognizer translationInView:self.mainView].y > [UIScreen mainScreen].bounds.origin.y + CLOSEST_TEXT_DISTANCE_TO_TOP) {
                self.textToReadLabelPositionFromTopConstraint.constant = _textDistanceFromTopBeforeMove + [panGestureRecognizer translationInView:self.mainView].y;
            }
        }


        // If one of the options views are present and the user pans really low, hide the options as to allow the user to see where they're panning
        if (_inSpeedChangingMode) {
            if (CGRectGetMaxY(self.textToReadLabel.frame) > CGRectGetMinY(self.progressBar.frame) - 10) {
                [self showWordOptions:nil];
            }
        }
        else if (_inTextChangingMode) {
            if (CGRectGetMaxY(self.textToReadLabel.frame) > CGRectGetMinY(self.progressBar.frame) - 10) {
                [self showTextOptions:nil];
            }
        }
    }
}

我到底做错了什么会导致它“粘住”?是否有更好的方法来做到这一点?

4

2 回答 2

2

您可以完全使用在 Interface Builder 或代码中定义的约束来完成此操作。诀窍是定义约束以防止标签移动到比设置所需位置的约束具有更高优先级的边界。

在我的测试项目中,我完全在一个故事板中设置了一个视图层次结构,它有一个 1)视图控制器视图 2)定义边界的“容器视图”3)多行 UILabel。有 6 个约束作用于其容器中的标签:

  • 4 'space to' 约束(前导、尾随、顶部、底部)防止标签被定位在其父容器的边界之外。这些的优先级在 Interface Builder 中设置为默认的“1000”值。这些约束的关系是'>=',常数值是'0'。

  • 2 'space to' 约束(前导、顶部)驱动标签的实际位置。这些的优先级设置得较低;我选择了“500”。这些约束在视图控制器中有出口,因此可以在代码中进行调整。这些约束的关系是“=”,初始值是您想要放置标签的任何值。

标签本身有一个宽度约束,以强制它显示多行。

这是在 IB 中的样子:

选定的约束具有较低的优先级,用于驱动标签的 x 位置。此约束与视图控制器中的 ivar 相关联,因此可以在运行时进行调整。 显示选定的定位约束

选定的约束具有更高的优先级,并用于将标签圈在其父视图中。 显示选择的围场约束

这是视图控制器中的代码:

@interface TSViewController ()
@end

@implementation TSViewController
{
    IBOutlet NSLayoutConstraint* _xLayoutConstraint;

    IBOutlet NSLayoutConstraint* _yLayoutConstraint;
}

- (IBAction) pan: (UIGestureRecognizer*) pgr
{
    CGPoint p = [pgr locationInView: self.view];

    p.x -= pgr.view.frame.size.width / 2.0;
    p.y -= pgr.view.frame.size.height / 2.0;

    _xLayoutConstraint.constant = p.x;
    _yLayoutConstraint.constant = p.y;
}

@end

UIPanGestureRecognizerUILabel 相关联,并将其回调设置为视图控制器中的 pan: 方法。

于 2013-10-31T18:36:40.253 回答
1

如果您的应用具有最低 SDK iOS7,则可以使用 UIKit Dynamics 而不是那些 UIGestureRecognizers。使用 UICollisionBehavoir 和 UIAttachmentBehavior 可以轻松解决您的问题

你可能想调查一下。这是 UIKit Dynamics 上的苹果示例项目: https ://developer.apple.com/library/IOS/samplecode/DynamicsCatalog/Introduction/Intro.html

玩弄它,你会惊讶于你可以用这么少的代码做些什么。

WWDC 2013 会议: - UIKit Dynamics 入门 - UIKit Dynamics 高级技术

于 2013-10-31T18:43:55.860 回答