मैं आईओएस में एक संक्रमण एनीमेशन बनाने की कोशिश कर रहा हूं जहां पूरी स्क्रीन भरने के लिए एक व्यू या व्यू कंट्रोलर विस्तारित प्रतीत होता है, फिर पूरा होने पर उसकी पिछली स्थिति पर वापस अनुबंध करें। मुझे यकीन नहीं है कि इस प्रकार के संक्रमण को आधिकारिक तौर पर किस प्रकार बुलाया जाता है, लेकिन आप आईपैड के लिए यूट्यूब ऐप में एक उदाहरण देख सकते हैं। जब आप ग्रिड पर खोज परिणाम थंबनेल में से किसी एक को टैप करते हैं, तो यह थंबनेल से फैलता है, फिर जब आप खोज पर वापस आते हैं तो थंबनेल में वापस अनुबंध करते हैं।आईओएस पर विचारों के बीच मैं विस्तार/अनुबंध संक्रमण कैसे कर सकता हूं?
मैं इस के दो पहलुओं में दिलचस्पी रखता हूँ:
कैसे जब एक दूसरे को देखने और के बीच संक्रमण आप इस प्रभाव होगा? दूसरे शब्दों में, यदि ए को स्क्रीन के कुछ क्षेत्र को ले जाता है, तो आप बी को देखने के लिए इसे कैसे परिवर्तित करेंगे, जो पूरी स्क्रीन लेता है, और इसके विपरीत?
इस तरह आप एक मोडल व्यू में कैसे बदलाव करेंगे? दूसरे शब्दों में, यदि UIViewController C वर्तमान में दिखा रहा है और इसमें दृश्य डी शामिल है जो स्क्रीन का हिस्सा लेता है, तो आप इसे कैसे देखते हैं जैसे डी डी UIViewController E में बदल रहा है जिसे सी के शीर्ष पर सामान्य रूप से प्रस्तुत किया जाता है?
संपादित करें: मैं अगर है कि इस सवाल का अधिक प्यार हो जाता है देखने के लिए एक इनाम जोड़ रहा।
संपादित करें: मुझे कुछ स्रोत कोड मिला है जो यह करता है, और एनोमी का विचार कुछ परिशोधन के साथ एक आकर्षण की तरह काम करता है। मैंने पहली बार मोडल कंट्रोलर के दृश्य (ई) को एनिमेट करने का प्रयास किया था, लेकिन यह महसूस करने का असर नहीं हुआ कि आप स्क्रीन में ज़ूम कर रहे हैं, क्योंकि यह थंबनेल व्यू (सी) में सभी चीजों का विस्तार नहीं कर रहा था। तो फिर मैंने मूल नियंत्रक के दृश्य (सी) को एनिमेट करने का प्रयास किया, लेकिन इसे झटकेदार एनीमेशन के लिए बनाया गया, और पृष्ठभूमि बनावट जैसी चीजें ठीक से ज़ूम नहीं हुईं। तो मैं जो कर रहा हूं वह मूल दृश्य नियंत्रक (सी) की छवि ले रहा है और मॉड्यूल व्यू (ई) के अंदर ज़ूम कर रहा है। यह विधि मेरे मूल की तुलना में काफी जटिल है, लेकिन यह अच्छा लग रहा है! मुझे लगता है कि आईओएस को इसके आंतरिक संक्रमण भी करना चाहिए। वैसे भी, यह कोड है, जिसे मैंने UIViewController पर एक श्रेणी के रूप में लिखा है।
UIViewController + Transitions.h:
#import <Foundation/Foundation.h>
@interface UIViewController (Transitions)
// make a transition that looks like a modal view
// is expanding from a subview
- (void)expandView:(UIView *)sourceView
toModalViewController:(UIViewController *)modalViewController;
// make a transition that looks like the current modal view
// is shrinking into a subview
- (void)dismissModalViewControllerToView:(UIView *)view;
@end
UIViewController + Transitions.m:
#import "UIViewController+Transitions.h"
...
- (void)userDidTapThumbnail {
DetailViewController *detail =
[[DetailViewController alloc]
initWithNibName:nil bundle:nil];
[self expandView:thumbnailView toModalViewController:detail];
[detail release];
}
- (void)dismissModalViewControllerAnimated:(BOOL)animated {
if (([self.modalViewController isKindOfClass:[DetailViewController class]]) &&
(animated)) {
[self dismissModalViewControllerToView:thumbnailView];
}
else {
[super dismissModalViewControllerAnimated:animated];
}
}
:
#import "UIViewController+Transitions.h"
@implementation UIViewController (Transitions)
// capture a screen-sized image of the receiver
- (UIImageView *)imageViewFromScreen {
// make a bitmap copy of the screen
UIGraphicsBeginImageContextWithOptions(
[UIScreen mainScreen].bounds.size, YES,
[UIScreen mainScreen].scale);
// get the root layer
CALayer *layer = self.view.layer;
while(layer.superlayer) {
layer = layer.superlayer;
}
// render it into the bitmap
[layer renderInContext:UIGraphicsGetCurrentContext()];
// get the image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// close the context
UIGraphicsEndImageContext();
// make a view for the image
UIImageView *imageView =
[[[UIImageView alloc] initWithImage:image]
autorelease];
return(imageView);
}
// make a transform that causes the given subview to fill the screen
// (when applied to an image of the screen)
- (CATransform3D)transformToFillScreenWithSubview:(UIView *)sourceView {
// get the root view
UIView *rootView = sourceView;
while (rootView.superview) rootView = rootView.superview;
// convert the source view's center and size into the coordinate
// system of the root view
CGRect sourceRect = [sourceView convertRect:sourceView.bounds toView:rootView];
CGPoint sourceCenter = CGPointMake(
CGRectGetMidX(sourceRect), CGRectGetMidY(sourceRect));
CGSize sourceSize = sourceRect.size;
// get the size and position we're expanding it to
CGRect screenBounds = [UIScreen mainScreen].bounds;
CGPoint targetCenter = CGPointMake(
CGRectGetMidX(screenBounds),
CGRectGetMidY(screenBounds));
CGSize targetSize = screenBounds.size;
// scale so that the view fills the screen
CATransform3D t = CATransform3DIdentity;
CGFloat sourceAspect = sourceSize.width/sourceSize.height;
CGFloat targetAspect = targetSize.width/targetSize.height;
CGFloat scale = 1.0;
if (sourceAspect > targetAspect)
scale = targetSize.width/sourceSize.width;
else
scale = targetSize.height/sourceSize.height;
t = CATransform3DScale(t, scale, scale, 1.0);
// compensate for the status bar in the screen image
CGFloat statusBarAdjustment =
(([UIApplication sharedApplication].statusBarFrame.size.height/2.0)
/scale);
// transform to center the view
t = CATransform3DTranslate(t,
(targetCenter.x - sourceCenter.x),
(targetCenter.y - sourceCenter.y) + statusBarAdjustment,
0.0);
return(t);
}
- (void)expandView:(UIView *)sourceView
toModalViewController:(UIViewController *)modalViewController {
// get an image of the screen
UIImageView *imageView = [self imageViewFromScreen];
// insert it into the modal view's hierarchy
[self presentModalViewController:modalViewController animated:NO];
UIView *rootView = modalViewController.view;
while (rootView.superview) rootView = rootView.superview;
[rootView addSubview:imageView];
// make a transform that makes the source view fill the screen
CATransform3D t = [self transformToFillScreenWithSubview:sourceView];
// animate the transform
[UIView animateWithDuration:0.4
animations:^(void) {
imageView.layer.transform = t;
} completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
}
- (void)dismissModalViewControllerToView:(UIView *)view {
// take a snapshot of the current screen
UIImageView *imageView = [self imageViewFromScreen];
// insert it into the root view
UIView *rootView = self.view;
while (rootView.superview) rootView = rootView.superview;
[rootView addSubview:imageView];
// make the subview initially fill the screen
imageView.layer.transform = [self transformToFillScreenWithSubview:view];
// remove the modal view
[self dismissModalViewControllerAnimated:NO];
// animate the screen shrinking back to normal
[UIView animateWithDuration:0.4
animations:^(void) {
imageView.layer.transform = CATransform3DIdentity;
}
completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
}
@end
आप इसे एक UIViewController उपवर्ग में कुछ इस तरह इस्तेमाल कर सकते हैं संपादित करें: अच्छा, यह पता चला है कि नहीं करता है पोर्ट्रेट के अलावा इंटरफेस उन्मुखता वास्तव में संभाल नहीं है। इसलिए मुझे रोटेशन के साथ पास करने के लिए व्यू कंट्रोलर का उपयोग करके UIWindow में संक्रमण को एनिमेट करने के लिए स्विच करना पड़ा।
UIViewController + Transitions.m:
@interface ContainerViewController : UIViewController { }
@end
@implementation ContainerViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation {
return(YES);
}
@end
...
// get the screen size, compensating for orientation
- (CGSize)screenSize {
// get the size of the screen (swapping dimensions for other orientations)
CGSize size = [UIScreen mainScreen].bounds.size;
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
CGFloat width = size.width;
size.width = size.height;
size.height = width;
}
return(size);
}
// capture a screen-sized image of the receiver
- (UIImageView *)imageViewFromScreen {
// get the root layer
CALayer *layer = self.view.layer;
while(layer.superlayer) {
layer = layer.superlayer;
}
// get the size of the bitmap
CGSize size = [self screenSize];
// make a bitmap to copy the screen into
UIGraphicsBeginImageContextWithOptions(
size, YES,
[UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
// compensate for orientation
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
CGContextTranslateCTM(context, size.width, 0);
CGContextRotateCTM(context, M_PI_2);
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
CGContextTranslateCTM(context, 0, size.height);
CGContextRotateCTM(context, - M_PI_2);
}
else if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
CGContextTranslateCTM(context, size.width, size.height);
CGContextRotateCTM(context, M_PI);
}
// render the layer into the bitmap
[layer renderInContext:context];
// get the image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// close the context
UIGraphicsEndImageContext();
// make a view for the image
UIImageView *imageView =
[[[UIImageView alloc] initWithImage:image]
autorelease];
// done
return(imageView);
}
// make a transform that causes the given subview to fill the screen
// (when applied to an image of the screen)
- (CATransform3D)transformToFillScreenWithSubview:(UIView *)sourceView
includeStatusBar:(BOOL)includeStatusBar {
// get the root view
UIView *rootView = sourceView;
while (rootView.superview) rootView = rootView.superview;
// by default, zoom from the view's bounds
CGRect sourceRect = sourceView.bounds;
// convert the source view's center and size into the coordinate
// system of the root view
sourceRect = [sourceView convertRect:sourceRect toView:rootView];
CGPoint sourceCenter = CGPointMake(
CGRectGetMidX(sourceRect), CGRectGetMidY(sourceRect));
CGSize sourceSize = sourceRect.size;
// get the size and position we're expanding it to
CGSize targetSize = [self screenSize];
CGPoint targetCenter = CGPointMake(
targetSize.width/2.0,
targetSize.height/2.0);
// scale so that the view fills the screen
CATransform3D t = CATransform3DIdentity;
CGFloat sourceAspect = sourceSize.width/sourceSize.height;
CGFloat targetAspect = targetSize.width/targetSize.height;
CGFloat scale = 1.0;
if (sourceAspect > targetAspect)
scale = targetSize.width/sourceSize.width;
else
scale = targetSize.height/sourceSize.height;
t = CATransform3DScale(t, scale, scale, 1.0);
// compensate for the status bar in the screen image
CGFloat statusBarAdjustment = includeStatusBar ?
(([UIApplication sharedApplication].statusBarFrame.size.height/2.0)
/scale) : 0.0;
// transform to center the view
t = CATransform3DTranslate(t,
(targetCenter.x - sourceCenter.x),
(targetCenter.y - sourceCenter.y) + statusBarAdjustment,
0.0);
return(t);
}
- (void)expandView:(UIView *)sourceView
toModalViewController:(UIViewController *)modalViewController {
// get an image of the screen
UIImageView *imageView = [self imageViewFromScreen];
// show the modal view
[self presentModalViewController:modalViewController animated:NO];
// make a window to display the transition on top of everything else
UIWindow *window =
[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.hidden = NO;
window.backgroundColor = [UIColor blackColor];
// make a view controller to display the image in
ContainerViewController *vc = [[ContainerViewController alloc] init];
vc.wantsFullScreenLayout = YES;
// show the window
[window setRootViewController:vc];
[window makeKeyAndVisible];
// add the image to the window
[vc.view addSubview:imageView];
// make a transform that makes the source view fill the screen
CATransform3D t = [self
transformToFillScreenWithSubview:sourceView
includeStatusBar:(! modalViewController.wantsFullScreenLayout)];
// animate the transform
[UIView animateWithDuration:0.4
animations:^(void) {
imageView.layer.transform = t;
} completion:^(BOOL finished) {
// we're going to crossfade, so change the background to clear
window.backgroundColor = [UIColor clearColor];
// do a little crossfade
[UIView animateWithDuration:0.25
animations:^(void) {
imageView.alpha = 0.0;
}
completion:^(BOOL finished) {
window.hidden = YES;
[window release];
[vc release];
}];
}];
}
- (void)dismissModalViewControllerToView:(UIView *)view {
// temporarily remove the modal dialog so we can get an accurate screenshot
// with orientation applied
UIViewController *modalViewController = [self.modalViewController retain];
[self dismissModalViewControllerAnimated:NO];
// capture the screen
UIImageView *imageView = [self imageViewFromScreen];
// put the modal view controller back
[self presentModalViewController:modalViewController animated:NO];
[modalViewController release];
// make a window to display the transition on top of everything else
UIWindow *window =
[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.hidden = NO;
window.backgroundColor = [UIColor clearColor];
// make a view controller to display the image in
ContainerViewController *vc = [[ContainerViewController alloc] init];
vc.wantsFullScreenLayout = YES;
// show the window
[window setRootViewController:vc];
[window makeKeyAndVisible];
// add the image to the window
[vc.view addSubview:imageView];
// make the subview initially fill the screen
imageView.layer.transform = [self
transformToFillScreenWithSubview:view
includeStatusBar:(! self.modalViewController.wantsFullScreenLayout)];
// animate a little crossfade
imageView.alpha = 0.0;
[UIView animateWithDuration:0.15
animations:^(void) {
imageView.alpha = 1.0;
}
completion:^(BOOL finished) {
// remove the modal view
[self dismissModalViewControllerAnimated:NO];
// set the background so the real screen won't show through
window.backgroundColor = [UIColor blackColor];
// animate the screen shrinking back to normal
[UIView animateWithDuration:0.4
animations:^(void) {
imageView.layer.transform = CATransform3DIdentity;
}
completion:^(BOOL finished) {
// hide the transition stuff
window.hidden = YES;
[window release];
[vc release];
}];
}];
}
वाह नीचे और अधिक जटिल संस्करण मिलते हैं! लेकिन अब यह किसी भी प्रतिबंधित एपीआई का उपयोग किए बिना ऐप्पल के संस्करण की तरह दिखता है। साथ ही, यह मोडल व्यू के सामने होने पर अभिविन्यास बदलता है, भले ही यह काम करता है।
धन्यवाद। मैं अस्पष्ट हूं कि हम भाग 2 में एनिमेटिंग करेंगे। क्या यह मोडल व्यू कंट्रोलर के दृश्य को सामान्य रूप से प्रस्तुत करने से पहले एनिमेट करना संभव है? इस मामले में इसे वर्तमान में देखने वाले व्यू कंट्रोलर के सबव्यूव के रूप में जोड़ा जाना होगा, है ना? मुझे इसके लिए कुछ स्रोत कोड देखने में बहुत दिलचस्पी होगी। –
@ जेसे क्रॉसन: # 2 में पहली बार, आप कुछ दृश्य एनिमेट कर रहे होंगे जो मोडल व्यू कंट्रोलर के दृश्य की तरह दिखता है। कैलियर के 'रेंडरइन कॉन्टेक्स्ट:' का उपयोग करके बनाया गया सिर्फ "स्क्रीनशॉट" हो सकता है। दूसरी तरफ, आप सीधे व्यू कंट्रोलर के दृश्य में हेरफेर करेंगे। – Anomie
स्पष्टीकरण के लिए धन्यवाद! मैंने पाया है कि व्यू कंट्रोलर के गैर-मानक हेरफेर अभ्यास में कांटेदार हो सकते हैं, इसलिए मैंने स्रोत कोड के बारे में पूछा।मैं देखता हूं कि यह कैसे काम करता है और आपको बताता है। –