Skip to content

Jittery popover on Android phone #191

@TasseDeCafe

Description

@TasseDeCafe

Describe the bug
When a Popover is triggered to appear on Android, anchored to a View via a ref passed to the from prop, the initial rendering animation exhibits a "jitter". The popover briefly appears at one position, then quickly jumps slightly (e.g., ~1cm visually) to its final, correct position. This happens very fast but is noticeable. The issue does not occur on iOS.

Here is how I use it:

import { useRef, useState } from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import Popover, { PopoverPlacement } from 'react-native-popover-view'

export default function ContactScreen() {
  const [popoverVisible, setPopoverVisible] = useState(false)
  const buttonRef = useRef<View>(null)

  const handleButtonPress = () => {
    setPopoverVisible(true)
  }

  const closePopover = () => {
    setPopoverVisible(false)
  }

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <TouchableOpacity onPress={handleButtonPress}>
        {/* Inner View receives the ref */}
        <View
          ref={buttonRef}
          collapsable={false}
          renderToHardwareTextureAndroid={true}
          style={{ padding: 10, backgroundColor: 'lightblue' }}
        >
          <Text>Show Popover</Text>
        </View>
      </TouchableOpacity>

      <Popover
        debug={true}
        isVisible={popoverVisible}
        from={buttonRef}
        onRequestClose={closePopover}
        popoverStyle={{ borderRadius: 8, padding: 10 }}
        placement={PopoverPlacement.TOP} // Explicit placement
        animationConfig={{ duration: 1 }} // Minimal animation
      >
        <Text>Test Popover Content</Text>
      </Popover>
    </View>
  )
}

Device/Setup Info:

  • Device: [Xioami 10T Pro]
  • OS: [MIUI 14.0.1]
  • react-native version: [0.76] (Expo)
  • react-native-popover-view version: [6.1.0]

Screenshots
I recorded a video: https://drive.google.com/file/d/1MAFdmk5hs-XCzzuyGe65y-vjFoiONrTc/view?usp=sharing

Debug Output

I opened and closed the modal:

