iOS:滑动UIView开/关屏幕 [英] iOS: Sliding UIView on/off screen

查看:137
本文介绍了iOS:滑动UIView开/关屏幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的设置

1.我在Xcode 4中使用单视图应用程序模板。

2.在xib的主/边界视图中,我添加了2个UIViews( LeftPanel和RightPanel)和一个UIButton(ShowHideButton)。

3.我为LeftPanel绿色和RightPanel蓝色着色以便于查看。

4.加载视图时,两个面板都可见,UIButton的文本为隐藏面板。

5.按下按钮后,LeftPanel应滑离屏幕(向左),RightPanel应展开以占据其原始空间以及LeftPanel腾出的空间。

6.此时,ShowHideButton应将其文本更改为显示面板。

7.再次按下按钮后,LeftPanel应该滑回屏幕(从左侧),RightPanel应缩小到将其返回原始空间。

8.此时,ShowHideButton应将其文本更改回隐藏面板。



我正在使用 animateWithDuration实现动画:动画:完成:。到目前为止,过渡 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(强,非原子)IBOutlet UIButton * ShowHideButton;

@property(强,非原子)IBOutlet UIView * LeftPanel;
@property(强,非原子)IBOutlet UIView * RightPanel;

- (IBAction)showHidePressed:(id)sender;

@end


  DrawerTestingViewController.m 
#importDrawerTestingViewController.h

@implementation DrawerTestingViewController

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

#pragma mark - 我的方法

