Skip to content

fix: show iOS NativeList quick-tap press state and add pager tab press animation switch OK-63487 - #114

Merged
huhuanming merged 4 commits into
mainfrom
fix/native-list-ios-quick-tap-press
Sep 17, 2026
Merged

huhuanming merged 4 commits into
mainfrom
fix/native-list-ios-quick-tap-press

Conversation

@huhuanming

@huhuanming huhuanming commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • native-list (iOS): a quick tap on a NativeList row now shows the pressed background before the tap action runs. Before this change, iOS showed it only when the finger stayed down longer than about 150 ms. Android already showed it on every tap. Only RNCNativeListView.swift changes for this fix. Props, the snapshot schema and Android are unchanged.
  • pager-view (iOS and Android): add nativeTabPressAnimationEnabled to CollapsiblePagerView, default true. With false, a native tab press jumps straight to the pressed page instead of animating through every page in between (OK-63487). JS-only; the default behavior is unchanged.
  • Released as 3.0.142 (NativeList fix) and 3.0.144 (both changes) with the latest dist-tag. 3.0.143 was skipped.

Root cause

  1. The list's UICollectionView keeps UIScrollView's default delaysContentTouches = true. UIKit holds touch-down back from the cells for about 150 ms while it decides whether the touch is a scroll.
  2. Row highlighting depends on that touch reaching the collection view (shouldHighlightItemAtNativeListCell.isHighlightedupdateBackgroundColor()).
  3. When the finger lifts inside the delay, UIKit sends the delayed touch-down and the touch-up back to back. The row is highlighted, unhighlighted and selected in the same run loop turn, so the pressed color is never drawn.
  4. Android sets pressedRowBackground directly on ACTION_DOWN in NativeListRowView, so a quick tap renders a few pressed frames there.

The ancestor CollapsiblePagerView scroll views already set delaysContentTouches = NO, so the delay came only from the list itself.

Change

  • A private NativeListCollectionView subclass sets delaysContentTouches = false.
  • touchesShouldCancel(in:) returns true for UIControl views. Without the delay, in-row buttons (tag badges, accessories, checkboxes) receive touches first, and UIScrollView's default would otherwise stop a drag that starts on them from scrolling the list. Other views keep super's behavior. Cells contain only UIButton controls, and the section index rail is outside the collection view.
  • Side effect, matching Android: didHighlightItemAt, and with it pressInActionKey (for example prewarm-detail), now runs on touch-down, including touches that turn into a scroll.

Verification

app-monorepo x (native modules 3.0.141) with this change applied in node_modules. The shell was rebuilt with dev-shell --platform ios --shell local, and the compiled OneKeyWallet.debug.dylib contains NativeListCollectionView. The baseline used the remote CI shell for the same lockfile. Both ran on an iPhone 17 Pro simulator (iOS 26.5): Market home, Stocks and Trending lists, recorded with simctl io recordVideo. The recorder writes a frame only when the screen changes.

Case Before (remote 3.0.141 shell) After (this change)
100 ms tap on AAPL No frame shows the pressed background; the push starts about 250 ms after the last idle frame Pressed background at 45.963 s, cleared at 46.067 s (~100 ms), push starts at 46.293 s
400 ms hold on NVDA Pressed from 6.890 s to 7.130 s (~240 ms, i.e. hold minus the delay) Pressed from 11.232 s to 11.635 s (~400 ms, the full hold)
Swipe up starting on a row The list scrolls and no detail page opens. The row shows the pressed color in the first frame (7.055 s), cleared 15 ms later when the pan is recognized
Swipe up starting on the community-recognized badge (UIButton) The list scrolls and the tag popover does not open
Tap on the same badge The "Tag · Community-recognized" popover opens

Real device: iPhone 17 Pro, iOS 27.0 (24A437), app-monorepo Market home with this change in node_modules. Quick taps on rows now show the pressed background before the detail page opens, which they did not before.

Local Xcode 27 builds of app-monorepo currently crash at launch on iOS 27 in _UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption, because the app has not adopted the UIScene lifecycle. That is unrelated to this change. For this device test only, the built main executable's LC_BUILD_VERSION SDK was set to 26.0 with vtool, and the app was re-signed with the same development identity.

Not covered:

  • Horizontal (rail) layouts, reorderable lists and the wallet group rows.
  • keyboardShouldPersistTaps / keyboardDismissMode screens with a focused text input.
  • Dark mode.

pager-view: nativeTabPressAnimationEnabled (OK-63487)

Problem

