iOS:滑动UIView开/关屏幕

时间:2011-07-29 15:05:23

标签: ios panel slide slidingdrawer drawer

我正在开发一个应用程序,左侧有一个“抽屉”非常有用。我正在做一些初步测试,看看我最好能做到这一点,而且我遇到了一些非常基本的问题。

我的设置
1.我在Xcode 4中使用单视图应用程序模板。
2.在xib的“主/边界”视图中,我添加了2个UIViews(LeftPanel和RightPanel)和一个UIButton(ShowHideButton)。
我为LeftPanel绿色和RightPanel蓝色着色,以便更容易看到。
4.加载视图时,两个面板都可见,UIButton的文本为“隐藏面板”。
5.按下按钮后,LeftPanel应滑离屏幕(向左),RightPanel应展开以占据其原始空间加上LeftPanel腾出的空间。
6.此时,ShowHideButton应将其文本更改为“显示面板”。
7.再次按下按钮后,LeftPanel应向后滑动到屏幕上(从左侧),RightPanel应缩小到“将其返回”原始空间。
8.此时,ShowHideButton应将其文本更改回“隐藏面板”。

我正在使用animateWithDuration:animations:completion:实现动画。到目前为止,过渡 OFF 屏幕工作正常(实际上非​​常好)。

令我不安的是,当我尝试将LeftPanel“带回”时,我得到了一个EXC_BAD_ACCESS。我已经在下面发布了我的代码,我已经看了它,但我真的看不到我正在访问的内容(或者是导致EXC_BAD_ACCESS的任何内容)。

DrawerTestingViewController.h
#import <UIKit/UIKit.h>

typedef enum {
    kHidden,
    kShown
} PanelState;

@interface DrawerTestingViewController : UIViewController {

    PanelState   currentState;

    UIButton    *showHideButton;

    UIView      *leftPanel;
    UIView      *rightPanel;
}

@property (assign, nonatomic)          PanelState   CurrentState;

@property (strong, nonatomic) IBOutlet UIButton     *ShowHideButton;

@property (strong, nonatomic) IBOutlet UIView       *LeftPanel;
@property (strong, nonatomic) IBOutlet UIView       *RightPanel;

- (IBAction)showHidePressed:(id)sender;

@end


DrawerTestingViewController.m
#import "DrawerTestingViewController.h"

@implementation DrawerTestingViewController

@synthesize CurrentState    = currentState;
@synthesize LeftPanel       = leftPanel;
@synthesize RightPanel      = rightPanel;
@synthesize ShowHideButton  = showHideButton;

#pragma mark - My Methods

