ArkUI Animation/Interaction Event Development (ArkTS)

What should I do if the onBlur and onFocus callbacks cannot be triggered? (API version 9)

Problem

The onBlur and onFocus callbacks of the focus event cannot be triggered.

Solution

Check the trigger device. By default, the focus event (and the onBlur and onFocus callbacks) can be triggered only by the Tab button and arrow buttons on the connected keyboard. To enable the focus event to be triggered by a touch, add the focusOnTouch attribute for the target component.

Reference

Focus Control

How do I disable the scroll event of a Grid nested in the Scroll? (API version 9)

Implement nested scrolling of the containers, by using the onScrollFrameBegin event and the scrollBy method.

Reference

Example: Implementing Nested Scrolling

How do I enable a component to rotate continuously? (API version 9)

You can use property animation to implement that effect.

How do I scroll a list with the keyboard? (API version 9)

Solution

The following two solutions are available:

  1. Add focusable(true) to the list item to enable it to obtain focus.

  2. Nest a focusable component, for example, Button, at the outer layer of each item.

Why is the click event not triggered for the focused component upon the press of the Enter key after keyboard navigation? (API version 9)

By default, the built-in click event of the component and the custom onClick click event are bound to the space bar instead of the Enter key.

How do I block event bubbling when a button is nested in multi-layer components? (API version 9)

You can bind the button to the stopPropagation parameter.

How do I disable the page transition effect when the router or navigator is used for page transition? (API version 9)

  1. Define the pageTransition method for the current and target pages by following instructions in Example.

  2. Set the duration parameter of both PageTransitionEnter and PageTransitionExit to 0.

How do I fix misidentification of the pan gesture where container nesting is involved? (API version 9)

Recognition of the pan gesture requires a minimum 5 vp movement distance of a finger on the screen. You can set the distance parameter in PanGesture to 1 so that the pan gesture can be more easily recognized.

Reference

PanGesture

Can I use the fontFamily attribute to set different fonts? (API version 9)

Default value: 'HarmonyOS Sans'. Only the default font is supported.

How do I implement a text input box that shows a soft keyboard when touched and hides the soft keyboard when a button is touched? (API version 9)

Use focusControl for the TextInput component to control its focus. The TextInput component shows a soft keyboard when it gains focus and hides the soft keyboard when it loses focus.

Code Example

build() {
  Column() {
    TextInput()
    Button(`hide`)
      .key('button')
      .onClick(()=>{
        focusControl.requestFocus('button')
      })
  }
}

How do I implement a button that only responds to the bound onClick event, but not the onTouch event bound to the button's parent component? (API version 9)

Bind onTouch to the Button component and use stopPropagation() in onTouch to prevent the events from bubbling up to the parent component.

Code Example

@Entry
@Component
struct Index {
  build() {
    Row() {
      Button ("Click Me")
        .width(100)
        .backgroundColor('#f00')
        .onClick(() => {
          console.info("Button onClick");
        })
        .onTouch((e) => {
          console.info("Button onTouch");
          e.stopPropagation();
        })
    }
    .onTouch(() => {
      console.info("Row onTouch");
    })
  }
}

Why is the menu bound to a component not displayed when the component is right-clicked? (API version 9)

Solution

Currently, the menu is displayed when the bound component is clicked or long pressed.

How do I prevent the text input box from bringing up the default keyboard? (API version 9)

Set the focusable attribute of the TextInput component to false. In this way, the component is not focusable and therefore will not bring up the keyboard.

How do I implement the slide up and slide down effect for page transition? (API version 9)

Problem

How do I implement slide up and slide down effect for page transition?

Solution

You can use the pageTransition API to implement the page transition effect. Specifically, set slide in PageTransitionEnter and PageTransitionExit to SlideEffect.Bottom. In this way, the page slides in and out from the bottom.

Code Example

// Index.ets
@Entry
@Component
struct PageTransition1 {
  build() {
    Stack({alignContent: Alignment.Bottom}) {
      Navigator({ target: 'pages/Page1'}) {
        Image($r('app.media.ic_banner01')).width('100%').height(200) // Save the image in the media folder.
      }
    }.height('100%').width('100%')
  }
  pageTransition() {
    PageTransitionEnter({ duration: 500, curve: Curve.Linear }).slide(SlideEffect.Bottom)
    PageTransitionExit({ duration: 500, curve: Curve.Ease }).slide(SlideEffect.Bottom)
  }
}
// Page1.ets
@Entry
@Component
struct PageTransition2 {
  build() {
    Stack({alignContent: Alignment.Bottom}) {
      Navigator({ target: 'pages/Index'}) {
        Image($r('app.media.ic_banner02')).width('100%').height(200) // Save the image in the media folder.
      }
    }.height('100%').width('100%')
  }
  pageTransition() {
    PageTransitionEnter({ duration: 500, curve: Curve.Linear }).slide(SlideEffect.Bottom)
    PageTransitionExit({ duration: 500, curve: Curve.Ease }).slide(SlideEffect.Bottom)
  }
}

Reference

Page Transition

How do I configure custom components to slide in and out from the bottom? (API version 9)

Problem

