首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在pan代码更新中心后,UIView帧和中心不相关?

在pan代码更新中心后,UIView帧和中心不相关?
EN

Stack Overflow用户
提问于 2013-04-26 18:48:53
回答 1查看 856关注 0票数 1

所以我有一个简化的ViewController示例,它重现了这个行为,我似乎不能理解它。我正在使用一个带有一些代码的UIPanGestureRecognizer,这些代码正确地允许UIView在窗口中移动。但是,如果我更新框架,甚至更新到它本身,视图会跳转到一个意外的位置,大概是基于视图的中心。

关于这段代码,我有两个问题。首先,为什么视图的中心是最后一次触摸的位置(基本上anchorPoint映射到视图的边界),而显然与视图框架的中心没有任何关系?

其次,为什么将frame属性更改为当前值时,视图会移动?在我看来,视图的中心和框架只是部分相关,我不确定我错过了什么。

这个例子只是在应用委托中创建了一个基本的测试视图控制器:

代码语言:javascript
运行
复制
TestViewController *vc = [[TestViewController alloc] init];
self.window.rootViewController = vc;

TestViewController.m:

代码语言:javascript
运行
复制
#import "TestViewController.h"
#import <QuartzCore/QuartzCore.h>

@implementation TestViewController

- (void)loadView
{
    self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 748)];
    self.view.backgroundColor = UIColor.redColor;

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPan:)];
    pan.maximumNumberOfTouches = 1;
    [self.view addGestureRecognizer:pan];
}

- (void)onPan:(UIPanGestureRecognizer*)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        UIView *view = recognizer.view;
        CGPoint locationInView = [recognizer locationInView:view];
        CGPoint locationInSuperview = [recognizer locationInView:view.superview];

        view.layer.anchorPoint = CGPointMake(locationInView.x / view.bounds.size.width, locationInView.y / view.bounds.size.height);
        view.center = locationInSuperview;
    }

    if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged) {

        CGPoint translation = [recognizer translationInView:[recognizer.view superview]];
        [recognizer.view setCenter:CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y+translation.y)];
        [recognizer setTranslation:CGPointZero inView:[recognizer.view superview]];
    }

    if(recognizer.state == UIGestureRecognizerStateEnded) {

        NSLog(@"AnchorPoint: %@", NSStringFromCGPoint(self.view.layer.anchorPoint));
        NSLog(@"Center: %@", NSStringFromCGPoint(self.view.center));
        NSLog(@"Frame: %@", NSStringFromCGRect(self.view.frame));

        self.view.frame = self.view.frame;
    }
}

@end

当平移手势结束时,如果我删除以下行,则平移将按预期工作:

代码语言:javascript
运行
复制
self.view.frame = self.view.frame;

我真的不明白这条线怎么会导致视图四处移动,除非之前的center属性没有“完全粘合”或其他什么。此外,我不理解center属性的值,因为它似乎是最后接触到的位置,而根本不是视图的中心。示例日志:

代码语言:javascript
运行
复制
AnchorPoint: {0.204427, 0.748506}
Center: {625, 218.5}
Frame: {{14, -34}, {768, 1004}}

从长远来看,我试图在这里实现的是一个可以缩放的视图,但当滚动到边缘之外时,它会弹回(就像UIScrollView一样)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-05 11:05:07

如果您删除这两行

代码语言:javascript
运行
复制
    view.layer.anchorPoint = CGPointMake(locationInView.x / view.bounds.size.width, locationInView.y / view.bounds.size.height);
    view.center = locationInSuperview;

然后,您的视图平移行为如您所期望的那样。你为什么要改变图层的锚点呢?一般来说,对于您试图实现的目标而言,您的代码似乎过于复杂了。请参阅David Rönnqvist,understanding the anchor point,了解更改锚点对视图框架属性的影响(通常是意外的)。

此外,离开顶层视图(视图控制器的self.view)并操作子视图通常是一个好主意。这样,您就可以知道所有内容与viewController的视图之间的关系,而不需要知道UIWindow发生了什么。旋转设备时,会将旋转变换应用于该顶级视图,这在检查帧数据时没有帮助。它的子视图的属性不受该转换的影响。

您的代码在未转换的纵向模式下的行为与您期望的一样,并且只有在横向或纵向颠倒时才会抛出奇怪的结果。以下是应用了旋转变换的视图的情况。Apple说,当转换应用到视图时,框架的原点属性是未定义的,所以当您这样做时:

代码语言:javascript
运行
复制
self.view.frame = self.view.frame

您正在分配处于未定义状态的属性。期待意想不到的事情。

您可以更改视图加载代码,如下所示:

代码语言:javascript
运行
复制
- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView* subview = [[UIView alloc] initWithFrame:
                       CGRectMake(0, 0
                                  , self.view.bounds.size.width
                                  , self.view.bounds.size.height)];
    [self.view addSubview:subview];
    subview.backgroundColor = UIColor.redColor;
    [subview setAutoresizingMask:UIViewAutoresizingFlexibleWidth 
                                |UIViewAutoresizingFlexibleHeight];
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] 
                                     initWithTarget:self 
                                             action:@selector(onPan:)];
    pan.maximumNumberOfTouches = 1;
    [subview addGestureRecognizer:pan];
}

这里我们没有覆盖-loadView,让它自动创建顶级视图,然后在viewDidLoad中实现一个子视图。现在,您的测试应用程序运行正常。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16234631

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档