ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
50.93k stars 13.52k forks source link

[4.0.0-rc.2] ion-slides do not resize after screen orientation changes in iOS #17148

Closed gigocabrera closed 3 years ago

gigocabrera commented 5 years ago

Bug Report

Ionic version: [x] 4.x

Current behavior: [4.0.0-rc.2] ion-slides do not resize after screen orientation changes in iOS

Expected behavior: ion-slides should resize when orientation changes in iOS

Steps to reproduce:

  1. Create a new ionic 4 app and add 3 or 4 slides. Or take ionic-conference-app and upgrade to 4.0.0-rc.2
  2. Build project for iOS
  3. Install on device or run in simulator and change orientation

Ionic info:

Ionic:

   ionic (Ionic CLI)             : 4.7.1 (C:\Users\gigoc\AppData\Roaming\npm\node_modules\ionic)
   Ionic Framework               : @ionic/angular 4.0.0-rc.1
   @angular-devkit/build-angular : 0.12.1
   @angular-devkit/schematics    : 7.1.4
   @angular/cli                  : 7.1.4
   @ionic/angular-toolkit        : 1.2.2

Cordova:

   cordova (Cordova CLI) : not installed
   Cordova Platforms     : not available
   Cordova Plugins       : not available

System:

   NodeJS : v8.11.3 (C:\Program Files\nodejs\node.exe)
   npm    : 6.5.0
   OS     : Windows 10
RHinderiks commented 5 years ago

Some examples:

first: img_da9e9a367200-1

Rotated: img_b4eb11c34078-1

Rotated back: img_c56629e9e836-1

It should show a single slide every time.

If it helps it breaks in seemingly random ways, sometimes showing 2,5 on rotation and a single time it worked as expected so possibly a timing issue ?

EdwinRikkers commented 5 years ago

+1

RHinderiks commented 5 years ago

@paulstelzer Any news on this ?

ghost commented 5 years ago

Can confirm this is not working properly on simulator and real device. Rotating to landscape doesn't cause it to dynamically update the width on as it does on android so width is too short and shifted off center to left, also results in it being off center when returning to portrait as well.

leechy commented 5 years ago

My recipe:

Template:

<ion-slides #slides>
...
</ion-slides>

Class:

  ...
  @ViewChild('slides') slides;
  ...
  @HostListener('window:resize')
  onResize() {
    setTimeout(() => this.slides.update(), 100);
  }

I'm using setTimeout() because I'm using <ion-split-pane> and there can be one more resize of the <ion-content> after the browser window resize. And listen to ionSplitPaneVisible makes everything much more complicated. But if you are not using additional elements affecting component size, you can easily drop the setTimeout.

But still — it'll be better if the component listens to it's size changes internally.

HTH

RHinderiks commented 5 years ago

Any news on this ?

konnectappdev commented 5 years ago

@leechy At least on ios i still need a timeout even without surrounding elements. Also and this will sound strange, it will still go "wrong" when rotating the device slowly...

DavidWiesner commented 5 years ago

The core issue is iOS will call the resize and orientationChange event before the viewport was resized (see this link for some details). ion-slides (in detail the external swiper library) is listen to this event and calculation the sizes of the slides right after this event will fired. There are two solutions to solve this issue. One solution was already mentioned: call slides.update() after a specific timeout e.g.: 300ms. Another solution is to disable some calculation in swiper by set the option slidesPerColumn to auto (<ion-slides options="{'slidesPerColumn':'auto'}">). But this solution will cause some other issues. So at the moment calling slides.update() maybe several times after a timeout is the simplest solution for this problem. BTW: swiper also has an option to only recalc their dimensions by calling swiper.emit('resize'). But this api is not exposed by ion-slides.

konnectappdev commented 5 years ago

This is still an issue in release 4.3.0

adamduren commented 5 years ago

I created a directive off of @leechy's recipe to patch slides automatically and reduce boilerplate if anyone would find this useful.

import { Directive, ElementRef, HostListener } from '@angular/core';
import { Platform } from '@ionic/angular';

@Directive({
  // tslint:disable-next-line: directive-selector
  selector: 'ion-slides',
})
export class PatchSlidesDirective {
  public get slides() {
    return this.el && this.el.nativeElement;
  }

  constructor(
    public el: ElementRef<HTMLIonSlidesElement>,
    public platform: Platform,
  ) {}

  @HostListener('window:resize')
  public onResize() {
    if (this.platform.is('ios')) {
      setTimeout(() => {
        if (this.slides) {
          this.slides.update();
        }
      }, 100);
    }
  }
}
VictorNorman commented 5 years ago

I've seen this bug on Android, too.

I found that putting a call to this.slider.update(); in ionViewWillEnter() fixed my problem.

jansgescheit commented 5 years ago

I have this problem also with ionic 4.6. The workaround does not work on every time in my case. Sometimes the problem comes back and sometimes it can resolve by another orientation change. Strange and ugly

kyleabens commented 5 years ago

My solution...

npm i angular-resize-event

CSS:

ion-slide {
    width: 100% !important;
}

HTML:

<ion-slides #slider>
    <ion-slide (resized)="slider.update()">One</ion-slide>
    <ion-slide (resized)="slider.update()">Two</ion-slide>
    <ion-slide (resized)="slider.update()">Three</ion-slide>
</ion-slides>
bigfox commented 5 years ago

For me works update to Ionic 4.9.1 and code from @adamduren and styles from @kyleabens

NiklasMerz commented 4 years ago

This issue is still a problem with Ionic 4.11.8

Simbaclaws commented 4 years ago

Please have a look in my linked post.

I'm trying desperately to figure out what could be wrong. I think it has to do with how swiper.bundle.js does device platform detection. This doesn't seem to be handed off to capacitor's device plugin, cordova's device.platform or @ionic/angular's platform for that matter, but has it's own window.navigator.platform and window.navigator.useragent script to check the correct device platform.

I'm guessing this is where some iOS devices aren't recognized and therefore the orientationchange event is not added to the swiper.

I could be wrong here. Let me know if I'm aiming in the right direction.

Ofcourse you could simply manually call slider.update() but that doesn't seem like a proper fix. More like a workaround.

EDIT: Someone else also mentioned that the following css in globals.scss would also fix the issue as a workaround:

.swiper-slide-active {
width: 100% !important;
}

haven't tried this yet though.

SeanStayn commented 4 years ago

@Simbaclaws thank you! Works on iOS! :)

conde2 commented 4 years ago

Having same issue, this bug is very old, no fix so far?

ionitron-bot[bot] commented 3 years ago

Thanks for the issue! This issue is being closed due to inactivity. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Thank you for using Ionic!