2010-05-10 34 views
16

Trên iPad, người ta có thể hiển thị UIActionSheet bằng cách sử dụng -showFromBarButtonItem: hoạt hình :. Điều này thuận tiện vì nó bao bọc một UIPopoverController xung quanh trang tính hành động và nó trỏ mũi tên của cửa sổ bật lên tới UIBarButtonItem được truyền vào.Truy cập UIPopoverController cho UIActionSheet trên iPad

Tuy nhiên, cuộc gọi này thêm thanh công cụ UIBarButtomItem vào danh sách các lần xem vượt qua - không phải luôn luôn mong muốn. Và, không có con trỏ tới UIPopoverController, người ta không thể thêm các khung nhìn khác vào danh sách passthrough.

Có ai biết cách tiếp cận bị xử phạt để đưa con trỏ đến bộ điều khiển bật lên không?

Xin cảm ơn trước.

Trả lời

2

Tôi không nghĩ điều đó khả thi. Tôi đang ngồi với cùng một vấn đề.

Sử dụng

- (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated 

Ví dụ:

[actionSheet showFromRect:[[[myToolBar subviews] objectAtIndex:0] frame] inView:myToolBar animated:YES]; 

Lưu ý: Bạn phải thay đổi các chỉ số cho objectAtIndex: để phù hợp với tình hình của bạn và có tham chiếu đến ToolBar của bạn

+0

Điều đó có hiệu quả thông qua thay đổi định hướng không? Hay bạn cần điều chỉnh các sự kiện xoay vòng? Cảm ơn. – westsider

10

Bạn sẽ cần phải điều chỉnh về sự thay đổi định hướng.

Tôi đã tìm thấy giải pháp thay thế, hoạt động hoàn hảo cho tôi.

Stick để

- (void)showFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated 

Trong @ interface của bạn thêm

UIActionSheet *popoverActionsheet; 

cũng thêm

@property (nonatomic, retain) UIActionSheet *popoverActionsheet; 

cũng thêm

- (IBAction)barButtonItemAction:(id)sender; 

Vì vậy, bạn có tham chiếu đến actionheet của bạn từ bất cứ nơi nào trong việc thực hiện của bạn.

trong việc thực hiện của bạn

- (IBAction) barButtonItemAction:(id)sender 
{ 
    //If the actionsheet is visible it is dismissed, if it not visible a new one is created. 
    if ([popoverActionsheet isVisible]) { 
     [popoverActionsheet dismissWithClickedButtonIndex:[popoverActionsheet cancelButtonIndex] 
                animated:YES]; 
     return; 
    } 

    popoverActionsheet = [[UIActionSheet alloc] initWithTitle:nil 
                delegate:self 
              cancelButtonTitle:nil 
             destructiveButtonTitle:nil 
         otherButtonTitles:@"Save Page", @"View in Safari", nil]; 

    [popoverActionsheet showFromBarButtonItem:sender animated:YES]; 
} 

trong đoàn actionsheet của bạn thực hiện

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex 
{ 

    if (buttonIndex == [actionSheet cancelButtonIndex]) return; 

    //add rest of the code for other button indeces 
} 

và đừng quên để phát hành popoverActionsheet trong

- (void)dealloc 

Tôi tin rằng điều này sẽ làm.

+1

Stalinkay, cảm ơn. Những gì bạn mô tả là gần với những gì tôi đang làm bây giờ. Tôi phải cụ thể hơn. Tôi có bảng tác vụ được hiển thị từ một nút trong thanh công cụ ở cuối màn hình. Tôi cũng có một thanh điều hướng trên đầu màn hình. Tôi muốn các nút trong thanh điều hướng hoạt động giống nhau (đối với trang tác vụ) dưới dạng các nút trên thanh công cụ. Nói cách khác, tôi muốn các nút nav bar nằm trong danh sách passthrough của cửa sổ pop-action của hành động - và để có các nút bấm trong các nút trên thanh điều hướng * cả * loại bỏ hành động sheet * và * nút xử lý sự kiện. Đây là lý do tại sao nhận con trỏ đến cửa sổ bật lên là quan trọng. – westsider

4

tôi nghi ngờ có một cách tiếp cận xử phạt này kể từ actionsheets được thể hiện trong UIPopoverViews được liên kết với một UIViewController không phải là một UIPopoverController

NSLog(@"%@",[[[popoverActionsheet superview] superview] passthroughViews]); 

Nhìn qua các tập tin tiêu đề UIPopoverView (không có giấy tờ) sản lượng các giải pháp sau đây mặc dù không có giấy tờ.Nghi ngờ bạn có thể snick rằng quá khứ App Reviewers nhưng cung cấp cho nó một đi nếu bạn nghĩ rằng nó có giá trị một shot.

http://github.com/kennytm/iphone-private-frameworks/blob/master/UIKit/UIPopoverView.h

NSArray *passthroughViews = [[[popoverActionsheet superview] superview] passthroughViews]; 

     NSMutableArray *views = [passthroughViews mutableCopy]; 
     [views addObject:[self view]]; 
     [[[popoverActionsheet superview] superview] setPassthroughViews:views]; 
     [views release]; 
+0

Tôi nghĩ rằng đây là những gì tôi đang tìm kiếm - ở một mức độ nào đó. Đó là, rõ ràng, mong manh đến mức Apple có thể thay đổi cách thực hiện cơ bản bằng cách nói thêm một lớp khung nhìn khác, v.v. Tôi muốn viết phiên bản của riêng mình bằng popover. Khi tôi nhận được xung quanh đó, tôi sẽ đăng mã ở đây. Cảm ơn, một lần nữa! – westsider

+0

Tuyệt vời. Muốn xem những gì bạn nghĩ ra. – stalinkay

1

Khi trình bày từ một mục nút thanh, bạn thường muốn vô hiệu hóa tất cả các nút khác trên thanh công cụ của bạn cho đến khi tờ hành động sa thải.

Tôi nghĩ cách đơn giản nhất để thực hiện việc này là sửa đổi lớp UIToolbar. Bạn sẽ cần một cách để giữ các actionheet, có lẽ bằng cách lưu nó trong ứng dụng đại biểu.

Tạo một file UIToolbar + Modal.m, như thế này:

@implementation UIToolbar (Modal) 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    UIView *hitView = [super hitTest:point withEvent:event]; 

    UIActionSheet *mySheet = [[[UIApplication sharedApplication] delegate] myActionSheet]; 
    if ([mySheet isVisible]) return nil; 
    else return hitView; 
} 

