ionic-framework icon indicating copy to clipboard operation
ionic-framework copied to clipboard

bug: ion-segment scrollable IOS animation bug

Open rostislavcz opened this issue 1 year ago • 3 comments

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

rostislavcz avatar May 20 '24 07:05 rostislavcz

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

Procisz avatar Jul 25 '24 14:07 Procisz

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

Procisz avatar Aug 23 '24 16:08 Procisz

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

rostislavcz avatar Aug 27 '24 08:08 rostislavcz

Thank you for the issue!

I was able to replicate this bug for all frameworks. This only happens on a physical iOS device or an simulator. A fix for this should be coming soon.

thetaPC avatar Sep 19 '24 20:09 thetaPC

Thanks for the issue! This has been resolved via https://github.com/ionic-team/ionic-framework/pull/29884 and will be available in an upcoming release of Ionic.

thetaPC avatar Sep 23 '24 18:09 thetaPC

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. 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.

ionitron-bot[bot] avatar Oct 23 '24 18:10 ionitron-bot[bot]