2012-06-13 19 views
5

Tôi đang sử dụng chế độ xoay, chụm và xoay UIGestureRecognizers để cho phép người dùng đặt một số phần tử giao diện người dùng chính xác vào nơi họ muốn. Sử dụng mã từ đây http://www.raywenderlich.com/6567/uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more (hoặc mã tương tự từ đây http://mobile.tutsplus.com/tutorials/iphone/uigesturerecognizer/) cả hai đều cung cấp cho tôi những gì tôi cần để người dùng đặt các phần tử giao diện người dùng này theo ý muốn của họ.Đang tải chuyển đổi & trung tâm của UIView từ các cài đặt cho vị trí khác nhau

Khi thoát người dùng "bố trí giao diện người dùng" chế độ, tôi tiết kiệm của biến đổi và trung tâm như vậy UIView:

NSString *transformString = NSStringFromCGAffineTransform(self.transform); 
[[NSUserDefaults standardUserDefaults] setObject:transformString forKey:@"UItransform", suffix]]; 

NSString *centerString = NSStringFromCGPoint(self.center); 
[[NSUserDefaults standardUserDefaults] setObject:centerString forKey:@"UIcenter"]; 

Khi tôi tải lại ứng dụng, tôi đọc của biến đổi và trung tâm như vậy UIView:

NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"UIcenter"]; 
if(centerString != nil) 
    self.center = CGPointFromString(centerString); 

NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"UItransform"]; 

if(transformString != nil) 
    self.transform = CGAffineTransformFromString(transformString); 

Và UIView kết thúc xoay và chia tỷ lệ chính xác, nhưng ở sai vị trí. Hơn nữa, khi chuyển sang chế độ "Bố cục giao diện người dùng" một lần nữa, tôi không thể luôn luôn lấy chế độ xem bằng các cử chỉ khác nhau (như thể chế độ xem được hiển thị không phải là chế độ xem được hiểu bởi trình nhận dạng cử chỉ?)

Tôi cũng có nút đặt lại thiết lập số transform của UIView thành danh tính và center của bất kỳ thứ gì khi tải từ NIB. Nhưng sau khi tải trung tâm UIView thay đổi và chuyển đổi, ngay cả việc đặt lại không hoạt động. Vị trí của UIView là sai.

Suy nghĩ đầu tiên của tôi là vì các ví dụ mã cử chỉ này thay đổi center, việc quay phải xảy ra xung quanh các trung tâm khác nhau (giả sử một số di chuyển, xoay vòng và quy mô không thể đoán trước). Vì tôi không muốn lưu toàn bộ chuỗi chỉnh sửa (mặc dù điều đó có thể hữu ích nếu tôi muốn có một số tính năng hoàn tác trong chế độ bố cục), tôi đã thay đổi trình xử lý UIPanGestureRecognizer để sử dụng phép biến đổi để di chuyển nó. Một khi tôi nhận được rằng làm việc, tôi figured chỉ cần tiết kiệm biến đổi sẽ giúp tôi có được vị trí hiện tại và định hướng, bất kể trong những thứ thứ gì đã xảy ra. Nhưng không may mắn như vậy. Tôi vẫn nhận được một vị trí lập dị theo cách này.

Vì vậy, tôi đang thua lỗ. Nếu một UIView đã được di chuyển và xoay đến một vị trí mới, làm thế nào tôi có thể lưu vị trí và định hướng đó theo cách mà tôi có thể tải nó sau này và đưa UIView trở lại vị trí cần thiết?

Xin lỗi trước nếu tôi không gắn thẻ quyền này hoặc không đặt chính xác hoặc cam kết một số lỗi ngăn xếp chồng lên nhau khác. Đây là lần đầu tiên tôi đăng ở đây.

EDIT

Tôi đang thử hai đề xuất từ ​​trước đến nay. Tôi nghĩ rằng chúng có hiệu quả giống nhau (một gợi ý tiết kiệm khung và cái kia gợi ý tiết kiệm nguồn gốc, mà tôi nghĩ là frame.origin).

Vì vậy, bây giờ lưu/tải từ mã prefs bao gồm những điều sau đây.

Lưu:

