iPhone UIWebView ширина не подходит после операции масштабирования + изменение UIInterfaceOrientation - PullRequest
13 голосов
/ 23 мая 2010

Я создал приложение iPhone для iPhone с UIWebView (Scales Page to Fit = YES, shouldAutorotateToInterfaceOrientation = YES) и загрузил веб-страницу, например, https://stackoverflow.com/

Вращение устройства показывает, что UIWebView автоматически изменяетсячтобы соответствовать ширине.Хорошо.

Неправильно : увеличить масштаб страницы.Теперь вращение устройства показывает UIWebView со странной шириной в одной из ориентаций (если увеличить масштаб, ширина портрета будет странной, и наоборот).Это поведение исправлено только при переходе на другую страницу.

Исправить : загрузить тот же URL-адрес в Mobile Safari.Поворот работает и ширина подходит независимо от масштабирования.

Это ошибка UIWebView (вероятно, нет)?Или нужно что-то сделать, чтобы заставить вещи «просто работать», как в Mobile Safari?

Ответы [ 8 ]

14 голосов
/ 16 февраля 2011

Я нашел то, что сработало для меня. Проблема в том, что когда uiwebview меняет свою ориентацию, веб-содержимое масштабируется, чтобы соответствовать области просмотра. Но параметр zoomscale подпредставления прокрутки не обновляется корректно (ни обновляются минимальные ZoomScale и максимальные ZoomScale

Тогда нам нужно сделать это вручную на willRotateToInterfaceOrientation:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    CGFloat ratioAspect = webview.bounds.size.width/webview.bounds.size.height;
    switch (toInterfaceOrientation) {
        case UIInterfaceOrientationPortraitUpsideDown:
        case UIInterfaceOrientationPortrait:
            // Going to Portrait mode
            for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview 
                // Make sure it really is a scroll view and reset the zoom scale.
                if ([scroll respondsToSelector:@selector(setZoomScale:)]){
                    scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect;
                    scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect;
                    [scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES];
                }
            }
            break;
        default:
            // Going to Landscape mode
            for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview 
                // Make sure it really is a scroll view and reset the zoom scale.
                if ([scroll respondsToSelector:@selector(setZoomScale:)]){
                    scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect;
                    scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect;
                    [scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES];
                }
            }
            break;
    }
}

Надеюсь, это поможет!

4 голосов
/ 20 ноября 2012
- (UIScrollView *)findScrollViewInsideView:(UIView *)view
{
    for(UIView *subview in view.subviews){
        if([subview isKindOfClass:[UIScrollView class]]){
            return (UIScrollView *)subview;
        }

        UIScrollView *foundScrollView = [self findScrollViewInsideView:subview];
        if (foundScrollView){
            return foundScrollView;
        }
    }

    return nil;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    switch (self.interfaceOrientation){
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
        {
            UIScrollView *webViewScrollView = ([self.webView respondsToSelector:@selector(scrollView)])
                ? self.webView.scrollView
                : [self findScrollViewInsideView:self.webView];

            [webViewScrollView setZoomScale:1.01f animated:YES];
        }
            break;

        default:
            break;
    }
}

попробуйте этот код, он незначительно изменяет уровень масштабирования (1.01), чтобы позволить UIWebView увеличить размер содержимого в ландшафтном режиме

findScrollViewInsideView: добавлен метод для поддержки ios4

4 голосов
/ 30 июня 2011

Я пробовал решение от M Penades, и это, кажется, работает и для меня.

Единственная проблема, с которой я сталкиваюсь, заключается в том, что при запуске этого на 3Gs вращение, к сожалению, не очень плавное.

Поэтому я сейчас использую другой подход:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {

[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

CGFloat scale = browserWebView.contentScaleFactor;
NSString *javaStuff = [NSString stringWithFormat:@"document.body.style.zoom = %f;", scale];
[browserWebView stringByEvaluatingJavaScriptFromString:javaStuff];

}

С наилучшими пожеланиями,
Ральф

1 голос
/ 12 октября 2012

Я публикую это, потому что я также столкнулся с той же проблемой, и здесь я следую подходу M Penades. Ответ M Penades работает хорошо только в том случае, если пользователь не наклоняет (урезает) веб-представление, а затем поворачивает устройство и повторите этот процесс. Затем размер контента UiwebView постепенно уменьшается. так что проблема была в M Penades Ответе. поэтому я тоже исправил эту проблему, и мой код, как показано ниже.

1) Для этого я установил Жест пинча, чтобы при перекосе пользователя UIwebView мог проверять масштабированный размер UIwebView. // One This Пожалуйста импортируйте UIGestureRecognizerDelegate протокол в '.h файл'

     //call below method in ViewDidLoad Method for setting the Pinch gesture 