- (IBAction)showHidePressed:(id)sender
{
    switch ([self CurrentState]) {
        case kShown:
            // Hide the panel and change the button's text
            // 1. Hide the panel
            [UIView animateWithDuration:0.5 
                animations:^{
                // b. Move left panel from (0, 0, w, h) to (-w, 0, w, h)
                CGRect currLeftPanelRect = [[self LeftPanel] frame];
                currLeftPanelRect.origin.x = -1 * currLeftPanelRect.size.width;
                [[self LeftPanel] setFrame:currLeftPanelRect];
                // c. Expand right panel from (x, 0, w, h) to (0, 0, w + x, h)
                CGRect currRightPanelRect = [[self RightPanel] frame];
                currRightPanelRect.origin.x = 0;
                currRightPanelRect.size.width += currLeftPanelRect.size.width;
                [[self RightPanel] setFrame:currRightPanelRect];}
                completion:NULL];
            // 2. Change the button's text
            [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
            // 3. Flip [self CurrentState]
            [self setCurrentState:kHidden];
            break;
        case kHidden:
            // Show the panel and change the button's text
            // 1. Show the panel
            [UIView animateWithDuration:0.5 
                animations:^{
                // b. Move left panel from (-w, 0, w, h) to (0, 0, w, h)
                CGRect currLeftPanelRect = [[self LeftPanel] frame];
                currLeftPanelRect.origin.x = 0;
                [[self LeftPanel] setFrame:currLeftPanelRect];
                // c. Expand right panel from (0, 0, w, h) to (leftWidth, 0, w - leftWidth, h)
                CGRect currRightPanelRect = [[self RightPanel] frame];
                currRightPanelRect.origin.x = currLeftPanelRect.size.width;
                currRightPanelRect.size.width -= currLeftPanelRect.size.width;
                [[self RightPanel] setFrame:currRightPanelRect];}
                completion:NULL];
            // 2. Change the button's text
            [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
            // 3. Flip [self CurrentState]
            [self setCurrentState:kShown];
            break;
        default:
            break;
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setCurrentState:kShown];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    switch ([self CurrentState]) {
        case kShown:
            [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
            break;
        case kHidden:
            [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
            break;
        default:
            break;
    }
}

@end

我错过了一些超级基本的东西吗?有人可以帮忙吗?

谢谢!

修改: 我还尝试了两件事:
1.问题似乎与在屏幕上显示屏幕外视图有关,因为从屏幕上的LeftPanel开始给出了同样的问题。
2.可靠地单步执行代码会导致Xcode(Lion for 4 Beta)崩溃。以下是详细信息(每次崩溃都相同):

/SourceCache/DVTFoundation/DVTFoundation-867/Framework/Classes/FilePaths/DVTFilePath.m:373中的ASSERTION FAILURE 详细信息:空字符串不是有效路径 宾语: 方法:+ _filePathForParent:fileSystemRepresentation:length:allowCreation: 线程:{name =(null),num = 55} 提示:无 回溯:   0 0x00000001068719a6 - [IDEAssertionHandler handleFailureInMethod:object:fileName:lineNumber:messageFormat:arguments:](在IDEKit中)   1 0x0000000105f3e324 _DVTAssertionFailureHandler(在DVTFoundation中)   2 0x0000000105edd16f + [DVTFilePath _filePathForParent:fileSystemRepresentation:length:allowCreation:](在DVTFoundation中)   3 0x0000000105edcd4d + [DVTFilePath _filePathForParent:pathString:](在DVTFoundation中)   4 0x0000000105ede141 + [DVTFilePath filePathForPathString:](在DVTFoundation中)   5 0x00000001064a8dde - [IDEIndex queryProviderForFile:highPriority:](在IDEFoundation中)   6 0x000000010655193b - [IDEIndex(IDEIndexQueries)symbolsMatchingName:inContext:withCurrentFileContentDictionary:](在IDEFoundation中)   7 0x000000010aca6166 __68- [IDESourceCodeEditor symbolsForExpression:inQueue:completionBlock:] _ block_invoke_01561(在IDESourceEditor中)   8 0x00007fff93fb490a _dispatch_call_block_and_release(在libdispatch.dylib中)   9 0x00007fff93fb615a _dispatch_queue_drain(在libdispatch.dylib中)  10 0x00007fff93fb5fb6 _dispatch_queue_invoke(在libdispatch.dylib中)  11 0x00007fff93fb57b0 _dispatch_worker_thread2(在libdispatch.dylib中)  12 0x00007fff8bb5e3da _pthread_wqthread(在libsystem_c.dylib中)  13 0x00007fff8bb5fb85 start_wqthread(在libsystem_c.dylib中)

更新:屏幕截图
面板显示(启动状态) Panel Shown
面板隐藏(按下按钮后成功转换) Panel Hidden
错误:再次按下按钮会导致失败 Error


2 个答案:

答案 0 :(得分:11)

在玩了这一堆并将我的头撞在墙上后,我终于得出结论,我的代码没有错,除非我误解了一些关于块的东西。在调试中单步执行我的代码会产生与我预期完全相同的答案,但在动画块结束和完成块开始之间,EXC_BAD_ACCESS会不断弹出。

无论如何,我不确定我的想法在哪里,但我想我可能想尝试在动画块之外进行数学计算(用于更改帧)。

猜猜是什么? IT WorkED!

所以,不用多说了,这是我想要的工作代码:

- (IBAction)showHidePressed:(id)sender
{
    switch ([self CurrentState]) {
        case kShown:
        {
            // Hide the panel and change the button's text
            CGRect currLeftPanelRect = [[self LeftPanel] frame];
            currLeftPanelRect.origin.x -= currLeftPanelRect.size.width / 2;
            CGRect currRightPanelRect = [[self RightPanel] frame];
            currRightPanelRect.origin.x = 0;
            currRightPanelRect.size.width += currLeftPanelRect.size.width;
            // 1. Hide the panel
            [UIView animateWithDuration:0.5 
              animations:^{
              // b. Move left panel from (0, 0, w, h) to (-w, 0, w, h)
              [[self LeftPanel] setFrame:currLeftPanelRect];
              // c. Expand right panel from (x, 0, w, h) to (0, 0, w + x, h)
              [[self RightPanel] setFrame:currRightPanelRect];
              }
              completion:^(BOOL finished){ if(finished) {
              [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
              [self setCurrentState:kHidden];
              }
              }];
        }            
            break;
        case kHidden:
        {
            // Show the panel and change the button's text
            // 1. Show the panel
            [UIView animateWithDuration:0.5 
              animations:^{
              // b. Move left panel from (-w, 0, w, h) to (0, 0, w, h)
              CGRect currLeftPanelRect = [[self LeftPanel] frame];
              currLeftPanelRect.origin.x += currLeftPanelRect.size.width / 2;
              [[self LeftPanel] setFrame:currLeftPanelRect];
              // c. Expand right panel from (0, 0, w, h) to (leftWidth, 0, w - leftWidth, h)
              CGRect currRightPanelRect = [[self RightPanel] frame];
              currRightPanelRect.origin.x = currLeftPanelRect.size.width;
              currRightPanelRect.size.width -= currLeftPanelRect.size.width;
              [[self RightPanel] setFrame:currRightPanelRect];
              }
              completion:^(BOOL finished){ if(finished) {
              [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
              [self setCurrentState:kShown];
              }
              }];
        }
            break;
        default:
            break;
    }
}

答案 1 :(得分:0)

我认为你的崩溃与UIKit的不确定状态问题有关,只要你把主线程置于负载或处于视图转换的中间。当您检索数学计算的值时,您在动画块中与块外部,它们是访问UIView模型的不同上下文,因此在动画上下文中您不会感到惊讶,在这种情况下您会收到内存错误。