[英]UIView frame and center not correlated after pan code updates center?
因此,我得到了一個精簡的ViewController示例,該示例再現了這種行為,而我似乎無法纏住我的頭。 我正在使用帶有一些代碼的UIPanGestureRecognizer,該代碼正確地允許UIView在窗口中移動。 但是,如果我更新框架,甚至更新框架本身,視圖也會跳到意外位置,大概是基於視圖的中心。
我對此代碼有兩個問題。 首先,為什么視圖的中心位於最后一次觸摸的位置(基本上是將anchorPoint映射到視圖的邊界),並且顯然與視圖框架的中心無關?
其次,為什么在將frame屬性更改為當前值時視圖會移動? 在我看來,視圖的中心和框架只是部分相關,我不確定我缺少什么。
此示例僅在應用程序委托中創建一個基本的測試視圖控制器:
TestViewController *vc = [[TestViewController alloc] init];
self.window.rootViewController = vc;
TestViewController.m:
#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
平移手勢結束后,如果我刪除以下行,則平移將按預期工作:
self.view.frame = self.view.frame;
我真的看不到這條線怎么會導致視圖移動,除非以前的center屬性沒有“完全粘住”或其他東西。 此外,我不了解center屬性的值,因為它似乎是最后觸摸的地方,而不是視圖的中心。 日志示例:
AnchorPoint: {0.204427, 0.748506}
Center: {625, 218.5}
Frame: {{14, -34}, {768, 1004}}
從長遠來看,我試圖在這里實現的是一個可以縮放的視圖,但是當滾動到邊緣之外時,它將回彈(就像UIScrollView一樣)。
如果刪除這兩行
view.layer.anchorPoint = CGPointMake(locationInView.x / view.bounds.size.width, locationInView.y / view.bounds.size.height);
view.center = locationInSuperview;
然后,您的視圖平移將達到您的預期。 為什么仍要更改圖層的定位點? 通常,您要實現的代碼看起來過於復雜。 請參閱DavidRönnqvist, 了解錨點 , 了解如何更改錨點會對視圖的幀屬性產生(通常是意外的)影響。
此外,通常最好不要self.view
頂級視圖(視圖控制器的self.view
)並操作子視圖。 這樣,您就知道一切都與viewController的視圖相關聯,而不必懷疑UIWindow的狀況。 旋轉設備時,旋轉變換將應用於該頂層視圖,這在檢查框架數據時無濟於事。 子視圖的屬性不受該轉換的影響。
您的代碼在未轉換的縱向模式下的行為與預期的一樣,並且僅在橫向或縱向倒置時會拋出奇怪的結果。 在這些情況下,視圖已應用旋轉變換。 蘋果公司說,將變換應用於視圖后,框架的origin屬性是未定義的,因此在執行此操作時:
self.view.frame = self.view.frame
您正在分配處於未定義狀態的屬性。 期待意外。
您可以這樣更改視圖加載代碼:
- (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
實現一個子視圖。 現在,您的測試應用程序可以正常運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.