如何在 UIScrollView 中的对象(UIViews)上执行翻转动画
Posted
技术标签:
【中文标题】如何在 UIScrollView 中的对象(UIViews)上执行翻转动画【英文标题】:How to perform a flip animation on objects (UIViews) in a UIScrollView 【发布时间】:2012-06-29 19:30:40 【问题描述】:我正在将可变数量的对象(卡片)加载到UIScrollView
中。每张卡片都是从数组中的对象以编程方式创建的。这个想法是,用户将点击一张卡片,它会翻转表明它已完成。当我将对象(卡片)加载到UIScrollView
时,只有最后一张卡片会翻转。轻触其他任何一张牌都会翻转最后一张牌。
我怀疑我需要提供一个指向我想要翻转的对象(卡片)的指针,但我不确定该怎么做。我尝试将标签分配给被点击但没有走远的按钮。如何定位UIScrollView
中的特定对象以对其执行操作?
这是我目前的代码:
// create a cardScrollView
// if there are not cards for the schedule, display the no cards message.
// if there are cards then create the scroller, add the cards, and then add to screen.
if (cardCount == 0)
NSLog(@"There are no cards available");
// place a label on screen that tells user there are no cards on the schedule. with animation.
// *** TODO: this will eventually be a better graphical message. ***
UILabel *noScheduleMsg = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 240, 50)];
noScheduleMsg.backgroundColor = [UIColor clearColor];
[noScheduleMsg setText:@"Opps! It doesn't look like there are picture cards on this schedule!"];
[noScheduleMsg setLineBreakMode:UILineBreakModeCharacterWrap];
noScheduleMsg.numberOfLines = 2;
[noScheduleView addSubview:noScheduleMsg];
// animate the view onto the screen
[UIView animateWithDuration:.3 animations:^
noScheduleView.alpha = 1.0;
];
else
NSLog(@"Display schedule cards");
// check to see if there is a cardview first.
if (!cardView)
// TODO: check for the last known completed card and show the following card in line.
//create UIView that the scroller will go into.
cardView = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 320, 250)];
//set cardView properties
cardView.backgroundColor = [UIColor clearColor];
//make sure I hide the cardview so that animation to full alpha is completed. Add to main view.
cardView.alpha = 0.0;
[self.view addSubview:cardView];
//create the cardViewScroller. this is where all the cards will be placed.
cardScroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
cardScroller.backgroundColor = [UIColor clearColor];
cardScroller.alwaysBounceVertical = NO;
cardScroller.pagingEnabled = YES;
cardScroller.showsVerticalScrollIndicator = NO;
cardScroller.showsHorizontalScrollIndicator = NO;
cardScroller.scrollEnabled = YES;
int cardscrollWidth = 120;
cardScroller.contentSize = CGSizeMake(cardscrollWidth,80);
//iterate over the scheduleCards array and load each object into a view
NSMutableArray *cards = [[NSMutableArray alloc] initWithArray:[selectedSchedule scheduleCards]];
// this is to create the picture cards. itterate over each object and display in the cardScroller
for (int i = 0; i < cardCount; i++)
// TODO:
// create the front of the card and put in a UIView object
// create the back of the card and put in a UIView object.
// Add a clear button to each isComplete to each card that is complete. if selected then show the backside of the card.
// Add the flip logic
// tie reset button to clear all isComplete values on the cards.
// pull the right cards from the array at each index
Cards *theCard = [cards objectAtIndex:i];
UIButton *frontBtn = [[UIButton alloc] init];
[frontBtn setFrame:CGRectMake(35, 0, 250, 250)];
frontBtn.backgroundColor = [UIColor clearColor];
[frontBtn setTag:i];
[frontBtn addTarget:self action:@selector(changeTaskStatus:) forControlEvents:UIControlEventTouchUpInside];
//set card border
UIImageView *pcImageViewBg = [[UIImageView alloc] initWithFrame:CGRectMake(35, 0, 250, 250)];
UIImage *bgimg = [UIImage imageNamed:@"bigCardbg@2x"];
[pcImageViewBg setImage:bgimg];
// set card image
UIImageView *pcImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 230, 230)];
NSString *ik = [theCard imageKey];
if (ik)
//get the image key from the store
UIImage *imageToDisplay = [[ScheduleImageStore sharedStore] imageForKey:ik];
// use that image to display in the view
[pcImageView setImage:imageToDisplay];
else
//set default image.
[pcImageView setImage:[UIImage imageNamed:@"card"]];
// this is the front of the card.
frontCard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 255, 255)];
// back of the card (done state)
//backCard = [[UIView alloc] initWithFrame:CGRectMake(35, 0, 255, 255)];
//[backCard addSubview:frontBtn];
//backCard.backgroundColor = [UIColor redColor];
// UIview for the flip (container)
CGRect frame;
frame.origin.x = cardScroller.frame.size.width * i - 1;
frame.origin.y = 0;
frame.size = cardScroller.frame.size;
theCardFlipView = [[UIView alloc] initWithFrame:frame];
//theCardFlipView.backgroundColor = [UIColor greenColor];
// add the card views to the interface.
[pcImageViewBg addSubview:pcImageView];
[frontCard addSubview:pcImageViewBg];
[frontCard addSubview:frontBtn];
// this is the container holding the frontcard and backcard
// I need to target the appropriate 'theCardFlipView'
[theCardFlipView addSubview:frontCard];
[cardScroller addSubview:theCardFlipView];
NSLog(@"%i",frontBtn.tag);
// set the contentsize of the scroller dynamically. it's based on how many cards there are in the schedule.
cardScroller.contentSize = CGSizeMake(cardScroller.frame.size.width * cardCount, cardScroller.frame.size.height);
//add scroller to card view.
[cardView addSubview:cardScroller];
// animate the cardview into view from transparent to opaque.
[UIView animateWithDuration:.3 animations:^
cardView.alpha = 1.0;
completion: ^ (BOOL finished)
// if I want something to happen after loading the cardView, I could put it here.
];
这是我基于按钮按下的方法:
-(void)changeTaskStatus:(UIButton *)sender
NSLog(@"button tag: %@",[sender tag]);
if(toggleIsOn)
//NSLog(@"incomplete card");
[UIView transitionWithView:theCardFlipView
duration:0.8
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionCurveEaseInOut
animations:^
[[[theCardFlipView subviews] objectAtIndex:0] removeFromSuperview],
[theCardFlipView addSubview:frontCard];
completion:^(BOOL finished)
NSLog(@"card complete");
];
else
//NSLog(@"complete card");
[UIView transitionWithView:theCardFlipView
duration:0.8
options:UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionCurveEaseInOut
animations:^
[[[theCardFlipView subviews] objectAtIndex:0] removeFromSuperview],
[theCardFlipView addSubview:frontCard];
completion:^(BOOL finished)
//NSLog(@"front card tag: %i",frontBtn.tag);
NSLog(@"card not complete");
];
toggleIsOn = !toggleIsOn;
有什么建议吗?我觉得这也是非常笨拙的代码,因此欢迎提出任何建议。
【问题讨论】:
【参考方案1】:在创建卡片视图的循环中,在底部添加:
theCardFlipView.tag = i + 100; // since you're already using i for those button tags
100 是一个任意常数,只要没有其他人使用这些标签(并且只要您没有超过 99 张卡片),它就可以了。
然后,当您处理按钮按下时,将其放在最开始。
thecardFlipView = [cardScrollerView viewWithTag:sender.tag + 100];
您现在拥有的代码为按钮提供了一个标签,而不是您想要翻转的实际视图。您正在使用 theCardFlipView 而不将其更改为您想要翻转的内容(它只是保持分配给循环中的最后一张卡片)。
综上所述,您实际上可以在不制作按钮的情况下执行此操作,您只需要处理滚动视图上的点击手势并找到哪张卡片位于点击点。
编辑:
您使用的切换开关 (toggleIsOn
) 看起来也不是特定于卡片的,因此您最终会出现不正确的翻转行为。您应该跟踪哪些牌被翻转,哪些没有,并检查。如果您的卡片是 UIView 子类的实例,您可以在其中添加一个标志,否则您可能需要维护另一个包含该信息的数组。
【讨论】:
谢谢迪玛。这就是我需要的。奥吉的回答也让我想到我正在以错误的方式解决这个问题,因此我将尝试重构并使其更易于维护。再次感谢! @brandon 你能和我分享代码吗,因为我在这里也想做同样的事情。【参考方案2】:Dima 的回答应该可以解决您的问题。
创建一个包含前 ui 视图和后 uiview 的卡片类,并在 init 语句中设置子视图,再加上一个翻转方法将有助于实现这一点。
【讨论】:
以上是关于如何在 UIScrollView 中的对象(UIViews)上执行翻转动画的主要内容,如果未能解决你的问题,请参考以下文章
UIScrollView 的子视图应该如何报告它们的 contentSize 范围?
如何在 UIScrollView 中的对象(UIViews)上执行翻转动画
如何在垂直 UIScrollView 中显示文本和其他对象?