Ширина UIWebView iPhone не подходит после операции масштабирования + изменение UIInterfaceOrientation
Я создал приложение iPhone с голой костью с UIWebView (Scales Page to Fit = YES, shouldAutorotateToInterfaceOrientation = YES) и загрузил веб-страницу, например. /qaru.site/...
Вращение устройства показывает, что пользовательский интерфейс UIWebView автоматически изменяется в соответствии с шириной. Хорошо.
Неверно. Увеличьте масштаб страницы и уменьшите масштаб. Теперь вращение устройства показывает UIWebView в странной ширине в одной из ориентации (если и увеличить масштаб, ширина портрета странная, наоборот). Это поведение фиксируется только при переходе на другую страницу.
Исправить. Загрузите тот же URL-адрес в Mobile Safari. Вращающиеся работы и ширина подходят независимо от упражнений масштабирования.
Является ли это ошибкой UIWebView (возможно, нет)? Или есть что-то, что нужно сделать, чтобы вещи "просто работали", как в Mobile Safari?
Ответы
Ответ 1
Я нашел кое-что, что сработало для меня. Проблема заключается в том, что когда uiwebview меняет ориентацию, веб-контент зомбируется в соответствии с видовым экраном. Но параметр zoomscale подпрограммы scrollview не обновляется правильно (и не обновляется minimumZoomScale или maximumZoomScale
Затем нам нужно сделать это вручную в 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;
}
}
Надеюсь, это поможет!
Ответ 2
Я пробовал решение из 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];
}
С наилучшими пожеланиями,
Ральф
Ответ 3
- (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
Я отправляю это, потому что у меня также была та же проблема, и здесь я следую подходом M Penades
. M Penades
Ответ woks хорош только для случая, если пользователь не перекосит (защелкнет Out) веб-просмотр, а затем поверните устройство и повторите этот процесс. Затем размер содержимого UiwebView постепенно уменьшается. так что проблема возникла в ответе M Penades
. поэтому я исправил эту проблему, и мой код выглядит следующим образом.
1) Для этого я устанавливаю жест Pinch, чтобы при пользовательском перекос 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;
}
Возврат ДА гарантирует одновременное распознавание. возврат НЕТ не гарантируется, чтобы предотвратить одновременное распознавание, так как другой делегат может передать ДА
-(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 Pinch In/Out Веб-просмотр в этом случае просто установите коэффициент масштабирования. Так что WebView может отрегулировать свой ContentSize при изменении Oreintaion.
- (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.
Ответ 5
У меня есть решение этой проблемы, но я должен сказать, что я не большой поклонник этого. Он отлично работает, но решение на самом деле вызывает еще одну проблему. У меня есть исправление для вторичной проблемы, но требуется немного усилий.
Просто имейте в виду, что с OS3.2 или iOS4 (не уверен, какой) UIWebView прямо подвью теперь UIScrollView вместо UIScroller, поэтому мы можем сделать с ним намного больше. Кроме того, поскольку доступ к представлениям в представлении View не является частным действием, ни один из них не использует подзаголовок, который выставляется как документальное представление, мы можем многое сделать с UIWebView, не нарушая правил.
Сначала нам нужно получить UIScrollView из UIWebview:
UIScrollView *sview = [[webView subviews] objectAtIndex:0];
Теперь нам нужно изменить делегат этого прокрутки, чтобы мы могли переопределить вызовы делегатов 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, вызывается. Причина, по которой функция Selectlect задерживается на 0,0 секунды, заключается в том, что мы хотим вызвать adjustWithZoomData на следующей runloop. Если вы вызываете его напрямую, настройкаWithZoomData будет корректироваться для предыдущей ориентации.
Вот метод adjustWithZoomData:
- (void)adjustWithZoomData{
UIScrollView *sview = [[webView subviews] objectAtIndex:0];
[sview setZoomScale:zoomData animated:YES];
[sview setContentOffset:zoomOffset animated:YES];
[sview setContentSize:zoomContentSize];
updateZoomData = YES;
}
Вот оно! Теперь, когда вы вращаетесь, он будет поддерживать масштабирование и примерно поддерживать правильное смещение. Если кто-то хочет сделать математику о том, как получить точное правильное смещение, то идите за ней!
Ответ 6
Я изучал это сам и узнал дополнительную информацию:
Проблемы при изменении масштаба:
- Safari часто неправильно перерисовывает (если вообще), даже если уровень масштабирования изменился.
- Изменение ширины заставляет перерисовать.
- вы бы подумали, что ширина = ширина устройства в ландшафте будет использовать 1024, но, похоже, использует 768 (screen.width тоже).
например. если текущая ширина равна 1024, и вы хотите увеличить от 1 до 1,5 в ландшафте, вы можете:
- изменить комбинацию ширины и масштабирования, например. ширина до 2048 и увеличение до 0,75
- изменить ширину до 1023 (уродливое сглаживание?)
- измените ширину, чтобы сказать 1023, затем следующая строка назад до 1024 (двойная перерисовка, но по крайней мере окно перекрашено).
Ответ 7
Так что, видимо, я не использовал решение 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; }
Gist at https://gist.github.com/d6589584944685909ae5
Ответ 8
При вращении попробуйте установить для scrollView zoomScale значение 0.
См. Мой полный ответ здесь: Содержимое UIWebView не настроено на новый кадр после ротации