(NOBRIDGE) LOG Config for development environment validated successfully
(NOBRIDGE) LOG [2025-04-16T16:45:18.459Z] calculateRectFromRef - waiting for ref
(NOBRIDGE) LOG [2025-04-16T16:45:18.463Z] calculateRectFromRef - waiting for ref to move from: {"x":0,"y":0,"width":0,"height":0}
(NOBRIDGE) LOG [2025-04-16T16:45:18.484Z] calculateRectFromRef - calculated Rect: {"x":151.27273559570312,"y":450.54544830322266,"width":90.54545593261719,"height":19.272735595703125}
(NOBRIDGE) LOG [2025-04-16T16:45:18.519Z] setDefaultDisplayArea - newDisplayArea: {"x":0,"y":0.00004438920450411388,"width":392.7272644042969,"height":825.4545288085938}
(NOBRIDGE) LOG [2025-04-16T16:45:18.520Z] setDefaultDisplayArea - displayAreaOffset: {"x":0,"y":0}
(NOBRIDGE) LOG [2025-04-16T16:45:18.544Z] [BasePopover] componentDidUpdate - changedProps: ["displayArea"]
(NOBRIDGE) LOG [2025-04-16T16:45:18.548Z] componentDidUpdate - isVisible not changed, handling other changes
(NOBRIDGE) LOG [2025-04-16T16:45:18.551Z] handleChange - no requestedContentSize, exiting...
(NOBRIDGE) LOG [2025-04-16T16:45:18.554Z] calculateRectFromRef - waiting for ref
(NOBRIDGE) LOG [2025-04-16T16:45:18.555Z] calculateRectFromRef - waiting for ref to move from: {"x":151.27273559570312,"y":450.54544830322266,"width":90.54545593261719,"height":19.272735595703125}
(NOBRIDGE) LOG [2025-04-16T16:45:18.557Z] measureContent - new requestedContentSize: {"width":168.00001525878906,"height":78.9090576171875} (used to be null)
(NOBRIDGE) LOG [2025-04-16T16:45:18.578Z] handleChange - waiting 100ms to accumulate all changes
(NOBRIDGE) LOG [2025-04-16T16:45:18.689Z] handleChange - requestedContentSize: {"width":168.00001525878906,"height":78.9090576171875}
(NOBRIDGE) LOG [2025-04-16T16:45:18.690Z] handleChange - displayArea: {"x":0,"y":0.00004438920450411388,"width":392.7272644042969,"height":825.4545288085938}
(NOBRIDGE) LOG [2025-04-16T16:45:18.691Z] handleChange - fromRect: {"x":151.27273559570312,"y":450.54544830322266,"width":90.54545593261719,"height":19.272735595703125}
(NOBRIDGE) LOG [2025-04-16T16:45:18.691Z] handleChange - placement: "auto"
(NOBRIDGE) LOG [2025-04-16T16:45:18.691Z] computeAutoGeometry - displayArea: {"x":0,"y":0.00004438920450411388,"width":392.7272644042969,"height":825.4545288085938}
(NOBRIDGE) LOG [2025-04-16T16:45:18.692Z] computeAutoGeometry - fromRect: {"x":151.27273559570312,"y":450.54544830322266,"width":90.54545593261719,"height":19.272735595703125}
(NOBRIDGE) LOG [2025-04-16T16:45:18.692Z] computeAutoGeometry - List of available space: {"left":{"sizeAvailable":135.27273559570312,"sizeRequested":168.00001525878906,"fits":false,"extraSpace":-32.72727966308594},"right":{"sizeAvailable":134.90907287597656,"sizeRequested":168.00001525878906,"fits":false,"extraSpace":-33.0909423828125},"top":{"sizeAvailable":434.54540391401815,"sizeRequested":78.9090576171875,"fits":true,"extraSpace":355.63634629683065},"bottom":{"sizeAvailable":339.6363892988725,"sizeRequested":78.9090576171875,"fits":true,"extraSpace":260.727331681685}}
(NOBRIDGE) LOG [2025-04-16T16:45:18.693Z] computeAutoGeometry - Found best postition for placement: "top"
(NOBRIDGE) LOG [2025-04-16T16:45:18.693Z] computeGeometry - initial chosen geometry: {"popoverOrigin":{"x":112.54545593261719,"y":363.63639068603516},"anchorPoint":{"x":196.54546356201172,"y":450.54544830322266},"placement":"top","forcedContentSize":{"width":372.7272644042969,"height":432.54540391401815},"viewLargerThanDisplayArea":{"height":false,"width":false}}
(NOBRIDGE) LOG [2025-04-16T16:45:18.694Z] computeGeometry - final chosen geometry: {"popoverOrigin":{"x":112.54545593261719,"y":363.63639068603516},"anchorPoint":{"x":196.54546356201172,"y":450.54544830322266},"placement":"top","forcedContentSize":{"width":372.7272644042969,"height":432.54540391401815},"viewLargerThanDisplayArea":{"height":false,"width":false}}
(NOBRIDGE) LOG [2025-04-16T16:45:18.714Z] handleChange - animating in
(NOBRIDGE) LOG [2025-04-16T16:45:18.718Z] getTranslateOrigin - popoverSize: {"width":168.00001525878906,"height":86.9090576171875}
(NOBRIDGE) LOG [2025-04-16T16:45:18.721Z] getTranslateOrigin - anchorPoint: {"x":196.54546356201172,"y":450.54544830322266}
(NOBRIDGE) LOG [2025-04-16T16:45:18.730Z] animateIn - translateStart: {"x":112.54545593261719,"y":1992.5454649491744}
(NOBRIDGE) LOG [2025-04-16T16:45:18.734Z] animateIn - translatePoint: {"x":112.54545593261719,"y":363.63639068603516}
(NOBRIDGE) LOG [2025-04-16T16:45:18.743Z] Setting up keyboard listeners
(NOBRIDGE) LOG [2025-04-16T16:45:19.126Z] animateIn - onOpenComplete - Calculated Popover Rect: {"x":112.54545593261719,"y":363.6363525390625,"width":168.00001525878906,"height":78.9091796875}
(NOBRIDGE) LOG [2025-04-16T16:45:19.127Z] animateIn - onOpenComplete - Calculated Arrow Rect: {"x":188.5454559326172,"y":440.727294921875,"width":18.181808471679688,"height":10.181884765625}
(NOBRIDGE) LOG [2025-04-16T16:45:20.631Z] measureContent - Skipping, content size did not change
(NOBRIDGE) LOG [2025-04-16T16:45:20.680Z] [BasePopover] componentDidUpdate - changedProps: ["isVisible"]
(NOBRIDGE) LOG [2025-04-16T16:45:20.683Z] componentDidUpdate - isVisible changed, now false
(NOBRIDGE) LOG [2025-04-16T16:45:20.686Z] animateOut - isMounted: true
(NOBRIDGE) LOG [2025-04-16T16:45:20.689Z] getTranslateOrigin - popoverSize: {"width":168.00001525878906,"height":86.9090576171875}
(NOBRIDGE) LOG [2025-04-16T16:45:20.692Z] getTranslateOrigin - anchorPoint: {"x":196.54546356201172,"y":450.54544830322266}
(NOBRIDGE) LOG [2025-04-16T16:45:20.697Z] componentDidUpdate - Hiding popover
(NOBRIDGE) LOG [2025-04-16T16:45:20.727Z] Tearing down keyboard listeners

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions