UIScrollView с включенными страницами и поворотом / изменением ориентации устройства (MADNESS) - PullRequest
18 голосов
/ 26 марта 2010

Мне трудно это понять.

У меня есть UIScrollView с включенной подкачкой страниц. Он управляется контроллером представления (MainViewController), а каждая страница управляется PageViewController, его представление добавляется как подпредставление scrollView с соответствующим смещением. Прокрутка влево-вправо для приложения iPhone со стандартной ориентацией. Работает хорошо. В основном точно так же, как образец, предоставленный Apple, а также как приложение Weather, поставляемое с iPhone.

Однако, когда я пытаюсь поддерживать другие ориентации, вещи работают не очень хорошо. Я поддерживал каждую ориентацию в MainViewController и PageViewController с помощью этого метода:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
     return YES;
}

Однако, когда я поворачиваю устройство, мои страницы становятся довольно искаженными, и появляется много глюков рисования, особенно если загружены только некоторые страницы, тогда я поворачиваюсь, затем прокручиваю больше и т.д. ... Очень грязно .

Я сказал, что мои взгляды поддерживают автоматическое изменение размера с

 theView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Но безрезультатно. Кажется, это просто растягивает и искажает мои взгляды.

В моем MainViewController я добавил эту строку в попытке изменить размеры просмотров всех моих страниц:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * ([self.viewControllers count]), self.scrollView.frame.size.height);

    for (int i = 0; i < [self.viewControllers count]; i++) {
        PageViewController *controller = [self.viewControllers objectAtIndex:i];
        if ((NSNull *)controller == [NSNull null])
            continue;

        NSLog(@"Changing frame: %d", i);
        CGRect frame = self.scrollView.frame;
        frame.origin.x = frame.size.width * i;
        frame.origin.y = 0;
        controller.view.frame = frame;
    }
}

Но это не очень помогло (потому что я лениво загружаю представления, поэтому не все они обязательно загружаются при выполнении).

Есть ли способ решить эту проблему?

Ответы [ 4 ]

2 голосов
/ 17 января 2012

Я успешно достиг этого, используя метод ниже:

.h код файла:

@interface ScrollViewController2 : UIViewController <UIWebViewDelegate, UIScrollViewDelegate> {
NSMutableArray *views;
int currentPage;

IBOutlet UIScrollView *scrollView;
BOOL bolPageControlUsed;
int intCurrIndex;

NSMutableArray *arrayContentData;
NSMutableArray *viewControllers;
}

@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;

@property (nonatomic, retain) NSMutableArray *arrayContentData;
@property (nonatomic, retain) NSMutableArray *viewControllers;
@property (nonatomic) BOOL bolPageControlUsed;
@property (nonatomic) int intCurrIndex;

-(void)bindPages;

- (void)setUpScrollView;
- (void)alignSubviews;

- (NSURLRequest *)getPageFromDocumentsDirectory:(NSString *)pstrPageName;

-(void)initiateScrollView;
-(void)loadScrollViewWithPage:(int)page;

=============================================== =============================================

.m файл

@ synthesize scrollView;

@ syntize arrayContentData, viewControllers, bolPageControlUsed, intCurrIndex;

- (void)viewDidLoad {
[super viewDidLoad];

[self bindPages];

//[self setUpScrollView];

[self initiateScrollView];
}