@end 

File .h không cần phải chứa bất cứ điều gì đặc biệt

@interface UIToolbar (Modal) { 
} 
@end 

Bằng cách này, trước khi tìm giải pháp này Tôi đã thử gán một mảng trống cho passthroughViews, rằng bạn có thể truy cập như (ban đầu) được mô tả bởi stalinkay, nhưng điều này không thực sự làm việc (ngoài việc không có giấy tờ). Các cách khác để làm điều này tất cả đều có nhược điểm - hoặc là bạn phải xử lý các thay đổi định hướng, hoặc các nút trên thanh công cụ trông giống như chúng nhấn xuống khi thực tế hành động duy nhất được thực hiện là loại bỏ các actionheet.

CẬP NHẬT

Tính năng iOS 4.3 này không còn hoạt động nữa. Bạn cần phải phân lớp:

UIToolbarWithModal.h

#import <Foundation/Foundation.h> 

@interface UIToolbarWithModal : UIToolbar { 
} 

@end 

nhớ rằng khi bạn tạo ra các tấm hành động mà bạn cần để giữ cho nó dễ tiếp cận, có lẽ trong đại biểu ứng dụng của bạn - trong ví dụ này trong tài sản myActionSheet.

UIToolbarWithModal.m

#import "UIToolbarWithModal.h" 
#import "MyDelegate.h" 