NSString *originString = NSStringFromCGPoint(self.frame.origin); 
[[NSUserDefaults standardUserDefaults] setObject:originString forKey:@"UIorigin"]; 

Load (trước tải transform):

NSString *originString = [[NSUserDefaults standardUserDefaults] objectForKey:@"UIorigin"]; 
if(originString) { 
    CGPoint origin = CGPointFromString(originString); 
    self.frame = CGRectMake(origin.x, origin.y, self.frame.size.width, self.frame.size.height); 
} 

tôi nhận được như nhau (hoặc tương tự - đó là khó có thể nói) kết quả. Trong thực tế, tôi đã thêm một nút để tải lại các prefs và sau khi chế độ xem được xoay, nút "tải lại" sẽ di chuyển UIView bằng một số lần lặp lại (như khung hoặc biến đổi liên quan đến chính nó - mà tôi chắc chắn là một đầu mối, nhưng tôi không chắc nó là gì).

EDIT # 2

Điều này làm cho tôi tự hỏi về tùy thuộc vào quan điểm của frame. Từ Apple http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/WindowsandViews/WindowsandViews.html#//apple_ref/doc/uid/TP40009503-CH2-SW6 (nhấn mạnh mỏ):

Giá trị trong thuộc tính trung tâm luôn hợp lệ, ngay cả khi các yếu tố chia tỷ lệ hoặc xoay đã được thêm vào chuyển đổi của chế độ xem. Điều này cũng không đúng đối với giá trị trong thuộc tính khung, được coi là không hợp lệ nếu chuyển đổi của chế độ xem không bằng với biến đổi nhận dạng.

EDIT # 3

Được rồi, vì vậy khi tôi đang tải prefs trong, tất cả mọi thứ có vẻ tốt đẹp. Bảng điều khiển của giao diện người dùng là bounds rect là {{0, 0}, {506, 254}}. Vào cuối phương thức viewDidLoad của VC, mọi thứ vẫn ổn. Nhưng vào thời điểm mọi thứ được hiển thị, bounds là thứ khác. Ví dụ: {{0, 0}, {488.321, 435.981}} (có vẻ như nó lớn như thế nào trong phạm vi giám sát của nó khi xoay và thu nhỏ). Nếu tôi đặt lại giới hạn cho những gì nó được cho là, nó di chuyển trở lại vào vị trí.

Thật dễ dàng để đặt lại giới hạn cho những gì chúng được cho là có lập trình, nhưng tôi thực sự không chắc chắn khi nào làm điều đó! Tôi đã nghĩ sẽ làm điều đó vào cuối viewDidLoad, nhưng bounds vẫn chính xác tại thời điểm đó.

EDIT # 4

tôi đã cố gắng chụp self.bounds trong initWithCoder (vì nó đến từ một NIB), và sau đó trong layoutSubviews, đặt self.bounds để mà bắt CGRect. Và nó hoạt động.

Nhưng có vẻ như rất khó khăn và đầy nguy hiểm. Điều này có thể không thực sự là cách đúng để làm điều này. (Có thể không?) Câu trả lời của skram dưới đây có vẻ đơn giản, nhưng không hiệu quả đối với tôi khi ứng dụng tải lại.

+0

Câu hỏi đầu tiên tuyệt vời! Chào mừng bạn đến với SO! – jrturton

+0

Cảm ơn, jrturton :) SO thực sự là một cái gì đó khác. Thực tế là tôi có hai câu trả lời trong vòng vài phút (ngay cả khi tôi chưa thành công) chỉ là ngoạn mục! – sbkp

+0

Có lẽ bạn đang sử dụng kết hợp các phép biến đổi tỷ lệ và xoay để xoay/thu phóng và chỉ di chuyển trung tâm cho chảo? – jrturton

Trả lời

0

Nhờ tất cả những người đã đóng góp câu trả lời! Tổng cộng tất cả đã dẫn tôi đến những điều sau đây:

Sự cố dường như đã xảy ra là bounds CGRect đã được đặt lại sau khi tải biến đổi từ tùy chọn lúc khởi động, chứ không phải khi cập nhật tùy chọn trong khi sửa đổi trong thời gian thực.