#pragma mark -
#pragma mark Bind Pages
-(void)bindPages{
self.arrayContentData = [[NSMutableArray alloc] init];

[self.arrayContentData addObject:@"1.html"];
[self.arrayContentData addObject:@"2.html"];
[self.arrayContentData addObject:@"3.html"];
[self.arrayContentData addObject:@"4.html"];
[self.arrayContentData addObject:@"5.html"];
[self.arrayContentData addObject:@"6.html"];

[self.arrayContentData addObject:@"1.html"];
[self.arrayContentData addObject:@"2.html"];
[self.arrayContentData addObject:@"3.html"];
[self.arrayContentData addObject:@"4.html"];
[self.arrayContentData addObject:@"5.html"];
[self.arrayContentData addObject:@"6.html"];

[self.arrayContentData addObject:@"1.html"];
[self.arrayContentData addObject:@"2.html"];
[self.arrayContentData addObject:@"3.html"];
[self.arrayContentData addObject:@"4.html"];
[self.arrayContentData addObject:@"5.html"];
[self.arrayContentData addObject:@"6.html"];

[self.arrayContentData addObject:@"1.html"];
[self.arrayContentData addObject:@"2.html"];
[self.arrayContentData addObject:@"3.html"];
[self.arrayContentData addObject:@"4.html"];
[self.arrayContentData addObject:@"5.html"];
[self.arrayContentData addObject:@"6.html"];
}

#pragma mark - 
#pragma mark Get Filename from Document Directory
- (NSURLRequest *)getPageFromDocumentsDirectory:(NSString *)pstrPageName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *yourFilePath = [NSString stringWithFormat:@"%@/Html/%@", documentDirectory, pstrPageName];
NSURL *url = [NSURL fileURLWithPath:yourFilePath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
return requestObj;
}


#pragma mark -
#pragma mark ScrollView Methods
-(void)initiateScrollView{
views = [[NSMutableArray alloc] initWithCapacity:[self.arrayContentData count]];

NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < [self.arrayContentData count]; i++) {
    [controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];

scrollView.contentSize = CGSizeMake([self.arrayContentData count]*scrollView.bounds.size.width,
                                    scrollView.bounds.size.height);
scrollView.delegate = self;

if(self.intCurrIndex == 0){
    [self loadScrollViewWithPage:self.intCurrIndex];
}
}
-(void)loadScrollViewWithPage:(int)page{
if (page < 0) return;
if (page >= [self.arrayContentData count]) return;

// replace the placeholder if necessary
NSString *strContentName = [self.arrayContentData objectAtIndex:page];

//UIImageView *controller = [viewControllers objectAtIndex:page];
UIWebView *controller = [viewControllers objectAtIndex:page];

if ((NSNull *)controller == [NSNull null]) {

    UIView *v = [[UIView alloc] initWithFrame:scrollView.bounds];
    v.backgroundColor = [UIColor colorWithHue:arc4random()/(float)0x100000000
                                   saturation:0.75
                                   brightness:1.0
                                        alpha:1.0];

    controller = [[UIWebView alloc] initWithFrame:v.bounds];
    controller.delegate = self;
    controller.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    controller.center = CGPointMake(v.bounds.size.width/2, v.bounds.size.height/2);
    [controller loadRequest:[self getPageFromDocumentsDirectory:strContentName]];
    [v addSubview:controller];
    [controller release];

    [scrollView addSubview:v];

    [views addObject:v];
    [viewControllers replaceObjectAtIndex:page withObject:controller];
    [v release];
}

[self alignSubviews];

/*
// add the controller's view to the scroll view
if (nil == controller.superview) {
    CGRect frame = scrollView.frame;
    frame.origin.x = frame.size.width * page;
    //frame.origin.y = 0;
    controller.frame = frame;
    [scrollView addSubview:controller];
}*/
}
-(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 (self.bolPageControlUsed) {
    // 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

currentPage = scrollView.contentOffset.x / scrollView.bounds.size.width;
[self loadScrollViewWithPage:currentPage];
}

// В конце анимации прокрутки сбрасывает логическое значение, используемое, когда прокрутки происходят из UIPageControl - (void) scrollViewDidEndDecelerating: (UIScrollView *) scrollView { self.bolPageControlUsed = NO; }

#pragma mark -
#pragma mark setUp ScrollView
- (void)setUpScrollView {
// Set up some colorful content views
views = [[NSMutableArray alloc] initWithCapacity:[self.arrayContentData count]];

for (int i = 0; i < [self.arrayContentData count]; i++) {
    UIView *v = [[UIView alloc] initWithFrame:scrollView.bounds];
    v.backgroundColor = [UIColor colorWithHue:arc4random()/(float)0x100000000
                                   saturation:0.75
                                   brightness:1.0
                                        alpha:1.0];

    NSString *strContentName = [self.arrayContentData objectAtIndex:i];

    UIWebView *controller = [[UIWebView alloc] initWithFrame:v.bounds];
    controller.delegate = self;
    controller.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    controller.center = CGPointMake(v.bounds.size.width/2, v.bounds.size.height/2);
    [controller loadRequest:[self getPageFromDocumentsDirectory:strContentName]];
    [v addSubview:controller];
    [controller release];

    [scrollView addSubview:v];

    [views addObject:v];
    [v release];
}

[self alignSubviews];

[scrollView flashScrollIndicators];
}

#pragma mark -
#pragma mark Align Scroll Subviews
- (void)alignSubviews {
// Position all the content views at their respective page positions
scrollView.contentSize = CGSizeMake([self.arrayContentData count]*scrollView.bounds.size.width,
                                    scrollView.bounds.size.height);

NSUInteger i = 0;
for (UIView *v in views) {
    v.frame = CGRectMake(i * scrollView.bounds.size.width, 0,
                         scrollView.bounds.size.width, scrollView.bounds.size.height);

    for (UIWebView *w in v.subviews) {
        [w setFrame:v.bounds];
    }

    i++;
}
}

#pragma mark -
#pragma mark UIWebView delegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
}
- (void)webViewDidFinishLoad:(UIWebView *)webView { 
}