- (void)setPinchgesture
{
     UIPinchGestureRecognizer * pinchgesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(didPinchWebView:)];

    [pinchgesture setDelegate:self];

    [htmlWebView addGestureRecognizer:pinchgesture];
    [pinchgesture release];
   // here htmlWebView is WebView user zoomingIn/Out 

}
   //Allow The allow simultaneous recognition

  - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer   *)otherGestureRecognizer
  {
     return YES;
  }

Возвращение YES гарантирует одновременное распознавание. возврат NO не гарантирует предотвращения одновременного распознавания, так как делегат другого жеста может вернуть YES

 -(void)didPinchWebView:(UIPinchGestureRecognizer*)gestsure
   {
   //check if the Scaled Fator is same is normal scaling factor the allow set Flag True.
    if(gestsure.scale<=1.0)
    {
    isPinchOut = TRUE;

    }
    else// otherwise Set false
    {
    isPinchOut = FALSE;
   }
  NSLog(@"Hello Pinch %f",gestsure.scale);
}

Если пользователь использует Hase, вводит / выводит веб-представление в этом случае, просто установите коэффициент масштабирования. ПОЭТОМУ, WebView может изменить свой размер содержимого как измененный.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation   duration:(NSTimeInterval)duration {

   //Allow the Execution of below code when user has Skewed the UIWebView and Adjust the Content Size of UiwebView.

  if(isPinchOut){
  CGFloat ratioAspect = htmlWebView.bounds.size.width/htmlWebView.bounds.size.height;
  switch (toInterfaceOrientation) {
    case UIInterfaceOrientationPortraitUpsideDown:
    case UIInterfaceOrientationPortrait:
        // Going to Portrait mode
        for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview
            // Make sure it really is a scroll view and reset the zoom scale.
            if ([scroll respondsToSelector:@selector(setZoomScale:)]){
                scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect;
                scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect;
                [scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES];
            }
        }
        break;

    default:
        // Going to Landscape mode
        for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview
            // Make sure it really is a scroll view and reset the zoom scale.
            if ([scroll respondsToSelector:@selector(setZoomScale:)]){
                scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect;
                scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect;
                [scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES];
            }
        }
        break;
     }
  }

}

Это прекрасно работает даже для пользователя, наклоняющего UIWebView.

0 голосов
/ 23 февраля 2015

При вращении попробуйте установить scrollView zoomScale в 0. Смотрите мой полный ответ здесь: Содержимое UIWebView не корректируется для нового кадра после вращения

0 голосов
/ 16 мая 2012

Так что, видимо, я не использовал решение M Penades в конце (и забыл обновить этот пост! Извините).

Что я сделал, так это изменил размер всего документа (и изменил размер шрифта, чтобы сохранить пропорции). По-видимому, это решило проблему.

Однако мой UIWebView предназначен только для загрузки моих собственных HTML и CSS из файловой системы iOS - если вы создаете веб-браузер общего назначения, этот прием может не сработать.