Tôi nghĩ có hai giải pháp. Trước tiên, người ta sẽ tải các tùy chọn từ layoutSubviews thay vì từ viewDidLoad. Không có gì xảy ra với bounds sau khi gọi layoutSubviews.

Vì các lý do khác trong ứng dụng của tôi, tuy nhiên, thuận tiện hơn khi tải tùy chọn từ bộ điều khiển của chế độ xem viewDidLoad. Vì vậy, giải pháp tôi đang sử dụng là:

// UserTransformableView.h 
@interface UserTransformableView : UIView { 
    CGRect defaultBounds; 
} 

// UserTransformableView.m 
- (id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if(self) { 
     defaultBounds = self.bounds; 
    } 
    return self; 
} 

- (void)layoutSubviews { 
    self.bounds = defaultBounds; 
} 
2

Bạn cũng sẽ lưu thuộc tính frame. Bạn có thể sử dụng NSStringFromCGRect()CGRectFromString().

Khi tải, đặt khung sau đó áp dụng biến đổi của bạn. Đây là cách tôi làm điều đó trong một trong các ứng dụng của tôi.

Hy vọng điều này sẽ hữu ích.

CẬP NHẬT: Trong trường hợp của tôi, tôi có Draggable UIViews mà xoay và thay đổi kích thước có thể được áp dụng cho. Tôi sử dụng NSCoding để lưu và tải các đối tượng của tôi, ví dụ bên dưới.

//encoding 
.... 
[coder encodeCGRect:self.frame forKey:@"rect"]; 
// you can save with NSStringFromCGRect(self.frame); 
[coder encodeObject:NSStringFromCGAffineTransform(self.transform) forKey:@"savedTransform"]; 

//init-coder 
CGRect frame = [coder decodeCGRectForKey:@"rect"]; 
// you can use frame = CGRectFromString(/*load string*/); 
[self setFrame:frame]; 
self.transform = CGAffineTransformFromString([coder decodeObjectForKey:@"savedTransform"]); 

Điều này có tác dụng lưu khung hình của tôi và chuyển đổi và tải chúng khi cần. Cùng một phương pháp có thể được áp dụng với NSStringFromCGRect()CGRectFromString().

CẬP NHẬT 2: Trong trường hợp của bạn. Bạn sẽ làm một cái gì đó như thế này ..

[self setFrame:CGRectFromString([[NSUserDefaults standardUserDefaults] valueForKey:@"UIFrame"])]; 
self.transform = CGAffineTransformFromString([[NSUserDefaults standardUserDefaults] valueForKey:@"transform"]); 

Giả sử bạn đang tiết kiệm để NSUserDefaults với UIFrametransform phím.

+0

Cảm ơn, skram. Tôi nghĩ đề xuất của bạn về cơ bản giống như của dianz, phải không? Ông đề nghị lưu nguồn gốc của khung nhìn (có lẽ là khung hình). Cho dù với đề nghị của anh ấy hay của bạn (như tôi đã hiểu), tôi vẫn nhận được một kết quả khả quan. Nếu không quá nhiều để hỏi, bạn có thể đăng đoạn mã để đẩy tôi đi đúng hướng không? – sbkp

+0

đã thêm ví dụ về cách tôi sử dụng cùng một phương pháp. – skram

+0

Cảm ơn! Tôi vẫn nhận được kết quả tương tự. Nhưng hãy để tôi kiểm tra một cái gì đó ở đây. Tôi đang sử dụng NSUserDefaults mà không cần NSCoding cho việc này. Vì vậy, mã lưu của tôi (ví dụ) khác với mã của bạn, như vậy: '[[NSUserDefaults standardUserDefaults] NSStringFromCGRect (self.frame) forKey: @" UIframe "]; [[NSUserDefaults standardUserDefaults] NSStringFromCGAffineTransform (self.transform) forKey: @ "UItransform"]; ' Điều đó dường như hoàn thành giống như những gì bạn đang làm (phải không)? – sbkp

1

Bạn nên cũng lưu vị trí của UIView,

CGPoint position = CGPointMake(self.view.origin.x, self.view.origin.y) 

NSString _position = NSStringFromCGPoint(position); 

