【问题标题】:iOS: Sliding UIView on/off screeniOS:滑动 UIView 开/关屏幕
【发布时间】:2011-07-29 15:05:22
【问题描述】:

我正在开发一个应用程序,在该应用程序的左侧有一个“抽屉”会非常有益。我正在做一些初步测试,看看我将如何最好地完成此任务,但我遇到了一些非常基本的问题。

我的设置
1. 我在 Xcode 4 中使用单视图应用程序模板。
2. 在 xib 的“主/边框”视图中,我添加了 2 个 UIView(LeftPanel 和 RightPanel)和一个 UIButton(ShowHideButton)。
3. 为了便于查看,我将 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

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

谢谢!

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

/SourceCache/DVTFoundation/DVTFoundation-867/Framework/Classes/FilePaths/DVTFilePath.m:373 中的断言失败 详细信息:空字符串不是有效路径 目的: 方法:+_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 中)

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


【问题讨论】:

    标签: ios panel slide slidingdrawer drawer


    【解决方案1】:

    在玩了一大堆并将我的头撞到墙上之后,我终于得出结论,我的代码没有错误,除非我误解了关于块的某些内容。在调试中逐步执行我的代码得到的答案与我预期的完全一样,但是在动画块的结尾和完成块的开头之间,不断弹出 EXC_BAD_ACCESS。

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

    你猜怎么着? 成功了!

    所以,事不宜迟,这是我想要的工作代码:

    - (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;
        }
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-24
        相关资源
        最近更新 更多