DEV Community

HarmonyOS
HarmonyOS

Posted on

Fixing Duplicate Exit Animations When Dismissing bindSheet in ArkUI Lists

Read the original article:Fixing Duplicate Exit Animations When Dismissing bindSheet in ArkUI Lists

Fixing Duplicate Exit Animations When Dismissing bindSheet in ArkUI Lists

Problem Description

When using a semi-modal sheet via bindSheet for a “Share” popup, dismissing the sheet by tapping outside or dragging triggers the exit animation twice.

Background Knowledge

bindSheet presents a modal, non-fullscreen sheet over part of the parent view.

Its first parameter controls visibility; the second parameter is a CustomBuilder that defines the sheet’s content.

Troubleshooting Process

  • The UI is built with ForEach, producing multiple ListItems.
  • bindSheet is applied to each item’s child component, all bound to the same isShow state and the same ShareBuilder.
  • When the user taps Share to friends, isShow becomes true, effectively creating multiple stacked sheets (one per item).
  • On dismiss, the tapped sheet closes first; the two-way binding ($$) then flips isShow to false, causing the remaining hidden sheets to dismiss too—so visually the exit animation appears twice.

Analysis Conclusion

Multiple children were bound to bindSheet with the same state, so multiple sheets were opened and then dismissed in sequence, producing duplicate exit animations.

Solution

Bind bindSheet only on the intended child (the “Share to friends” item). For all other items, pass undefined as the second argument so they do not create a sheet.

Code Snippet / Configuration

class MenuObject {
  title: string;
  constructor(title: string) {
    this.title = title;
  }
}

@Component
struct MenuComponent {
  @Prop value: MenuObject

  build() {
    Row() {
      Text(this.value.title)
        .fontSize(16)
        .lineHeight(20)
        .padding({ left: 16, right: 16, top: 10, bottom: 10 })
        .maxLines(1)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
      Blank()
    }
    .width('100%')
  }
}

@Entry
@Component
struct Index {
  @State isShow: boolean = false

  private listObjs: MenuObject[] = [
    new MenuObject('Account Management'),
    new MenuObject('My Vehicles'),
    new MenuObject('Privacy Policy'),
    new MenuObject('User Agreement'),
    new MenuObject('Share with Friends'),
    new MenuObject('About')
  ]

  @Builder
  shareTitleBuilder() {
    Row() {
      Text('Share To')
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .padding({ left: 12, right: 12, top: 8, bottom: 8 })
    }
    .width('100%')
    .justifyContent(FlexAlign.Start)
  }

  @Builder
  ShareBuilder() {
    Column() {
      Button('Friends')
        .fontSize(16)
        .width('90%')
        .height(36)
        .margin({ top: 8, bottom: 8 })
        .onClick(() => {
          this.isShow = false
        })
    }
    .width('100%')
    .padding(12)
  }

  build() {
    Column() {
      List() {
        ForEach(this.listObjs, (item: MenuObject, index: number) => {
          ListItem() {
            MenuComponent({ value: item })
              .onClick(() => {
                if (item.title === 'Share with Friends') {
                  this.isShow = true
                } else {
                }
              })
              .bindSheet(
                $$this.isShow,
                item.title === 'Share with Friends' ? this.ShareBuilder() : undefined,
                {
                  detents: [SheetSize.FIT_CONTENT],
                  dragBar: false,
                  showClose: false,
                  title: this.shareTitleBuilder
                }
              )
          }
          .border({ width: 0 })
        })
      }
      .edgeEffect(EdgeEffect.None)
      .divider({
        strokeWidth: 1,
        color: '#1AFFFFFF',
        startMargin: 12,
        endMargin: 12
      })
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Section:

.bindSheet(
  $$this.isShow,
  item.title === 'Share with Friends' ? this.ShareBuilder() : undefined,
  {
    detents: [SheetSize.FIT_CONTENT],
    dragBar: false,
    showClose: false,
    title: this.shareTitleBuilder
  }
)
Enter fullscreen mode Exit fullscreen mode

Verification Result

After restricting bindSheet to the “Share to friends” item and passing undefined for others, the sheet opens once and the exit animation runs only once on dismiss.

14.gif

Related Documents or Links

Written by Bunyamin Eymen Alagoz

Top comments (0)