// Do the saving 
+0

Cảm ơn, dianz. Thật không may, tôi đã không nhận được nó để làm việc. Tôi đặt giải thích của tôi về những gì bạn có nghĩa là trong bài viết của tôi (sau khi "EDIT"). Bạn sẽ rất tử tế khi nhìn xem tôi có hiểu bạn đúng không? (Lưu self.frame.origin) Hoặc nếu không quá nhiều để hỏi, bạn có thể đăng đoạn mã để đẩy tôi đi đúng hướng không? – sbkp

+0

Điều này thậm chí không biên dịch và cũng không khác với thuộc tính trung tâm. – jrturton

0

Tôi không chắc chắn về tất cả những gì đang xảy ra, nhưng đây là một số ý kiến ​​cho rằng có thể giúp đỡ.

1- giải pháp skram có vẻ hợp lý, nhưng đó là số bounds bạn muốn lưu, không phải là frame. (.. Lưu ý rằng, nếu không hề được luân chuyển, trung tâm và giới hạn xác định khung Vì vậy, thiết lập hai cũng giống như thiết lập các khung hình) Từ, các View Programming Guide for IOS bạn liên quan đến:

Quan trọng Nếu một thuộc tính biến đổi của chế độ xem không phải là nhận dạng chuyển đổi, giá trị của thuộc tính khung của chế độ xem đó là không xác định và phải được bỏ qua. Khi áp dụng biến đổi cho chế độ xem, bạn phải sử dụng các giới hạn và thuộc tính trung tâm của các khung nhìn để có được kích thước và vị trí của chế độ xem. Hình chữ nhật khung của bất kỳ bản xem phụ nào vẫn hợp lệ vì chúng có liên quan đến giới hạn của khung nhìn.

2- Một ý tưởng khác. Khi bạn tải lại ứng dụng, bạn có thể thử như sau:

  • Trước tiên, đặt biến đổi của chế độ xem thành biến đổi nhận dạng.
  • Sau đó, đặt giới hạn và trung tâm của chế độ xem thành giá trị đã lưu.
  • Cuối cùng, đặt biến đổi của chế độ xem thành biến đổi đã lưu.

Tùy thuộc vào nơi ứng dụng của bạn khởi động lại, ứng dụng có thể bắt đầu sao lưu với một số hình ảnh cũ. Tôi thực sự không nghĩ rằng điều này sẽ thay đổi bất cứ điều gì, nhưng nó đủ dễ dàng để thử.
Cập nhật: Sau một số thử nghiệm, có vẻ như điều này sẽ không có hiệu lực. Thay đổi biến đổi dường như không thay đổi các giới hạn hoặc trung tâm (mặc dù nó thay đổi khung.)

3- Cuối cùng, bạn có thể tiết kiệm một số rắc rối bằng cách viết lại công cụ nhận dạng cử chỉ để hoạt động trên bounds thay vì transform. (Một lần nữa, hãy sử dụng bounds, không phải frame, vì xoay vòng trước đó có thể đã trả về frame không hợp lệ.) Bằng cách này, phép biến đổi chỉ được sử dụng cho phép quay mà tôi nghĩ không thể thực hiện theo cách khác mà không vẽ lại.

Từ hướng dẫn tương tự, đề nghị của Apple là:

Bạn thường thay đổi chuyển hóa tài sản của một cái nhìn khi bạn muốn thực hiện hình ảnh động. Ví dụ: bạn có thể sử dụng thuộc tính này để tạo hoạt ảnh cho chế độ xem của bạn xoay quanh điểm trung tâm của nó. Bạn sẽ không sử dụng thuộc tính này để thực hiện thay đổi vĩnh viễn cho chế độ xem của bạn, chẳng hạn như sửa đổi vị trí hoặc kích thước của một chế độ xem trong không gian tọa độ của người giám sát. Đối với loại thay đổi đó, bạn nên sửa đổi khung hình hình chữ nhật của chế độ xem thay thế.

2

