最近のUIはどんどん進化していまして、
clearのUIなんかは大好きなんですが、使い道が無いので残念です。
Android 2.xのアプリでも、android-support-packageを使用して、
FragmentとViewPagerを利用し、横にスワイプして画面遷移するUIが増えてきました。
iPhoneでもGoogle+やらmixiが実装していますので、
どうやるのかざっくりと検証してみましたら、
UIScrollVIew
と
UIPageControl
を使用する事で実装可能でしたので、
コードを紹介します。
参考:wannabegeek / PageViewController
再生するとこんな感じ
こちらのソースコードはGitHubに公開しました。
iPhoneでページ送りを実装するソースコード公開
今回作成するアプリは、1つのRootViewController(PagerViewController)に、
UIScrollViewとUIPageControlがあり、
UIScrollViewに
Document1ViewController
Document2ViewController
Document3ViewController
のviewを表示するように実装します。
InterfaceBuilderでUIScrollViewとUIPageControlを適当に配置したと仮定し、
下記コードで実装していきます。
PagerViewController.m
/**
* @author dommy <shonan.shachu at gmail.com>
* @version 1.0.0 updated on 2012-04-25
*/
#import "PagerViewController.h"
@interface PagerViewController ()
@property (assign) BOOL pageControlUsed;
@property (assign) NSUInteger page;
@property (assign) BOOL rotating;
- (void)loadScrollViewWithPage:(int)page;
@end
@implementation PagerViewController
@synthesize scrollView;
@synthesize pageControl;
@synthesize pageControlUsed = _pageControlUsed;
@synthesize page = _page;
@synthesize rotating = _rotating;
// UIViewControllerの配列を保存しておくNSMutableArray
@synthesize controllers;
// UIViewController
@synthesize controller1, controller2, controller3;
- (void)viewDidLoad
{
[super viewDidLoad];
// ベースとなるscrollViewの設定を決める
[self.scrollView setPagingEnabled:YES];
[self.scrollView setScrollEnabled:YES];
[self.scrollView setShowsHorizontalScrollIndicator:NO];
[self.scrollView setShowsVerticalScrollIndicator:NO];
[self.scrollView setDelegate:self];
// UIVIewControllerの初期化をする
controller1 = [[Document1ViewController alloc] initWithNibName:@"Document1ViewController" bundle:nil];
controller2 = [[Document1ViewController alloc] initWithNibName:@"Document2ViewController" bundle:nil];
controller3 = [[Document1ViewController alloc] initWithNibName:@"Document3ViewController" bundle:nil];
// UIViewControllerを保存する配列の設定
controllers = [[NSMutableArray alloc] initWithObjects:controller1, controller2, controller3, nil];
}
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
[viewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
_rotating = YES;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
[viewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [controllers count], scrollView.frame.size.height);
NSUInteger page = 0;
for (viewController in controllers) {
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
viewController.view.frame = frame;
page++;
}
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * _page;
frame.origin.y = 0;
[self.scrollView scrollRectToVisible:frame animated:NO];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
_rotating = NO;
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
[viewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (NSUInteger i =0; i < [controllers count]; i++) {
[self loadScrollViewWithPage:i];
}
self.pageControl.currentPage = 0;
_page = 0;
[self.pageControl setNumberOfPages:[controllers count]];
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewWillAppear:animated];
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [controllers count], scrollView.frame.size.height);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewDidAppear:animated];
}
}
- (void)viewWillDisappear:(BOOL)animated {
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewWillDisappear:animated];
}
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
UIViewController *viewController = [controllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewDidDisappear:animated];
}
[super viewDidDisappear:animated];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0)
return;
if (page >= [controllers count])
return;
// replace the placeholder if necessary
UIViewController *controller = [controllers objectAtIndex:page];
if (controller == nil) {
return;
}
// add the controller's view to the scroll view
if (controller.view.superview == nil) {
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[self.scrollView addSubview:controller.view];
}
}
- (IBAction)changePage:(id)sender {
int page = ((UIPageControl *)sender).currentPage;
// update the scroll view to the appropriate page
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
UIViewController *oldViewController = [controllers objectAtIndex:_page];
UIViewController *newViewController = [controllers objectAtIndex:self.pageControl.currentPage];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
[self.scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
_pageControlUsed = YES;
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
UIViewController *oldViewController = [controllers objectAtIndex:_page];
UIViewController *newViewController = [controllers objectAtIndex:self.pageControl.currentPage];
[oldViewController viewDidDisappear:YES];
[newViewController viewDidAppear:YES];
_page = self.pageControl.currentPage;
}
#pragma mark -
#pragma mark UIScrollViewDelegate methods
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (_pageControlUsed || _rotating) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
if (self.pageControl.currentPage != page) {
UIViewController *oldViewController = [controllers objectAtIndex:self.pageControl.currentPage];
UIViewController *newViewController = [controllers objectAtIndex:page];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
self.pageControl.currentPage = page;
[oldViewController viewDidDisappear:YES];
[newViewController viewDidAppear:YES];
_page = page;
}
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
_pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
_pageControlUsed = NO;
}
参照先はstoryboardを使っていますので、
iOS4系向けにInterface Builderで作り変えています。
self.childViewControllersは使わず、NSMutableArrayにcontrollerを記録し、
そちらを参照しております。
これはiOS4系向けの実装になります。
0 件のコメント:
コメントを投稿