Custom components A and B need to deliver the following effects: When custom component A, displayed at the bottom of the screen by default, is touched, it is hidden, and custom component B slides in from the bottom; when custom component B is touched, it is hidden, and custom component A slides in from the bottom. How can the effects be achieved?

Solution

You can use transition to create component transition animations. Set the type parameter to specify the component transition type, which can be component addition, component deletion, or both; set the translate parameter to specify the translation of the component during transition. Note that transition must work with animateTo. The animation duration, curve, and delay follow the settings in animateTo.

Code Example

@Entry
@Component
struct ComponentTransition {
  @State flag: boolean = true;

  build() {
    Stack({alignContent: Alignment.Bottom}) {
        if (this.flag) {
          ComponentChild1({ flag: $flag })
            .transition({ type: TransitionType.Insert,translate: { x: 0, y: 200 } })
        }
        if (!this.flag) {
          ComponentChild2({ flag: $flag })
            .transition({ type: TransitionType.Insert, translate: { x: 0, y: 200 } })
        }
    }.height('100%').width('100%')
  }
}

@Component
struct ComponentChild1 {
  @Link flag: boolean

  build() {
    Column() {
      Image($r('app.media.ic_banner01'))
        .width('100%')
        .height(200)
        .onClick(() => {
          this.getUIContext()?.animateTo({ duration: 1000 }, () => {
            this.flag = !this.flag;
          })
        })
    }
  }
}

@Component
struct ComponentChild2 {
  @Link flag: boolean

  build() {
    Column() {
      Image($r('app.media.ic_banner02'))
        .width('100%')
        .height(200)
        .onClick(() => {
          this.getUIContext()?.animateTo({ duration: 1000 }, () => {
            this.flag = !this.flag;
          })
        })
    }
  }
}

Reference

Enter/Exit Transition

Why does the file manager not respond to a short press? (API version 10)

Problem

A short press (for example, lasting between 200 and 500 ms) on a folder icon will not trigger a response in the file manager.

Possible Causes

Due to an unhandled exception branch in the drag gesture recognition logic, releasing the press within a specific short duration causes the gesture recognizer to remain in a pending state. This prevents it from responding to user input. As a result, the file manager becomes unresponsive.

Solution

Long press the file icon or the blank area to restore.

How do I customize event delivery between parent and child components? (API version 10)

Solution

  1. The system collects controls that need to respond to events based on hit testing. The test order propagates from the parent component to its child components. Subsequent gesture recognition and competition are performed based on the test results.

  2. Applications can change the hit test results for a component by modifying the value of hitTestBehavior of that component.

  3. The intervention in gesture recognition and competition results can be refined through custom events and custom gesture determination capabilities.

Reference

  1. hitTestBehavior

  2. Custom Event Dispatch

  3. Custom Gesture Judgment

How can I implement automatic repositioning and dynamic rearrangement of other list items when dragging a list item? (API version 10)

Solution

  1. Add the drag capability to list or grid items by enabling draggable and registering onDragStart.

  2. In the onDragStart callback, set visibility of the dragged item to HIDDEN.

  3. Register onDragMove for the list or grid items to listen for drag movement events.

  4. During dragging, obtain the coordinates of the drag follow point via the event parameter of onDragMove.

  5. Calculate the distance between the drag follow point coordinates and the item's center line. When they align, trigger the squeeze animation.

  6. Obtain the item layout information using the componentUtils API.

  7. Use animateTo to change the index in the data source, triggering the list's sorting animation.

  8. Implement the drop animation using a custom animation.

Code Example

// Record the dragged item when the drag starts.
  .onDragStart((event?: DragEvent, extraParams?: string) => {
    this.dragIndex = Number(item.data)
    this.dragItem = item
  })
  // Execute the squeeze effect when the dragged item enters a new item slot.
  .onDragEnter((event?: DragEvent, extraParams?: string) => {
    if (Number(item.data) != this.dragIndex) {
      let current = this.dataSource.findIndex((element) => element.data === this.dragItem.data)
      let index = this.dataSource.findIndex((element) => element.data === item.data)
      this.getUIContext()?.animateTo({
        curve: curves.interpolatingSpring(0, 1, 400, 38)
      }, () => {
        this.dataSource.splice(current, 1)
        this.dataSource.splice(index, 0, this.dragItem)
      })
    }
  })
   // Upon release, apply a custom drop animation for the dragged item at the release position.
  .onDrop((dragEvent: DragEvent) => {
    dragEvent.useCustomDropAnimation = true;
    // Obtain the drop position.
    let downLocation = getInspectorByKey(item.data)
    let currentLocation = dragEvent.getPreviewRect()
    this.dragItem.scale = 1.05
    this.getUIContext()?.animateTo({
      curve: curves.interpolatingSpring(14, 1, 170, 17)
    }, () => {
      this.dragItem.scale = 1
    })
  })

What should I do if a SuperHub floating window appears during image drag operations? (API version 9)

Problem

A SuperHub floating window appears unexpectedly during image drag operations.

Possible Causes

The Image component supports drag functionality by default. When the system's transfer service detects an image drag operation, it automatically displays the SuperHub floating window.

Solution

  1. Set the draggable attribute of the Image component to false.

  2. Go to Settings > System > SuperHub and disable Show on drag on the device.

Reference

draggable