Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: ion-segment scrollable IOS animation bug #29523

Closed
3 tasks done
rostislavcz opened this issue May 20, 2024 · 6 comments · Fixed by #29884 · May be fixed by l00pinfinity/devvscape-code-humor#71
Closed
3 tasks done

bug: ion-segment scrollable IOS animation bug #29523

rostislavcz opened this issue May 20, 2024 · 6 comments · Fixed by #29884 · May be fixed by l00pinfinity/devvscape-code-humor#71
Labels
type: bug a confirmed bug report

Comments

@rostislavcz
Copy link
Contributor

rostislavcz commented May 20, 2024

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

Screen.Recording.2024-05-20.at.8.59.54.mov

Expected Behavior

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

RPReplay_Final1716188775.mov

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

@ionitron-bot ionitron-bot bot added the triage label May 20, 2024
@brandyscarney brandyscarney removed their assignment Jul 15, 2024
@Procisz
Copy link

Procisz commented Jul 25, 2024

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

@Procisz
Copy link

Procisz commented Aug 23, 2024

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

@rostislavcz
Copy link
Contributor Author

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

@thetaPC
Copy link
Contributor

thetaPC commented Sep 19, 2024

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 thetaPC added the type: bug a confirmed bug report label Sep 19, 2024
@ionitron-bot ionitron-bot bot removed the triage label Sep 19, 2024
github-merge-queue bot pushed a commit that referenced this issue Sep 23, 2024
Issue number: resolves #29523

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

The scrollable segment flickers on iOS physical devices or simulators
when the active button is near the edge of the screen. The jump is due
to the button being scrolled to the center and snaps back to the edge
since the button was scrolled past the container.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Switched to `scrollTo` provides for a smoother transition.
- Gave co author credit to the original reporter since they provided
part of the solution
- No new tests were created since functionality stays the same and
testing on Playwright would be impossible to recreate

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: 8.3.2-dev.11726779768.16e1f1d2

How to test:
1. Create a new app through any starter
2. Add a scrollable segment with at least 6 buttons (code snippet
example below)
3. Recommended to change the segment mode to `md` since it's easier to
see the flicker
4. Build the app and open it in an iOS or simulator (if more
instructions on how to do this is needed, reach out to me)
5. Click on the third button
6. Click on the first button
7. Notice the flicker
8. Click over to the third to last button
9. Click on either the last two buttons
10. Notice the flicker
11. Install the dev build
12. Verify the load does not flicker
13. Repeat steps 4 and 5
14. Verify the flicker is no longer there
15. Repeat steps 7 and 8
16. Verify the flicker is no longer there


```js
<ion-segment value="2" scrollable="true" mode="md">
  <ion-segment-button value="1">
    <ion-label>Button 1</ion-label>
  </ion-segment-button>
  <ion-segment-button value="2">
    <ion-label>Button 2</ion-label>
  </ion-segment-button>
  <ion-segment-button value="3">
    <ion-label>Button 3</ion-label>
  </ion-segment-button>
  <ion-segment-button value="4">
    <ion-label>Button 4</ion-label>
  </ion-segment-button>
  <ion-segment-button value="5">
    <ion-label>Button 5</ion-label>
  </ion-segment-button>
  <ion-segment-button value="6">
    <ion-label>Button 6</ion-label>
  </ion-segment-button>
</ion-segment>
```

---------

Co-authored-by: rostislavcz <[email protected]>
@thetaPC
Copy link
Contributor

thetaPC commented Sep 23, 2024

Thanks for the issue! This has been resolved via #29884 and will be available in an upcoming release of Ionic.

Copy link

ionitron-bot bot commented Oct 23, 2024

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 ionitron-bot bot locked and limited conversation to collaborators Oct 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: bug a confirmed bug report
Projects
None yet
4 participants