@implementation UIToolbarWithModal 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    UIView *hitView = [super hitTest:point withEvent:event]; 

    UIActionSheet *mySheet = [[[UIApplication sharedApplication] delegate] myActionSheet]; 
    if ([mySheet isVisible]) return nil; 
    else return hitView; 
} 

@end 

Sau đó, chỉ cần sử dụng UIToolbarWithModal trong mã của bạn, nơi bạn có thể đã sử dụng UIToolbar trước.

9
if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) { 
     [[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil]; 
    } 

Sẽ thực hiện thủ thuật, điều này sẽ không gây ra bất kỳ sự cố nào với Người đánh giá ứng dụng vì không gọi bất kỳ API riêng tư nào.

Rất mong manh - các câu lệnh if đảm bảo mã của bạn sẽ không bị lỗi (không hoạt động) trong trường hợp không chắc Apple thay đổi cài đặt cơ bản.

+0

Đây là một giải pháp tốt. Tôi tự hỏi tại sao Apple lại thêm thanh vào các cuộc phỏng vấn ở nơi đầu tiên. – DrMickeyLauer

+0

Điều này không hiệu quả đối với tôi trên iOS 6. Trình điều khiển cửa sổ không nằm trong chuỗi phản hồi. –

+1

Làm việc tuyệt vời cho tôi trên iOS 6! Nó phải được gọi sau khi bảng hành động được trình bày. – ToddH

2

Đây là giải pháp. Tôi mới phát hiện ra nó và nó rất dễ dàng. Đặt userInteractionEnabled thành NO trước khi hiển thị trang hành động và đặt nó thành YES ở cuối phương thức ủy nhiệm của trang hành động của bạn để loại bỏ.

- (void)promptResetDefaults:(id)sender 
{ 
    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil 
                  delegate:self 
                cancelButtonTitle:nil 
               destructiveButtonTitle:NSLocalizedString(@"Reset All Defaults", nil) 
                otherButtonTitles:nil]; 

    self.navigationController.navigationBar.userInteractionEnabled = NO; 
    [actionSheet showFromBarButtonItem:sender animated:YES]; 
} 

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex 
{ 
    if (buttonIndex == actionSheet.destructiveButtonIndex) 
    { 
     [self.dataDefaults resetDataDefaults]; 
     [self.tableView reloadData]; 
    } 

    self.navigationController.navigationBar.userInteractionEnabled = YES; 
} 
+0

Giải pháp rất tốt (thậm chí có thể là giải pháp tốt nhất ở đây). Tôi không biết tại sao mọi người không upvote này. – Byte

2

Tôi đã sử dụng câu trả lời nbransby cho một vài năm, nhưng điều đó không còn hoạt động trong iOS 8. Tuy nhiên, vấn đề vẫn còn tồn tại với mới UIAlertController trong iOS 8.Đây là bản cập nhật phù hợp với tôi:

UIAlertController *actionSheet = [UIAlertController 
    alertControllerWithTitle:@"Test" 
    message:@"Hello, world!" 
    preferredStyle:UIAlertControllerStyleActionSheet]; 
[actionSheet addAction:[UIAlertAction 
    actionWithTitle:@"OK" 
    style:UIAlertActionStyleDefault 
    handler:^(UIAlertAction *action) {}]]; 
actionSheet.modalPresentationStyle = UIModalPresentationPopover; 
actionSheet.popoverPresentationController.barButtonItem = testButton; 
[self presentViewController:actionSheet animated:TRUE completion:^(void) { 
    actionSheet.popoverPresentationController.passthroughViews = [NSArray array]; 
}]; 

Lưu ý rằng passthroughXem được đặt sau khi cửa sổ bật lên xuất hiện, nhưng bạn có thể sử dụng khối hoàn thành để thực hiện điều đó một cách thuận tiện.

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