使用UIViewAnimationTransitionFlipFromRight在按下时翻转UIButton并在“另一侧”显示一个新按钮

时间:2013-03-04 22:20:00

标签: ios uiview uibutton uiviewanimation uiviewanimationtransition

为MOXY编辑。

我有一组按钮,顶部有一个图像,按钮阵列的视图是背景颜色。当我点击一个按钮我想要检索该按钮索引并使用该索引也获得另一个视图的相应背景颜色..并使用该信息翻转按钮(带图像)和“翻转”到揭示背景色。

我的屏幕组成是,ViewControllersView-> TileView->(按钮数组)。

 -(void)viewDidAppear:(BOOL)animated{
 _viewContents = [model getRequestedView];  //this retrieves an array of UIButtons(24 
  //of them) whose frames and background colors have already been initialized to fit
   //within the TileView.
 _viewFrontImageContents =[model getRequestedViewFrontCardImagesWithFrame:_viewContents];

for(int screenViewIndex = 0; screenViewIndex < [_viewContents count]; screenViewIndex++){
    [TileView addSubview:[_viewFrontImageContents objectAtIndex:screenViewIndex]];
    [[_viewFrontImageContents objectAtIndex:screenViewIndex] addTarget:self action:@selector(frontOfCardPushed:) forControlEvents:UIControlEventTouchUpInside];
    //[TileView addSubview:[_viewContents objectAtIndex:screenViewIndex]];
    //[[_viewContents objectAtIndex:screenViewIndex] addTarget:self action:@selector(frontOfCardPushed:) forControlEvents:UIControlEventTouchUpInside];
}

}

// getRequestedViewFrontCardImagesWithFrame方法

-(NSMutableArray *)getRequestedViewFrontCardImagesWithFrame:(NSArray *)views{
        NSMutableArray *cards = [[NSMutableArray alloc] init];
        UIImage *frontOfCardImage = [UIImage imageNamed:@"Back_of_Tile"];
        UIButton *frontOfCardView;

        for(int viewIndex = 0; viewIndex < [views count]; viewIndex++){
            frontOfCardView = [[UIButton alloc] initWithFrame:[[views objectAtIndex:viewIndex] frame]];
            frontOfCardView.backgroundColor = [UIColor colorWithPatternImage:frontOfCardImage];
  //setting the tag of each frontCard to match the view index to keep them aligned.
            frontOfCardView.tag = viewIndex;
            [cards addObject:frontOfCardView];

            if(viewIndex == 0){
              NSLog(@"first frontcard frame %@, first _viewContentsFrame %@", [cards objectAtIndex:0], [views objectAtIndex:0]);
    }
        }
        return cards;
    }

上面我添加的UIButtons顶部有一个图像来代表“扑克牌的正面”。所述按钮的索引完全匹配_viewContents数组的indeces。我设置每个按钮以匹配已经初始化的按钮的框架(大小和位置)。