CollapsiblePagerView.onNativeTabPress always dispatched an animated setPage. The iOS direct pager animates its content offset over 0.28 s and Android's ViewPager2 smooth-scrolls, so pressing a distant tab scrolled through every page in between. With pageRetentionDistance={1} those pages are unmounted, so app-monorepo's Market home showed blank pages and neighboring lists sliding past under a sticky header that had already switched to the pressed tab. Before the native pager migration, Market tab presses switched without animation (app-monorepo #12842, tabPressAnimationEnabled={false}).

app-monorepo currently works around it in MobileLayout.native.tsx: its onNativeTabPress handler sends a second setPageWithoutAnimation, which supersedes the queued animated command, and it tracks the last native page selection so a repeated press on a pending tab is superseded as well.

Change

  • nativeTabPressAnimationEnabled?: boolean, default true. With false, onNativeTabPress dispatches setPageWithoutAnimation through the same dispatchNativeTabPageCommand path, so the pressed page is still added to the retained pages before the command runs.
  • The prop is consumed by the JS wrapper and not forwarded to the native component. Swipes and the imperative setPage / setPageWithoutAnimation methods are unchanged.
  • The pager README documents the prop.

Verification

  • example/react-native: jest __tests__/CollapsiblePagerView.web.test.tsx passes 10/10. The new native wrapper cases press a distant native tab and assert that the default dispatches Commands.setPage and nativeTabPressAnimationEnabled={false} dispatches only Commands.setPageWithoutAnimation. The disabled case failed before the change.
  • react-native-pager-view: yarn typecheck passes; Prettier passes on the changed files.
  • The native path this selects was verified through the app-monorepo workaround, which sends the same setPageWithoutAnimation command on every tab press. Recorded on an iPhone 17 Pro simulator (iOS 26.5) and an Android 15 emulator: distant taps and rapid double taps switch in one frame without showing intermediate pages, and swipes still animate. The prop itself has not run on a device yet. app-monorepo adopts it and drops the workaround in fix: switch market tabs without the pager animation OK-63487 app-monorepo#13523.

Release

Commit Change
e4a27ebea fix(ios): show NativeList row press state on quick taps
4195671ec chore: bump packages to 3.0.142
e5bd5bfaf feat(pager-view): let native tab presses skip the page animation OK-63487
3c1a744d1 chore: bump packages to 3.0.144

Published from this branch with the latest dist-tag. For 3.0.142, the run's registry check passed for all packages, and the downloaded @onekeyfe/react-native-native-list@3.0.142 tarball's ios/RNCNativeListView.swift is byte-identical to the file verified on the simulator and on the iPhone.

For 3.0.144, the run's registry check passed and npm view reports 3.0.144 as latest for all 40 packages. The downloaded @onekeyfe/react-native-pager-view@3.0.144 tarball's src/CollapsiblePagerView.tsx is byte-identical to 3c1a744d1, and its compiled lib/module and type declarations include nativeTabPressAnimationEnabled.

Version Commit Publish run app-monorepo pin bump
3.0.142 4195671ec 35181537599 OneKeyHQ/app-monorepo#13514
3.0.144 3c1a744d1 35194067917 OneKeyHQ/app-monorepo#13523

🤖 Generated with Claude Code

huhuanming and others added 2 commits September 17, 2026 11:19
UICollectionView inherits UIScrollView's delaysContentTouches = true, so a
row receives touch-down only after about 150 ms, once UIKit knows the touch
is not a scroll. A tap released inside that window gets the delayed
touch-down and the touch-up back to back: the row is highlighted,
unhighlighted and selected in one run loop turn, so the pressed background
never renders. Android rows set their pressed background on ACTION_DOWN,
so the same tap shows feedback there.

- use a NativeListCollectionView subclass with delaysContentTouches = false;
  didHighlightItemAt, and with it pressInActionKey, now runs on touch-down
  as it does on Android
- return true from touchesShouldCancel(in:) for UIControl views so a drag
  that starts on an in-row button (tag badge, accessory, checkbox) still
  scrolls the list

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bump all 40 publishable packages to 3.0.142 and record the iOS
NativeList quick-tap press state fix in the changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
originalix pushed a commit to OneKeyHQ/app-monorepo that referenced this pull request Sep 17, 2026
#13514)

* fix: disable pull-to-refresh on market home pager lists

iOS still attached a UIRefreshControl to the Market home NativeList
pages; Android had it disabled already. A pull showed a spinner that
disappeared almost immediately. Drop the refresh wiring from
NativeMarketList and its token, watchlist, stock, top coins and perps
callers so the snapshot keeps pullToRefresh off on both platforms.
Error and load-more retry rows still refetch.

* fix: upgrade native modules to 3.0.142 for iOS row press state

Pin all @onekeyfe native modules to 3.0.142. It ships the iOS NativeList
fix from OneKeyHQ/app-modules#114: the list's UICollectionView no longer
delays touch-down by about 150 ms, so a quick tap on a Market row renders
the pressed background before the detail page opens, matching Android.

* chore: add iOS 27 device install script for local builds

Local Xcode 27 builds link against the iOS 27 SDK, and iOS 27 then stops
any app that has not adopted the UIScene lifecycle at launch
(_UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption). Until
OneKeyWallet adopts UIScene, development/scripts/ios27-device-install.sh
copies the device Debug build and rewrites the main executable's
LC_BUILD_VERSION SDK to 26.0. It re-signs the copy with the original
identity and entitlements, then installs and launches it against Metro.
huhuanming and others added 2 commits September 17, 2026 15:16
…3487

CollapsiblePagerView dispatched an animated setPage for every native tab
press. The iOS direct pager animates its content offset and Android's
ViewPager2 smooth-scrolls, so pressing a distant tab scrolled through every
page in between. With pageRetentionDistance={1} those pages are unmounted,
so they showed blank while neighboring lists slid past under a sticky
header that had already switched to the pressed tab. app-monorepo's Market
home had to send a second, non-animated command from onNativeTabPress to
supersede it.

- add nativeTabPressAnimationEnabled, default true; when false a native
  tab press dispatches setPageWithoutAnimation through the same
  retain-then-dispatch path, so the pressed page is still mounted before
  the pager moves
- document the prop in the pager README
- cover the default and disabled modes in the native wrapper tests

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bump all 40 publishable packages to 3.0.144 and record the pager-view
nativeTabPressAnimationEnabled prop in the changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@huhuanming huhuanming changed the title fix(ios): show NativeList row press state on quick taps fix: show iOS NativeList quick-tap press state and add pager tab press animation switch OK-63487 Sep 17, 2026
@huhuanming
huhuanming merged commit 15d7aa9 into main Sep 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants