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.92k stars 13.52k forks source link

bug: ion-segment scrollable IOS animation bug #29523

Open rostislavcz opened 4 months ago

rostislavcz commented 4 months ago

Prerequisites

Ionic Framework Version

v7.x, v8.x

Current Behavior

When you use multiple segment items there is strange animation bug on ios devices when using scrollable option. (Android, Web - even Safari works fine)

<IonSegment scrollable={true} value="heart">
  <IonSegmentButton value="home">
    <IonIcon icon={home}></IonIcon>
  </IonSegmentButton>
  <IonSegmentButton value="heart">
    <IonIcon icon={heart}></IonIcon>
  </IonSegmentButton>
  <IonSegmentButton value="pin">
    <IonIcon icon={pin}></IonIcon>
  </IonSegmentButton>
  <IonSegmentButton value="star">
    <IonIcon icon={star}></IonIcon>
  </IonSegmentButton>
</IonSegment>

Here you can see the result on real device, i did a little CSS changes but tried also with original styles and there is the same result. I also did a little digging in your code and managed to solve the problem:

In Segment class there is method

private scrollActiveButtonIntoView(smoothScroll = true) {
  const { scrollable, value, el } = this;

  if (scrollable) {
    const buttons = this.getButtons();
    const activeButton = buttons.find((button) => button.value === value);
    if (activeButton !== undefined) {
      const scrollContainerBox = el.getBoundingClientRect();
      const activeButtonBox = activeButton.getBoundingClientRect();

      /**
        * Subtract the active button x position from the scroll
        * container x position. This will give us the x position
        * of the active button within the scroll container.
        */
      const activeButtonLeft = activeButtonBox.x - scrollContainerBox.x;

      /**
        * If we just used activeButtonLeft, then the active button
        * would be aligned with the left edge of the scroll container.
        * Instead, we want the segment button to be centered. As a result,
        * we subtract half of the scroll container width. This will position
        * the left edge of the active button at the midpoint of the scroll container.
        * We then add half of the active button width. This will position the active
        * button such that the midpoint of the active button is at the midpoint of the
        * scroll container.
        */
      const centeredX = activeButtonLeft - scrollContainerBox.width / 2 + activeButtonBox.width / 2;

      /**
        * We intentionally use scrollBy here instead of scrollIntoView
        * to avoid a WebKit bug where accelerated animations break
        * when using scrollIntoView. Using scrollIntoView will cause the
        * segment container to jump during the transition and then snap into place.
        * This is because scrollIntoView can potentially cause parent element
        * containers to also scroll. scrollBy does not have this same behavior, so
        * we use this API instead.
        *
        * Note that if there is not enough scrolling space to center the element
        * within the scroll container, the browser will attempt
        * to center by as much as it can.
        */
      el.scrollBy({
        top: 0,
        left: centeredX,
        behavior: smoothScroll ? 'smooth' : 'instant',
      });
    }
  }
}

Instead of el.scrollBy if I call el.scrollTo, the problem dissapears and it works as it should

https://github.com/ionic-team/ionic-framework/assets/58735164/21208d4d-bfd9-47ed-a74a-dcc45165b2e0

Expected Behavior

The same result when you just change el.scrollBy to el.scrollTo

https://github.com/ionic-team/ionic-framework/assets/58735164/1a0af05f-a8f2-440e-8811-03804e6893eb

Steps to Reproduce

Run any basic Ionic/Capacitor project on ios device and use scrollable ion-segment with multiple items, that will has width more than 100% of device width

Code Reproduction URL

https://stackblitz.com/edit/dw3jre?file=package.json

Ionic Info

Ionic:

Ionic CLI : 7.0.1 (/usr/local/lib/node_modules/@ionic/cli) Ionic Framework : @ionic/angular 8.0.0 @angular-devkit/build-angular : 17.3.5 @angular-devkit/schematics : 17.3.5 @angular/cli : 17.3.5 @ionic/angular-toolkit : 11.0.1

Capacitor:

Capacitor CLI : 6.0.0 @capacitor/android : 6.0.0 @capacitor/core : 6.0.0 @capacitor/ios : 6.0.0

Utility:

cordova-res : 0.15.4 native-run : 2.0.1

Additional Information

No response

Procisz commented 1 month ago

Same issue here (Angular v18 with Ionic), please fix it! :)

Procisz commented 3 weeks ago

Yo' Folks, Do you have some progress with that issue?

rostislavcz commented 3 weeks ago

Sad is, that i literally wrote them how to fix that and they dont care :D