-(IBAction)frontOfCardPushed:(id)sender{
int containerViewIndex = -1;
UIButton *pressedButton = (UIButton *)sender;
NSLog(@"Button Index: %i", pressedButton.tag);
containerViewIndex = pressedButton.tag;
UIView *container = [TileView viewWithTag:containerViewIndex];
UIView *viewToShow = [_viewContents objectAtIndex:containerViewIndex];
NSLog(@"container: %@, viewToShow: %@", container, viewToShow);
//viewToShow.frame = container.frame;
//NSLog(@"container: %@, viewToShow: %@", container, viewToShow);

[UIView transitionWithView:container duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight
                animations:^{
                    [sender removeFromSuperview];
                    [container addSubview:viewToShow];
                }
                completion:nil];

我想要做的是使用转换 - 即“UIViewAnimationTransitionFlipFromRight”来按下“翻转卡片”以显示相关_viewContents数组的内容。我还希望能够让用户翻转卡片以显示frontCardButton的图像。上面的这段代码只关注卡片的第一次翻转以避免代码墙。

我看到了合适的背景颜色 - 但动画本身无效。

我做错了什么,我需要添加/删除这段代码才能使其正常工作?

  • 编辑* 如下面Moxy所述,请查看getRequestedViewFrontCardImagesWithFrame方法中的输出结果。查看第一张卡片的输出,然后在请求具有相应标签的视图后查看frontCardPushed:方法中容器视图的输出 - 它们不匹配。我打印出按钮索引,以便您可以看到我正在访问第一个TileView子视图。 _viewContents视图的标记是表示颜色的标记集,与我在getRequestedViewFrontCardImagesWithFrame方法中指定的TileView标记无关。然而令人费解的是,当我将标签打印出来时,我将标签分配给第一个按钮后,标签未列出。

输出:

//why doesnt the first frontcard frame list a tag? I had just assigned it one?
  

第一个前卡帧UIButton:0x1c53f020; frame =(6 5; 145 145);   opaque = NO; layer = CALayer:0x1c534ac0,首先是_viewContentsFrame   UIButton:0x1d045220; frame =(6 5; 145 145); opaque = NO; tag = 3;   layer = CALayer:0x1d04535

     

按钮索引:0
  容器:UIView:0x1c53a400; frame =(51 83; 922   614); clipsToBounds = YES; autoresize = W + H; gestureRecognizers =   NSArray:0x1d05afe0&gt ;; layer = CALayer:0x1c53a460,viewToShow:   UIButton:0x1d045220; frame =(6 5; 145 145); opaque = NO; tag = 3;   layer = CALayer:0x1d045350

2 个答案:

答案 0 :(得分:3)

更简单的方法是使用[UIView transitionWithView]:

[UIView transitionWithView:self.flipButton
                  duration:0.8
                   options:displayingFirstButton ? UIViewAnimationOptionTransitionFlipFromLeft : UIViewAnimationOptionTransitionFlipFromRight
                animations:^{
                  //change image for button
                }
                completion:^(BOOL finished) {

                }];

答案 1 :(得分:2)

您可以使用容器视图来保持按钮。

-(void)viewDidAppear:(BOOL)animated
{
    _viewContents = [model getRequestedView];  //this retrieves an array of UIButtons(24 of them) whose frames and background colors have already been initialized to fit within the TileView.

    for(int i = 0; i < [_viewContents count]; i++){
        UIView *container = [[UIView alloc] initWithFrame:[[_viewContents objectAtIndex:screenViewIndex] frame]]; 
        container.tag = i;      
        UIButton *frontOfCardView = [[UIButton alloc] initWithFrame:container.bounds];
        frontOfCardView.backgroundColor = [UIColor colorWithPatternImage:_frontOfCardImage];
        frontOfCardView.tag = i;
        [container addSubview:frontOfCardView]; 
        [frontOfCardView addTarget:self action:@selector(frontOfCardPushed:) forControlEvents:UIControlEventTouchUpInside];
        [tileView addSubview:container];
    }
}

-(IBAction)frontOfCardPushed:(UIButton *)sender
{
    UIView *container = [tileView viewWithTag:sender.tag];
    UIView *viewToShow = [_viewContents objectAtIndex:index];
    viewToShow.frame = sender.frame;
    [UIView transitionWithView:container
                      duration:0.5
                       options:UIViewAnimationOptionTransitionFlipFromRight
                    animations:^{
                      [sender removeFromSuperView];
                      [container addSubview:viewToShow];
                    }
                    completion:nil];
}

我没有测试过,但应该可以使用。无论如何,这不是很干净/漂亮的代码。但是,我知道这只是为了学习目的。

如果它仍然不起作用,请告诉我。

编辑:

我以一个视图控制器为例做了一个简单的项目。我认为你跟踪所有视图/按钮的方式是没用的。在这种情况下,模型只是一种背景颜色,你想要做的只是显示/隐藏它,所以一旦你将颜色分配给按钮,它只需要知道切换状态,所以你甚至不需要(在其他情况下,控制器需要识别接收事件的按钮,以便询问模型所需的内容)

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) NSArray *colors;
@property (nonatomic, strong) UIView *tileView;
@end