- (IBAction)showHidePressed:(id)sender
{
switch([self CurrentState]){
case kShown:
//隐藏面板并更改按钮的文本
// 1.隐藏面板
[UIView animateWithDuration:0.5
动画:^ {
// b。将左侧面板从(0,0,w,h)移动到(-w,0,w,h)
CGRect currLeftPanelRect = [[self LeftPanel] frame];
currLeftPanelRect.origin.x = -1 * currLeftPanelRect.size.width;
[[self LeftPanel] setFrame:currLeftPanelRect];
// c。将右侧面板从(x,0,w,h)展开到(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.更改按钮的文本
[[self ShowHideButton] setTitle:@Show PanelforState:UIControlStateNormal];
// 3.翻转[self CurrentState]
[self setCurrentState:kHidden];
休息;
case kHidden:
//显示面板并更改按钮的文本
// 1.显示面板
[UIView animateWithDuration:0.5
动画:^ {
// b。将左面板从(-w,0,w,h)移动到(0,0,w,h)
CGRect currLeftPanelRect = [[self LeftPanel] frame];
currLeftPanelRect.origin.x = 0;
[[self LeftPanel] setFrame:currLeftPanelRect];
// c。将右侧面板从(0,0,w,h)展开到(leftWidth,0,w - leftWidth,h)
CGRect currRightPanelRect = [[right RightPanel] frame];
currRightPanelRect.origin.x = currLeftPanelRect.size.width;
currRightPanelRect.size.width - = currLeftPanelRect.size.width;
[[self RightPanel] setFrame:currRightPanelRect];}
completion:NULL];
// 2.更改按钮的文本
[[self ShowHideButton] setTitle:@Hide PanelforState:UIControlStateNormal];
// 3.翻转[self CurrentState]
[self setCurrentState:kShown];
休息;
默认值:
break;
}
}

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

- (void)viewWillAppear:(BOOL)动画
{
[super viewWillAppear:animated];
switch([self CurrentState]){
case kShown:
[[self ShowHideButton] setTitle:@Hide PanelforState:UIControlStateNormal];
休息;
case kHidden:
[[self ShowHideButton] setTitle:@Show PanelforState:UIControlStateNormal];
休息;
默认值:
break;
}
}

@end

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



谢谢!



编辑:
我已经尝试了两件事:

1.问题似乎与屏幕上的屏幕外视图相关,如启动使用LeftPanel屏幕外显示同样的问题。

2.可靠地逐步执行代码会导致Xcode(Lion的4 Beta)崩溃。以下是详细信息(每次崩溃都相同):



/SourceCache/DVTFoundation/DVTFoundation-867/Framework/Classes/FilePaths/DVTFilePath.m:373 $ ASSERTION FAILURE b $ b详细信息:空字符串不是有效路径
对象:
方法:+ _filePathForParent:fileSystemRepresentation:length:allowCreation:
线程:{name =(null),num = 55}
提示:无
Backtrace:
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:](in 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中)



更新:屏幕截图

面板显示(启动状态)


面板隐藏(按下按钮后成功转换)


错误:再次按下按钮导致失败





解决方案

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



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



<猜猜是什么? 工作了!



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

   - (IBAction)showHidePressed:(id)sender 
{
switch([self CurrentState]){
case kShown:
{
//隐藏面板并更改按钮的文本
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.隐藏面板
[UIView animateWithDuration:0.5
动画:^ {
// b。将左侧面板从(0,0,w,h)移动到(-w,0,w,h)
[[self LeftPanel] setFrame:currLeftPanelRect];
// c。将右侧面板从(x,0,w,h)展开到(0,0,w + x,h)
[[self RightPanel] setFrame:currRightPanelRect];
}
完成:^(BOOL完成){if(已完成){
[[self ShowHideButton] setTitle:@Show PanelforState:UIControlStateNormal];
[self setCurrentState:kHidden];
}
}];
}
休息;
case kHidden:
{
//显示面板并更改按钮的文本
// 1.显示面板
[UIView animateWithDuration:0.5
动画:^ {
// b。将左面板从(-w,0,w,h)移动到(0,0,w,h)
CGRect currLeftPanelRect = [[self LeftPanel] frame];
currLeftPanelRect.origin.x + = currLeftPanelRect.size.width / 2;
[[self LeftPanel] setFrame:currLeftPanelRect];
// c。将右侧面板从(0,0,w,h)展开到(leftWidth,0,w - leftWidth,h)
CGRect currRightPanelRect = [[right RightPanel] frame];
currRightPanelRect.origin.x = currLeftPanelRect.size.width;
currRightPanelRect.size.width - = currLeftPanelRect.size.width;
[[self RightPanel] setFrame:currRightPanelRect];
}
完成:^(BOOL完成){if(已完成){
[[self ShowHideButton] setTitle:@Hide PanelforState:UIControlStateNormal];
[self setCurrentState:kShown];
}
}];
}
休息;
默认值:
break;
}
}


I'm working on an app where having a "drawer" on the left-hand side would be very beneficial. I'm doing some initial testing to see how I would best accomplish this, and I'm having some very basic trouble.

My Setup
1. I am using a single-view application template in Xcode 4.
2. To the xib's "main/border" view, I've added 2 UIViews (LeftPanel and RightPanel) and a UIButton (ShowHideButton).
3. I've colored the LeftPanel green and the RightPanel blue for easier visibility.
4. When the view is loaded, both panels are visible and the UIButton has the text "Hide Panel".
5. Upon pressing the button, LeftPanel should slide off the screen (to the left) and RightPanel should expand to take up its original space plus the space vacated by LeftPanel.
6. At this point, ShowHideButton should change its text to "Show Panel".
7. Upon pressing the button again, LeftPanel should slide back onto the screen (from the left) and RightPanel should shrink to "give it back" its original space.
8. At this point, ShowHideButton should change its text back to "Hide Panel".

I'm implementing the animation using animateWithDuration:animations:completion:. So far, the transition OFF the screen is working fine (very well, actually).

What's troubling me is that when I then try to bring LeftPanel "back", I'm getting an EXC_BAD_ACCESS. I've posted my code below, and I've looked at it, but I really can't see what I'm accessing that's been released (or whatever is causing the 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

Am I missing something super-basic? Can anybody help?

Thanks!

Edit: I've tried 2 more things:
1. The problem seems to be related to bringing the off-screen view on-screen, as starting with LeftPanel off-screen gives me the same problem.
2. Stepping through the code reliably causes Xcode (4 Beta for Lion) to crash. Here are the details (same for every crash):

ASSERTION FAILURE in /SourceCache/DVTFoundation/DVTFoundation-867/Framework/Classes/FilePaths/DVTFilePath.m:373 Details: empty string is not a valid path Object: Method: +_filePathForParent:fileSystemRepresentation:length:allowCreation: Thread: {name = (null), num = 55} Hints: None Backtrace: 0 0x00000001068719a6 -[IDEAssertionHandler handleFailureInMethod:object:fileName:lineNumber:messageFormat:arguments:] (in IDEKit) 1 0x0000000105f3e324 _DVTAssertionFailureHandler (in DVTFoundation) 2 0x0000000105edd16f +[DVTFilePath _filePathForParent:fileSystemRepresentation:length:allowCreation:] (in DVTFoundation) 3 0x0000000105edcd4d +[DVTFilePath _filePathForParent:pathString:] (in DVTFoundation) 4 0x0000000105ede141 +[DVTFilePath filePathForPathString:] (in DVTFoundation) 5 0x00000001064a8dde -[IDEIndex queryProviderForFile:highPriority:] (in IDEFoundation) 6 0x000000010655193b -[IDEIndex(IDEIndexQueries) symbolsMatchingName:inContext:withCurrentFileContentDictionary:] (in IDEFoundation) 7 0x000000010aca6166 __68-[IDESourceCodeEditor symbolsForExpression:inQueue:completionBlock:]_block_invoke_01561 (in IDESourceEditor) 8 0x00007fff93fb490a _dispatch_call_block_and_release (in libdispatch.dylib) 9 0x00007fff93fb615a _dispatch_queue_drain (in libdispatch.dylib) 10 0x00007fff93fb5fb6 _dispatch_queue_invoke (in libdispatch.dylib) 11 0x00007fff93fb57b0 _dispatch_worker_thread2 (in libdispatch.dylib) 12 0x00007fff8bb5e3da _pthread_wqthread (in libsystem_c.dylib) 13 0x00007fff8bb5fb85 start_wqthread (in libsystem_c.dylib)

Update: Screen Shots
Panel Shown (startup state)
Panel Hidden (successful transition after button press)
Error: Pressing button again causes failure


解决方案

After playing around with this a bunch and banging my head against the wall, I finally came to the conclusion that my code wasn't wrong unless I misunderstood something about blocks. Stepping through my code in debug yielded answers exactly like I expected, but between the end of the animation block and the beginning of the completion block, an EXC_BAD_ACCESS kept popping up.

Anyway, I'm not sure where I got the idea, but I figured I might want to try doing my mathematical calculations (for changing the frames) outside of my animation block.

Guess what? IT WORKED!

So, without further ado, here's the working code for what I wanted:

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

这篇关于iOS:滑动UIView开/关屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