Подтвердить что ты не робот

UIScrollView со включенными страницами и изменениями вращения/ориентации устройства (MADNESS)

Мне сложно с этим справиться.

У меня есть UIScrollView, с поддержкой пейджинга. Он управляется контроллером представления (MainViewController), и каждая страница управляется с помощью PageViewController, его представление добавляется как подзадача scrollView при правильном смещении. Прокрутка влево-вправо, для приложений с ориентацией на стандартную ориентацию. Работает хорошо. В основном точно так же, как образец, предоставленный 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;
    }
}

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

.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 file

@synthesize scrollView;

@synthesize 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 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];
}

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

#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);
}

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

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

Ответ 3

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

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

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

Относительно (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: Я написал "теоретический", потому что содержимое вашего представления также может превышать эти границы рамки - они ограничивают представление только тогда, когда свойство UIView clipsToBounds установлено в YES. Я думаю, что это ошибка, которую Apple установила по умолчанию NO.

Ответ 4

В дополнение к тому, что написал Efrain, обратите внимание на то, что свойство frame НЕ ДОЛЖНО, если преобразование представления отличается от преобразования идентичности - то есть, когда представление повернуто.

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