Tôi đang gặp sự cố khi tái tạo sự cố của bạn.Tôi đã sử dụng đoạn mã sau, mà làm những điều sau đây:

  • Thêm một cái nhìn
  • Moves nó bằng cách thay đổi trung tâm
  • Cân nó với một transform
  • Xoay nó với một biến đổi, nối vào đầu tiên
  • Lưu biến đổi và trung tâm thành chuỗi
  • Thêm chế độ xem khác và áp dụng trung tâm và chuyển đổi từ chuỗi

Điều này dẫn đến hai quan điểm trong chính xác cùng một vị trí và vị trí:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
    view1.layer.borderWidth = 5.0; 
    view1.layer.borderColor = [UIColor blackColor].CGColor; 
    [self.view addSubview:view1]; 
    view1.center = CGPointMake(150,150); 
    view1.transform = CGAffineTransformMakeScale(1.3, 1.3); 
    view1.transform = CGAffineTransformRotate(view1.transform, 0.5); 

    NSString *savedCentre = NSStringFromCGPoint(view1.center); 
    NSString *savedTransform = NSStringFromCGAffineTransform(view1.transform); 

    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
    view2.layer.borderWidth = 2.0; 
    view2.layer.borderColor = [UIColor greenColor].CGColor; 
    [self.view addSubview:view2]; 
    view2.center = CGPointFromString(savedCentre); 
    view2.transform = CGAffineTransformFromString(savedTransform); 

} 

Giving:

enter image description here

này gắn với những gì tôi mong chờ từ các tài liệu, trong đó tất cả biến đổi xảy ra xung quanh điểm trung tâm và do đó không bao giờ bị ảnh hưởng. Cách duy nhất tôi có thể tưởng tượng rằng bạn không thể khôi phục các mục về trạng thái trước đó của chúng là bằng cách nào đó, superview khác nhau, với biến đổi của riêng nó hoặc khung khác hoặc hoàn toàn khác. Nhưng tôi không thể nói điều đó từ câu hỏi của bạn.

Tóm lại, mã ban đầu trong câu hỏi của bạn phải hoạt động, vì vậy có điều gì đó khác đang diễn ra! Hy vọng câu trả lời này sẽ giúp bạn thu hẹp nó xuống.

+0

Tôi đã xảy ra để thử một cái gì đó tương tự: lưu biến đổi và trung tâm của xem và tải lại chúng. Điều này không di chuyển (tái tạo kết quả của bạn). Nhưng khi tôi khởi động lại ứng dụng, nó ở một nơi khác. Vì vậy, sau suy nghĩ của bạn về superview là vấn đề, có lẽ khi tôi đang đọc các ưu đãi trong khi khởi động, một số nhà nước trong superview chưa được thiết lập. Tôi sẽ đào sâu vào đó và báo cáo lại. Cám ơn rất nhiều! – sbkp

+0

Được rồi, vì vậy khi tôi tải các prefs vào, mọi thứ đều ổn. Giao diện 'bounds' của bảng giao diện người dùng là {{0, 0}, {506, 254}}. Vào cuối phương thức viewDidLoad của VC, mọi thứ vẫn ổn. Nhưng vào thời điểm mọi thứ thực sự được hiển thị, thì 'bounds' rect là một thứ khác. Ví dụ: {{0, 0}, {488.321, 435.981}}. Nếu tôi đặt lại giới hạn cho những gì nó được cho là, nó di chuyển trở lại vào vị trí. Vì vậy, thật dễ dàng để làm điều đó theo chương trình, nhưng tôi thực sự không chắc chắn khi nào để làm điều đó! Tôi đã nghĩ sẽ làm điều đó ở cuối viewDidLoad, nhưng 'bounds' vẫn chính xác tại thời điểm đó. – sbkp

+2

Hình học (khung, giới hạn, vv) không được thiết lập đầy đủ khi viewDidLoad được gọi, nhưng _is_ được đặt trước viewWillAppear. Vì vậy, đó sẽ là nơi để kiểm tra hình học và thực hiện bất kỳ điều chỉnh nào. (Tuy nhiên, thiết lập lại giới hạn mà không hiểu những gì thay đổi nó có thể có hậu quả khác.) Một mặt nạ autoresizing có thể được thay đổi khung/bounds/trung tâm trước khi xem xuất hiện. –

Các vấn đề liên quan