@implementation ViewController

#pragma mark -
#pragma Getters and setters

// I'm assuming the tileView is just a simple view to wrap all the buttons
// PS : propertys should always start with a lowercase letter
-(UIView *)tileView
{
    if (!_tileView) {
        _tileView = [[UIView alloc] initWithFrame:self.view.bounds];
        _tileView.backgroundColor = [UIColor greenColor];
    }
    return _tileView;
}

// The model: just an array of colors, you can generate it or use other complicated stuff
-(NSArray *)colors
{
    if (!_colors) {
        _colors = @[[UIColor blackColor], [UIColor redColor], [UIColor grayColor], [UIColor yellowColor],
                    [UIColor whiteColor], [UIColor blueColor], [UIColor orangeColor], [UIColor darkGrayColor],
                    [UIColor lightGrayColor], [UIColor cyanColor], [UIColor brownColor], [UIColor magentaColor],
                    [UIColor blackColor], [UIColor redColor], [UIColor grayColor], [UIColor yellowColor],
                    [UIColor whiteColor], [UIColor blueColor], [UIColor orangeColor], [UIColor darkGrayColor],
                    [UIColor lightGrayColor], [UIColor cyanColor], [UIColor brownColor], [UIColor magentaColor]];
    }
    return _colors;
}

#pragma mark -
#pragma mark Helper methods

#define ROWS 6
#define COLUMNS 4
#define CARD_HEIGHT 60.0f
#define CARD_WIDTH 40.0f

// Gets the width that each card can use based on the chose number of columns
-(CGFloat)horizontalStep
{
    return self.tileView.frame.size.width / COLUMNS;
}

// Gets the height that each card can use based on the chose number of columns
-(CGFloat)verticalStep
{
    return self.tileView.frame.size.height / ROWS;
}

// Calculates the center for the card frame (return (0,0) if the index is out of bounds)
-(CGPoint)centerForCardAtIndex:(NSUInteger)index
{
    CGFloat x = 0.0f, y = 0.0f;
    if (index < [self.colors count]) {
        x = [self horizontalStep] * 0.5f + (index % COLUMNS) * [self horizontalStep];
        y = [self verticalStep] * 0.5f + (index / COLUMNS) * [self verticalStep];
    }
    return CGPointMake(x, y);
}

// Gets the frame for the card at index
-(CGRect)frameForCardAtIndex:(NSUInteger)index
{
    CGPoint center = [self centerForCardAtIndex:index];
    CGPoint origin = CGPointMake(center.x - CARD_WIDTH * 0.5f, center.y - CARD_HEIGHT * 0.5f);
    return CGRectMake(origin.x, origin.y, CARD_WIDTH, CARD_HEIGHT);
}

-(void)layoutCards
{
    // Add tileView to the controller's view
    [self.view addSubview:self.tileView];
    // Create the card buttons and add them to the tile view
    for (int i = 0; i < [self.colors count]; i++) {
        UIButton *card = [UIButton buttonWithType:UIButtonTypeCustom];
        card.frame = [self frameForCardAtIndex:i];

        // The only use of the model IN THIS CASE
        card.backgroundColor = self.colors[i];
        [card setImage:[UIImage imageNamed:@"back_of_tile.png"]
              forState:UIControlStateNormal];

        [card addTarget:self
                 action:@selector(cardPressed:)
       forControlEvents:UIControlEventTouchUpInside];

        [self.tileView addSubview:card];
    }
}

-(void)cardPressed:(UIButton *)card
{
    [UIView transitionWithView:card
                      duration:0.5
                       options:UIViewAnimationOptionTransitionFlipFromRight
                    animations:^{
                        card.selected = !card.selected;
                        if (!card.selected) {
                            [card setImage:[UIImage imageNamed:@"back_of_tile.png"]
                                  forState:UIControlStateNormal];
                        } else {
                            [card setImage:nil
                                  forState:UIControlStateNormal];
                        }
                    }
                    completion:nil];
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self layoutCards];
}