私はチュートリアルを作成していますが、Pathのチュートリアルのスタイルを次のようにエミュレートしようとしています。
http://www.appcoda.com/wp-content/uploads/2013/06/UIPageViewController-Tutorial-Screen.jpg
私の問題は、デリゲートメソッドを次のように設定すると:
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
return 5;
}
次に、ドットの下にこの愚かな黒いバーが表示されます。
http://i.stack.imgur.com/pUEdh.png
UINavigationBarを半透明に設定するのと同様の方法で、このバーを半透明にする方法はありますか?
動作させるのはとても簡単です。必要なことは、pageviewcontrollerをより高くし、PageControlをXIBファイルに配置するだけです。このトリックは、PageControlを最初にフォアグラウンド(および他のすべての共通コントロール)に配置し、PageViewControllerでPageControlのコンテンツを更新します。コードは次のとおりです。
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
// We need to cover all the control by making the frame taller (+ 37)
[[self.pageController view] setFrame:CGRectMake(0, 0, [[self view] bounds].size.width, [[self view] bounds].size.height + 37)];
TutorialPageViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
// Bring the common controls to the foreground (they were hidden since the frame is taller)
[self.view bringSubviewToFront:self.pcDots];
[self.view bringSubviewToFront:self.btnSkip];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(TutorialPageViewController *)viewController index];
[self.pcDots setCurrentPage:index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(TutorialPageViewController *)viewController index];
[self.pcDots setCurrentPage:index];
index++;
if (index == 3) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (TutorialPageViewController *)viewControllerAtIndex:(NSUInteger)index {
TutorialPageViewController *childViewController = [[TutorialPageViewController alloc] initWithNibName:@"TutorialPageViewController" bundle:nil];
childViewController.index = index;
return childViewController;
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
NSInteger tutorialSteps = 3;
[self.pcDots setNumberOfPages:tutorialSteps];
return tutorialSteps;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return 0;
}
次のようにUIPageViewControllerをサブクラス化し、viewDidLayoutSubviewsをオーバーライドするだけで、同じ効果を実現できます。
-(void)viewDidLayoutSubviews {
UIView* v = self.view;
NSArray* subviews = v.subviews;
// Confirm that the view has the exact expected structure.
// If you add any custom subviews, you will want to remove this check.
if( [subviews count] == 2 ) {
UIScrollView* sv = nil;
UIPageControl* pc = nil;
for( UIView* t in subviews ) {
if( [t isKindOfClass:[UIScrollView class]] ) {
sv = (UIScrollView*)t;
} else if( [t isKindOfClass:[UIPageControl class]] ) {
pc = (UIPageControl*)t;
}
}
if( sv != nil && pc != nil ) {
// expand scroll view to fit entire view
sv.frame = v.bounds;
// put page control in front
[v bringSubviewToFront:pc];
}
}
[super viewDidLayoutSubviews];
}
その後、個別のUIPageControlなどを維持する必要はありません。
Swift 3スニペット
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let scrollView = view.subviews.filter({ $0 is UIScrollView }).first,
let pageControl = view.subviews.filter({ $0 is UIPageControl }).first {
scrollView.frame = view.bounds
view.bringSubview(toFront:pageControl)
}
}
ZerotoolのソリューションをSwift 2.1に変換しますが、おそらくもっとエレガントな書き方があります:
override func viewDidLayoutSubviews() {
var scrollView: UIScrollView?
var pageControl: UIPageControl?
// If you add any custom subviews, you will want to remove this check.
if (self.view.subviews.count == 2) {
for view in self.view.subviews {
if (view.isKindOfClass(UIScrollView)) {
scrollView = view as? UIScrollView
} else if (view.isKindOfClass(UIPageControl)) {
pageControl = view as? UIPageControl
}
}
}
if let scrollView = scrollView {
if let pageControl = pageControl {
scrollView.frame = self.view.bounds
self.view.bringSubviewToFront(pageControl)
}
}
super.viewDidLayoutSubviews()
}
UIPageViewControllerの動作を変更できるとは思わないので、Pathアプリは独自のView Controllerを使用しているようです。同じことを行うことができます。UIPageControlを使用して現在のページを示す独自のコンテナービューコントローラーを作成します。
今日見つけた小さなハック..
以下のコードをご覧ください。
self.pageController.dataSource = self;
CGRect rect = [self.view bounds];
rect.size.height+=37;
[[self.pageController view] setFrame:rect];
NSArray *subviews = self.pageController.view.subviews;
UIPageControl *thisControl = nil;
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isKindOfClass:[UIPageControl class]]) {
thisControl = (UIPageControl *)[subviews objectAtIndex:i];
}
}
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(0, -30, 320, 40)];
[tempview addSubview:thisControl];
thisControl.pageIndicatorTintColor = [UIColor lightGrayColor];
thisControl.currentPageIndicatorTintColor = [UIColor greenColor];
[self.view addSubview:tempview];
UIPageViewControllerのUIPageControlのアルファを単純に調整できます。
まず、次のようにUIPageViewControllerから取得する必要があります。
- (UIPageControl *)getPageControlForPageViewController:(UIPageViewController *)pageViewController {
for (UIView *subview in self.pageViewController.view.subviews) {
if ([subview isKindOfClass:[UIPageControl class]]) {
return (UIPageControl *) subview;
}
}
return nil;
}
次に、関数を使用します。 ViewControllerにchildPageControlというプロパティを作成しました。 UIPageViewControllerのUIPageControlを指定します。
self.childPageControl = [self getPageControlForPageViewController:self.pageViewController];
次に、アルファを調整して半透明の効果を与えることができます。
self.childPageControl.alpha = .5;
UIPageViewControllerのUIPageControlに影響を与えるためにできることは非常に限られていますが、少なくとも少しの労力でこれを達成できます。
私はこのコードを使用して解決します:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.namesImage = @[@"page1.png", @"page2.png", @"page3.png", @"page4.png"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
self.pageViewController.dataSource = self;
TutorialContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
[[UIPageControl appearance] setPageIndicatorTintColor:[UIColor grayColor]];
[[UIPageControl appearance] setCurrentPageIndicatorTintColor:[UIColor whiteColor]];
[[UIPageControl appearance] setBackgroundColor: [[UIColor blackColor] colorWithAlphaComponent:0.1f]];
[[UIPageControl appearance] setOpaque:YES];
}
作業していたアプリで同様の効果を実現したかった-UIPageViewControllerと別のUIPageControlを使用しました。
これにより、UIPageViewControllerの上部など、ビュー内の任意の場所にUIPageControlを配置できます。また、UIPageViewControllerデリゲートメソッドを使用して、アクティブページのドットを最新の状態に保ちます。
- (void)pageViewController:(UIPageViewController *)pageViewController
didFinishAnimating:(BOOL)finished
previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers
transitionCompleted:(BOOL)completed {
if (completed) {
self.pageControl.currentPage = [self.pageViewControllers indexOfObject:pageViewController.viewControllers.firstObject];
}
}
内部UIPageViewControllerページコントロールを見つけようとしてサブビュー階層をトラバースする必要も、内部スクロールビューのコンテンツのサイズを変更する必要もありません。
お役に立てれば。
このコードはSwift UIPageViewControllerに以下を追加
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for view in self.view.subviews {
if view.isKindOfClass(UIScrollView) {
view.frame = UIScreen.mainScreen().bounds
} else if view.isKindOfClass(UIPageControl) {
view.backgroundColor = UIColor.clearColor()
}
}
}
自分に合った他の回避策を見つけました。
zerotoolで指定されたコード を再利用して、UIPageViewControllerで使用されるUIPageControl(pageControlという変数)とUIScrollView(pageViewという変数)を取得します。
ViewDidLoadでそれが完了したら、pageViewのクリップサブビューを防止し、コンテンツをUIPageControlの下に広げるようにします。
PageControlはpageViewの下にあるため、手動で前面に表示する必要があります。
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if(
[[[self view] subviews] count] == 2
)
{
UIScrollView* pageView = nil;
UIPageControl* pageControl = nil;
UIView* selfView = self.view;
NSArray* subviews = selfView.subviews;
for( NSInteger i = 0 ; i < subviews.count && ( pageView == nil || pageControl == nil ) ; i++ )
{
UIView* t = subviews[i];
if( [t isKindOfClass:[UIScrollView class]] )
{
pageView = (UIScrollView*)t;
}
else if( [t isKindOfClass:[UIPageControl class]] )
{
pageControl = (UIPageControl*)t;
}
}
if( pageView != nil && pageControl != nil )
{
[pageView setClipsToBounds:NO];
[selfView bringSubviewToFront:pageControl];
}
}
}
PageControlによって占有されているスペースをカバーするpageViewを取得したら、pageControlの下で、pageとして表示される各viewControllerのnibファイルの使用を調整するだけです。