#pragma mark -
#pragma mark Orientation
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                            duration:(NSTimeInterval)duration {
currentPage = scrollView.contentOffset.x / scrollView.bounds.size.width;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
                                     duration:(NSTimeInterval)duration {
[self alignSubviews];
//NSLog(@"%f", currentPage * scrollView.bounds.size.width);
scrollView.contentOffset = CGPointMake(currentPage * scrollView.bounds.size.width, 0);
}

Надеюсь, это будет полезно всем.

Приветствие.

2 голосов
/ 13 сентября 2010

Необходимо ли иметь отдельный UIViewController (PageViewController) для каждой страницы в вашем UIScrollView? Почему бы не позволить вашему MainViewController позаботиться об этом.

Изменение размеров ваших представлений (и вашего пользовательского интерфейса в целом) после поворота устройства намного проще при создании пользовательского интерфейса в Interface Builder.

1 голос
/ 31 августа 2010

В дополнение к тому, что написал Эфрейн, обратите внимание, что свойство кадра НЕ ДЕЙСТВИТЕЛЬНО, если преобразование вида отличается от преобразования идентичности - , т.е. , когда представление поворачивается.

Конечно, вы учли тот факт, что ваши представления должны быть в новой смещенной позиции, верно?

1 голос
/ 14 апреля 2010

Я не совсем уверен, что правильно вас понимаю ... однако, некоторые мысли:

Свойство frame - это одно (A), а то, как отображается содержимое представления, - другое (B). Кадр CGRect - это (теоретическая) граница вашего представления в суперпредставлении (родительском представлении) ... однако ваше представление не обязательно должно заполнять всю область кадра .

Относительно (A): Здесь у нас есть свойство autoresizingMask UIView, чтобы установить, как изменяется размер кадра при изменении размера суперпредставления. Что происходит, когда вы меняете ориентацию. Тем не менее, вы обычно можете положиться на настройки по умолчанию (работал для меня до сих пор).

Относительно (B): Как содержимое представления распределяется в рамке просмотра, определяется свойством UIView contentMode. С помощью этого свойства вы можете установить, что соотношение сторон должно оставаться неизменным. Например, установите UIViewContentModeScaleAspectFit или что-то еще ..

см. Здесь: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW99

PS: я написал «теоретический», потому что содержимое вашего представления может также превышать эти границы кадра - они ограничивают представление, только если для свойства clivToBounds UIView установлено значение YES. Я думаю, что это ошибка, что Apple по умолчанию установил для этого параметра значение NO.

...