ViewController.m

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    switch (toInterfaceOrientation) {
        case UIInterfaceOrientationPortraitUpsideDown:
        case UIInterfaceOrientationPortrait:
            if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
                [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'ppad'"];
            } else {
                [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'pphone'"];
            }
            break;
        default:
            if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
                [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'lpad'"];
            } else {
                [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'lphone'"];
            }
            break;
    }
}

и app.css

html>body.pphone { font-size:12px; width: 980px; }
html>body.lphone { font-size:18px; width: 1470px; }
html>body.ppad { font-size:12px; width: 768px; }
html>body.lpad { font-size:15.99999996px; width: 1024px; }

Суть в https://gist.github.com/d6589584944685909ae5

0 голосов
/ 12 сентября 2011

Я сам изучил это и обнаружил еще немного информации:

Проблемы при изменении масштаба:

  1. Safari часто не перерисовывается должным образом (если вообще), хотяизменен уровень масштабирования.
  2. Изменение ширины вызывает перерисовку.
  3. можно подумать, что width = device-width в альбомной ориентации будет использовать 1024, но, похоже, будет использоваться 768 (screen.width тоже происходит).

например, если текущая ширина равна 1024, и вы хотите увеличить от 1 до 1,5 в альбомной ориентации, вы можете:

  • изменить комбинацию ширины и увеличения, например, ширину до 2048 и увеличитьна 0,75
  • изменить ширину на 1023 (ужасный псевдоним?)
  • изменить ширину на 1023, затем на следующей строке вернуться к 1024 (двойная перекраска, но по крайней мере окно перерисовывается).
0 голосов
/ 15 июля 2010

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

Просто имейте в виду, что, поскольку OS3.2 или iOS4 (не знаю, какой именно) прямым подпредставлением UIWebView теперь является UIScrollView, а не UIScroller, поэтому мы можем сделать с ним гораздо больше. Кроме того, поскольку доступ к подпредставлениям представления не является частным действием, также не используется подпредставление, которое приводится как документированное представление, мы можем многое сделать с помощью UIWebView, не нарушая правил.

Сначала нам нужно получить UIScrollView из UIWebview:

UIScrollView *sview = [[webView subviews] objectAtIndex:0];

Теперь нам нужно изменить делегата этого scrollview, чтобы мы могли переопределить вызовы делегата scrollview (что может фактически стать причиной вторичной ошибки в результате этого решения, о котором я расскажу чуть позже):

sview.delegate = self;

Теперь, если вы попробуете в этот момент, масштабирование будет нарушено. Нам нужно реализовать метод UIScrollViewDelegate, чтобы исправить это. добавить:

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    UIView *webBrowserView = [[scrollView subviews] objectAtIndex:10];
    return webBrowserView;
}

webBrowserView на самом деле является UIWebBrowserView, но это не документированный класс, поэтому мы просто будем рассматривать его как UIView.

Теперь запустите ваше приложение, увеличьте, а затем уменьшите масштаб веб-страницы. Поверните, и оно должно появиться правильно.

Это вызывает довольно большую ошибку, которая, возможно, хуже оригинала.

Если вы увеличите, а затем поверните, вы потеряете способность к прокрутке, но ваше изображение будет увеличено. Вот исправление, чтобы завершить все это.

Во-первых, нам нужно отследить несколько цифр и определить флаг:

Я определил их в моем файле h:

BOOL updateZoomData;
float zoomData; //this holds the scale at which we are zoomed in, scrollView.zoomScale
CGPoint zoomOffset; //this holds the scrollView.contentOffset
CGSize zoomContentSize; //this holds the scrollView.contentSize

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

Нам нужно использовать другой метод делегата:

- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
    if(updateZoomData){
        zoomData = scrollView.zoomScale;
        zoomOffset = scrollView.contentOffset;
        zoomContentSize = scrollView.contentSize;
    }
}

Теперь я чувствую беспорядок.

Нам нужно отслеживать вращение, поэтому вам нужно добавить это в ваш viewDidLoad, loadView или любой другой метод, который вы используете для регистрации уведомлений:

[[NSNotificationCenter defaultCenter] addObserver:self 
            selector:@selector(webViewOrientationChanged:) 
            name:UIDeviceOrientationDidChangeNotification 
            object:nil];

и создайте этот метод:

- (void)webViewOrientationChanged:(NSNotification *)notification{
    updateZoomData = NO;
    [self performSelector:@selector(adjustWithZoomData) withObject:nil afterDelay:0.0];
}

Так что теперь каждый раз, когда вы поворачиваете, будет вызываться webViewOrientationChange. Причина выполнения executeSelector на 0,0 секунды заключается в том, что мы хотим вызвать AdjustWithZoomData при следующем цикле выполнения. Если вы вызываете его напрямую, AdjustWithZoomData откорректирует предыдущую ориентацию.

Вот метод AdjustWithZoomData:

- (void)adjustWithZoomData{
    UIScrollView *sview = [[webView subviews] objectAtIndex:0];
    [sview setZoomScale:zoomData animated:YES];
    [sview setContentOffset:zoomOffset animated:YES]; 
    [sview setContentSize:zoomContentSize];
    updateZoomData = YES;
}

Вот и все! Теперь при повороте он будет поддерживать масштабирование и примерно поддерживать правильное смещение. Если кто-то хочет сделать математику о том, как получить точное правильное смещение, тогда сделайте это!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...