harmonyos-best-practices-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -0
- package/data/docs/bpta-2in1-window-shape.md +296 -0
- package/data/docs/bpta-abckitts-implements-instrumentation.md +1279 -0
- package/data/docs/bpta-add-watermark.md +379 -0
- package/data/docs/bpta-ads-jump.md +67 -0
- package/data/docs/bpta-agent.md +472 -0
- package/data/docs/bpta-always-on-market-watch.md +703 -0
- package/data/docs/bpta-analysis-of-image-blurring.md +231 -0
- package/data/docs/bpta-analyze-memory-problem.md +17 -0
- package/data/docs/bpta-animation-frame.md +28 -0
- package/data/docs/bpta-antipeep-protection.md +291 -0
- package/data/docs/bpta-app-architecture-overview.md +25 -0
- package/data/docs/bpta-app-asset-protection-design.md +277 -0
- package/data/docs/bpta-app-code-ob.md +180 -0
- package/data/docs/bpta-app-concurrency-design.md +1189 -0
- package/data/docs/bpta-app-data-security.md +397 -0
- package/data/docs/bpta-app-icon-configuration.md +226 -0
- package/data/docs/bpta-app-privacy-protection.md +295 -0
- package/data/docs/bpta-application-aspect-programming-design.md +675 -0
- package/data/docs/bpta-application-cold-start-optimization.md +1397 -0
- package/data/docs/bpta-application-continue-progess.md +285 -0
- package/data/docs/bpta-application-gesture-share.md +468 -0
- package/data/docs/bpta-application-knock-file-share.md +263 -0
- package/data/docs/bpta-application-knock-video-share.md +552 -0
- package/data/docs/bpta-application-latency-optimization-cases.md +615 -0
- package/data/docs/bpta-application-power-analysis.md +15 -0
- package/data/docs/bpta-application-power-optimization.md +12 -0
- package/data/docs/bpta-application-power-test.md +52 -0
- package/data/docs/bpta-application-track-practice.md +595 -0
- package/data/docs/bpta-arkts-high-performance.md +464 -0
- package/data/docs/bpta-arkts-js-memory-analysis.md +111 -0
- package/data/docs/bpta-arkts-language.md +18 -0
- package/data/docs/bpta-arkweb-component-security.md +1134 -0
- package/data/docs/bpta-arkweb_rendering_framework.md +412 -0
- package/data/docs/bpta-aspect-implements-aop.md +505 -0
- package/data/docs/bpta-audio-and-video.md +30 -0
- package/data/docs/bpta-audio-cast.md +460 -0
- package/data/docs/bpta-audio-focus-management.md +862 -0
- package/data/docs/bpta-audio-in-ear-monitor.md +803 -0
- package/data/docs/bpta-audio-playback-series.md +16 -0
- package/data/docs/bpta-audio-record-base-on-audiocapturer.md +188 -0
- package/data/docs/bpta-audio-record-base-on-avrecorder-arkts.md +179 -0
- package/data/docs/bpta-audio-record-base-on-avrecorder.md +207 -0
- package/data/docs/bpta-audio-record-base-on-avscreencapture.md +165 -0
- package/data/docs/bpta-audio-record-base-on-ohaudio.md +162 -0
- package/data/docs/bpta-audio-record-overview.md +34 -0
- package/data/docs/bpta-audio-record.md +16 -0
- package/data/docs/bpta-audio-ripple-animation.md +198 -0
- package/data/docs/bpta-audio-video-synchronization.md +508 -0
- package/data/docs/bpta-audio-video.md +15 -0
- package/data/docs/bpta-automated-testing-frameworks.md +481 -0
- package/data/docs/bpta-avplayer-basic-control.md +533 -0
- package/data/docs/bpta-avplayer-embeded-network-video.md +486 -0
- package/data/docs/bpta-avplayer-embeded-short-video.md +512 -0
- package/data/docs/bpta-avplayer-long-video.md +907 -0
- package/data/docs/bpta-avplayer-short-video.md +158 -0
- package/data/docs/bpta-avplayer-video-practices.md +15 -0
- package/data/docs/bpta-avscreencapture-for-screen-recording.md +1121 -0
- package/data/docs/bpta-back-task-implement.md +317 -0
- package/data/docs/bpta-background-blur.md +316 -0
- package/data/docs/bpta-background-sensors-baned-analysis.md +93 -0
- package/data/docs/bpta-best-practices-long-list.md +891 -0
- package/data/docs/bpta-best-practices-overview.md +48 -0
- package/data/docs/bpta-bluetooth-low-energy.md +905 -0
- package/data/docs/bpta-buffer-mode-transcoding.md +728 -0
- package/data/docs/bpta-buffer-power-optimization.md +224 -0
- package/data/docs/bpta-camera-shot2see.md +368 -0
- package/data/docs/bpta-card-update-and-data-interaction.md +670 -0
- package/data/docs/bpta-carousel-graphic-works.md +379 -0
- package/data/docs/bpta-cell-phone.md +13 -0
- package/data/docs/bpta-click-to-click-response-optimization.md +264 -0
- package/data/docs/bpta-click-to-complete-delay-analysis.md +637 -0
- package/data/docs/bpta-collaboration-office.md +1178 -0
- package/data/docs/bpta-comment-reply-pop-up-window.md +523 -0
- package/data/docs/bpta-common-list-flows.md +688 -0
- package/data/docs/bpta-common-list-operations.md +828 -0
- package/data/docs/bpta-common-network-query.md +784 -0
- package/data/docs/bpta-comparative_practice_of_taskpool_and_worker.md +381 -0
- package/data/docs/bpta-compatible-scheme.md +11 -0
- package/data/docs/bpta-complex-type-pass.md +868 -0
- package/data/docs/bpta-component-nesting-optimization.md +421 -0
- package/data/docs/bpta-component-reuse-issue-diagnosis-and-analysis.md +637 -0
- package/data/docs/bpta-component-reuse.md +1258 -0
- package/data/docs/bpta-concurrency-capability.md +23 -0
- package/data/docs/bpta-concurrent-optimization.md +369 -0
- package/data/docs/bpta-content-creation.md +646 -0
- package/data/docs/bpta-continue-cast.md +702 -0
- package/data/docs/bpta-continue-data.md +335 -0
- package/data/docs/bpta-continue.md +1323 -0
- package/data/docs/bpta-control-rendering-range.md +29 -0
- package/data/docs/bpta-controlling-background-process-cpu.md +31 -0
- package/data/docs/bpta-crash-monitor-practice.md +116 -0
- package/data/docs/bpta-cross-domain-solutions-for-web-pages.md +308 -0
- package/data/docs/bpta-cross-end-migration.md +13 -0
- package/data/docs/bpta-cross-module-reference.md +406 -0
- package/data/docs/bpta-cross-platform-compatibility.md +321 -0
- package/data/docs/bpta-custom-camera-photo.md +454 -0
- package/data/docs/bpta-custom-camera-preview.md +1170 -0
- package/data/docs/bpta-custom-camera-video.md +322 -0
- package/data/docs/bpta-custom-font-settings.md +354 -0
- package/data/docs/bpta-custom-hvigor-plugin.md +159 -0
- package/data/docs/bpta-custom-keyboard.md +519 -0
- package/data/docs/bpta-customdialog-selection-and-development.md +406 -0
- package/data/docs/bpta-dark-mode-adaptation.md +321 -0
- package/data/docs/bpta-deal-stride-solution.md +261 -0
- package/data/docs/bpta-decrease_pakage_size.md +126 -0
- package/data/docs/bpta-delayed-trigger-operation.md +215 -0
- package/data/docs/bpta-desktop-shortcuts.md +180 -0
- package/data/docs/bpta-detection.md +12 -0
- package/data/docs/bpta-developing-high-performance-ui.md +19 -0
- package/data/docs/bpta-development-scenarios-for-tabs.md +934 -0
- package/data/docs/bpta-dialog-encapsulation.md +201 -0
- package/data/docs/bpta-dispose-highly-loaded-component-render.md +352 -0
- package/data/docs/bpta-distribute-drag-cast.md +60 -0
- package/data/docs/bpta-distributed-pasteboard-cast.md +88 -0
- package/data/docs/bpta-distributed-pasteboard.md +314 -0
- package/data/docs/bpta-drawing-capability-improve-performance.md +436 -0
- package/data/docs/bpta-dynamic-link-library.md +272 -0
- package/data/docs/bpta-easygo-parallel.md +402 -0
- package/data/docs/bpta-fair-use-animation.md +1693 -0
- package/data/docs/bpta-file-transmission-based-on-sfft.md +265 -0
- package/data/docs/bpta-file-upload-and-download-performance.md +484 -0
- package/data/docs/bpta-foldable-guide.md +205 -0
- package/data/docs/bpta-folded-hover.md +202 -0
- package/data/docs/bpta-form-kit.md +12 -0
- package/data/docs/bpta-frontend-invisible-animation-analysis.md +187 -0
- package/data/docs/bpta-full-scenario-collaborative-development.md +13 -0
- package/data/docs/bpta-fuzzy-scene-performance-optimization.md +256 -0
- package/data/docs/bpta-game-prelaunch-practice.md +175 -0
- package/data/docs/bpta-general-comments.md +17 -0
- package/data/docs/bpta-gestures-practice.md +619 -0
- package/data/docs/bpta-global-state-management-state-store.md +472 -0
- package/data/docs/bpta-gpu-acceleration-practices.md +11 -0
- package/data/docs/bpta-graphic-drawing-practices.md +13 -0
- package/data/docs/bpta-grid-based-on-scrollcomponents.md +1112 -0
- package/data/docs/bpta-grid-drag-swap.md +725 -0
- package/data/docs/bpta-hadss_dialoghub.md +786 -0
- package/data/docs/bpta-harmony-application-security.md +1253 -0
- package/data/docs/bpta-hdrtosdr.md +439 -0
- package/data/docs/bpta-hdrvivid.md +700 -0
- package/data/docs/bpta-high-cpu-load-analysis.md +113 -0
- package/data/docs/bpta-high-performance-json-parsing.md +263 -0
- package/data/docs/bpta-high-performance-protobuf-parsing.md +259 -0
- package/data/docs/bpta-hmos-live-stream-audio-call.md +140 -0
- package/data/docs/bpta-hmos-live-stream-solution.md +495 -0
- package/data/docs/bpta-hmrouter.md +659 -0
- package/data/docs/bpta-hopping.md +60 -0
- package/data/docs/bpta-hwc-self-rendering-layer-analysis.md +77 -0
- package/data/docs/bpta-image-processing-practices.md +13 -0
- package/data/docs/bpta-image-to-video-synthesis.md +459 -0
- package/data/docs/bpta-image-white-lump-solution.md +282 -0
- package/data/docs/bpta-image_get_and_save.md +120 -0
- package/data/docs/bpta-implement-timeline-based-on-canvas.md +493 -0
- package/data/docs/bpta-implementing-image-filters.md +406 -0
- package/data/docs/bpta-implementing-image-resizable.md +270 -0
- package/data/docs/bpta-improve-layout-performance.md +547 -0
- package/data/docs/bpta-improve-running-efficiency.md +187 -0
- package/data/docs/bpta-improve_grid_performance.md +268 -0
- package/data/docs/bpta-input-method-framework.md +12 -0
- package/data/docs/bpta-intent-recommend-practice.md +313 -0
- package/data/docs/bpta-js-leak-watcher.md +153 -0
- package/data/docs/bpta-kernel-memory-analysis.md +38 -0
- package/data/docs/bpta-keyboard-layout-adapt.md +725 -0
- package/data/docs/bpta-landscape-and-portrait-development.md +947 -0
- package/data/docs/bpta-layered-architecture-design.md +82 -0
- package/data/docs/bpta-lazyforeach-optimization.md +217 -0
- package/data/docs/bpta-link-between-apps-overview.md +99 -0
- package/data/docs/bpta-list-based-on-scrollcomponents.md +1643 -0
- package/data/docs/bpta-lite-wearable-guide.md +1899 -0
- package/data/docs/bpta-live-form-development-practice.md +544 -0
- package/data/docs/bpta-live-streaming-optimization.md +397 -0
- package/data/docs/bpta-local-file-and-data-multithreaded-io.md +367 -0
- package/data/docs/bpta-local-file.md +11 -0
- package/data/docs/bpta-lock-screen-immersive-live-window.md +473 -0
- package/data/docs/bpta-long-snapshot-practice.md +1046 -0
- package/data/docs/bpta-low-power-consumption-of-background-tasks.md +14 -0
- package/data/docs/bpta-low-power-consumption-of-foreground-tasks.md +14 -0
- package/data/docs/bpta-low-power-design-in-dark-mode.md +418 -0
- package/data/docs/bpta-ltpo-description.md +323 -0
- package/data/docs/bpta-maleoon-gpu-best-practices.md +1297 -0
- package/data/docs/bpta-malloc-dispatch-table.md +144 -0
- package/data/docs/bpta-managing-audio-input-devices.md +350 -0
- package/data/docs/bpta-managing-audio-output-devices.md +399 -0
- package/data/docs/bpta-mate-book-fold.md +229 -0
- package/data/docs/bpta-matetv-guide.md +223 -0
- package/data/docs/bpta-matext-guide.md +269 -0
- package/data/docs/bpta-memory-basic-knowledge.md +71 -0
- package/data/docs/bpta-memory-optimization.md +545 -0
- package/data/docs/bpta-modular-design.md +282 -0
- package/data/docs/bpta-multi-device-adaptive-layout.md +775 -0
- package/data/docs/bpta-multi-device-adaptive.md +11 -0
- package/data/docs/bpta-multi-device-camera.md +584 -0
- package/data/docs/bpta-multi-device-collaboration.md +19 -0
- package/data/docs/bpta-multi-device-component-layout.md +190 -0
- package/data/docs/bpta-multi-device-design-principles.md +26 -0
- package/data/docs/bpta-multi-device-function.md +99 -0
- package/data/docs/bpta-multi-device-hardware.md +12 -0
- package/data/docs/bpta-multi-device-ide.md +124 -0
- package/data/docs/bpta-multi-device-interaction.md +11 -0
- package/data/docs/bpta-multi-device-layout-overview.md +47 -0
- package/data/docs/bpta-multi-device-overview.md +340 -0
- package/data/docs/bpta-multi-device-page-layout.md +699 -0
- package/data/docs/bpta-multi-device-page.md +19 -0
- package/data/docs/bpta-multi-device-resource.md +122 -0
- package/data/docs/bpta-multi-device-responsive-layout.md +1274 -0
- package/data/docs/bpta-multi-device-responsive.md +14 -0
- package/data/docs/bpta-multi-device-screen-diff.md +197 -0
- package/data/docs/bpta-multi-device-screen-layout.md +834 -0
- package/data/docs/bpta-multi-device-start.md +376 -0
- package/data/docs/bpta-multi-device-ui-development.md +27 -0
- package/data/docs/bpta-multi-device-window-direction.md +1322 -0
- package/data/docs/bpta-multi-device-window-immersive.md +364 -0
- package/data/docs/bpta-multi-device-window-mode.md +1293 -0
- package/data/docs/bpta-multi-device-window.md +13 -0
- package/data/docs/bpta-multi-device.md +13 -0
- package/data/docs/bpta-multi-interaction.md +368 -0
- package/data/docs/bpta-multi-mobile-payment.md +282 -0
- package/data/docs/bpta-multi-music-app-overview.md +365 -0
- package/data/docs/bpta-multi-settings-application-page.md +163 -0
- package/data/docs/bpta-multi-tab-practice.md +750 -0
- package/data/docs/bpta-multi-target.md +490 -0
- package/data/docs/bpta-multi-window-practice.md +795 -0
- package/data/docs/bpta-multi_game.md +472 -0
- package/data/docs/bpta-music-card.md +1916 -0
- package/data/docs/bpta-music-playback-scenarios.md +120 -0
- package/data/docs/bpta-native-memory-analysis.md +101 -0
- package/data/docs/bpta-native-sub-main-comm.md +323 -0
- package/data/docs/bpta-navigation-scenarios.md +69 -0
- package/data/docs/bpta-network-ca-security.md +241 -0
- package/data/docs/bpta-network-reconnection.md +327 -0
- package/data/docs/bpta-network-resources.md +24 -0
- package/data/docs/bpta-news-reading.md +12 -0
- package/data/docs/bpta-news_homepage.md +449 -0
- package/data/docs/bpta-object-serialization-performance.md +12 -0
- package/data/docs/bpta-one-shot-to-the-end.md +932 -0
- package/data/docs/bpta-online-video-playback-lags-practice.md +298 -0
- package/data/docs/bpta-optimization-overview.md +227 -0
- package/data/docs/bpta-optimization-tool-practice.md +20 -0
- package/data/docs/bpta-package-structure.md +13 -0
- package/data/docs/bpta-pad-guide.md +268 -0
- package/data/docs/bpta-page-brightness-settings.md +256 -0
- package/data/docs/bpta-page-transition.md +583 -0
- package/data/docs/bpta-pc-guide.md +438 -0
- package/data/docs/bpta-pc.md +12 -0
- package/data/docs/bpta-perceived-smoothness.md +49 -0
- package/data/docs/bpta-performance-detection.md +160 -0
- package/data/docs/bpta-performance-guide-reading.md +50 -0
- package/data/docs/bpta-performance-mainthread-consumption-detection.md +11 -0
- package/data/docs/bpta-performance-optimization.md +23 -0
- package/data/docs/bpta-performance-runtime-detection.md +13 -0
- package/data/docs/bpta-performance-sliding-frame-drop-detection.md +19 -0
- package/data/docs/bpta-performance-startup-time-detection.md +13 -0
- package/data/docs/bpta-permission-application.md +318 -0
- package/data/docs/bpta-permission-timeout-analysis.md +51 -0
- package/data/docs/bpta-photo.md +15 -0
- package/data/docs/bpta-picture-preview.md +464 -0
- package/data/docs/bpta-picture.md +12 -0
- package/data/docs/bpta-playing-formatted-audio-based-avplayer-arkts.md +481 -0
- package/data/docs/bpta-playing-formatted-audio-based-avplayer-cpp.md +593 -0
- package/data/docs/bpta-playing-pcm-audio-based-audiorenderer.md +959 -0
- package/data/docs/bpta-playing-pcm-audio-based-ohaudio.md +599 -0
- package/data/docs/bpta-playing-short-audio-based-soundpool.md +182 -0
- package/data/docs/bpta-positioning.md +364 -0
- package/data/docs/bpta-power-basic-quality-test.md +35 -0
- package/data/docs/bpta-power-consumption-analysis.md +12 -0
- package/data/docs/bpta-power-consumption-develop-analysis.md +12 -0
- package/data/docs/bpta-power-consumption-experience.md +119 -0
- package/data/docs/bpta-power-consumption-runtime-analysis.md +15 -0
- package/data/docs/bpta-power_overview.md +26 -0
- package/data/docs/bpta-pptimized-component-drawing.md +27 -0
- package/data/docs/bpta-pre-connect.md +133 -0
- package/data/docs/bpta-preloading-resources.md +21 -0
- package/data/docs/bpta-program-framework.md +15 -0
- package/data/docs/bpta-properly-use-foreground-resources.md +22 -0
- package/data/docs/bpta-purax-guide.md +215 -0
- package/data/docs/bpta-quality-overview.md +79 -0
- package/data/docs/bpta-reader-page-flip.md +890 -0
- package/data/docs/bpta-reasonable-audio-playback-use.md +42 -0
- package/data/docs/bpta-reasonable-audio-use.md +163 -0
- package/data/docs/bpta-reasonable-bluetooth-use.md +52 -0
- package/data/docs/bpta-reasonable-gps-use.md +59 -0
- package/data/docs/bpta-reasonable-network-use.md +105 -0
- package/data/docs/bpta-reasonable-position-navigation-use.md +47 -0
- package/data/docs/bpta-reasonable-request-use.md +77 -0
- package/data/docs/bpta-reasonable-sensor-use.md +53 -0
- package/data/docs/bpta-reasonable-system-use.md +67 -0
- package/data/docs/bpta-recommended-use-of-device-id.md +79 -0
- package/data/docs/bpta-reduce-layout-nodes.md +30 -0
- package/data/docs/bpta-reduce-time-consuming.md +36 -0
- package/data/docs/bpta-redundancy-refresh-guide.md +409 -0
- package/data/docs/bpta-render-web-using-same-layer-render.md +601 -0
- package/data/docs/bpta-resource-and-storage-optimization.md +14 -0
- package/data/docs/bpta-retrieve-process-memory-info.md +49 -0
- package/data/docs/bpta-rich-text-display.md +475 -0
- package/data/docs/bpta-rich-text-editor.md +426 -0
- package/data/docs/bpta-risk-control-engine.md +146 -0
- package/data/docs/bpta-scenario-performance-optimization.md +17 -0
- package/data/docs/bpta-scenario-power-optimization.md +12 -0
- package/data/docs/bpta-scenario-stability-address-sanitizer.md +210 -0
- package/data/docs/bpta-scenario-stability-app-freeze.md +615 -0
- package/data/docs/bpta-scenario-stability-cppcrash.md +516 -0
- package/data/docs/bpta-scenario-stability-exception-exit.md +12 -0
- package/data/docs/bpta-scenario-stability-jscrash.md +922 -0
- package/data/docs/bpta-scenario-stability-leak.md +276 -0
- package/data/docs/bpta-scenario-stability.md +14 -0
- package/data/docs/bpta-screen-flicker-solution.md +480 -0
- package/data/docs/bpta-shared-bicycle.md +509 -0
- package/data/docs/bpta-short-video-base-adaptivevideo.md +403 -0
- package/data/docs/bpta-smart-reach.md +306 -0
- package/data/docs/bpta-smartwatch.md +755 -0
- package/data/docs/bpta-smartwatchnavigation.md +384 -0
- package/data/docs/bpta-smooth-application-design.md +225 -0
- package/data/docs/bpta-smooth-switching.md +294 -0
- package/data/docs/bpta-social-communications.md +11 -0
- package/data/docs/bpta-social-share.md +637 -0
- package/data/docs/bpta-solutions-to-special-issues.md +12 -0
- package/data/docs/bpta-sound-quality-switching.md +422 -0
- package/data/docs/bpta-spatiality-immersive.md +531 -0
- package/data/docs/bpta-special-text-recognition.md +137 -0
- package/data/docs/bpta-stability-address-illegal-way.md +190 -0
- package/data/docs/bpta-stability-address-sanitizer-catagory.md +212 -0
- package/data/docs/bpta-stability-address-sanitizer-faq.md +32 -0
- package/data/docs/bpta-stability-address-sanitizer-opt.md +170 -0
- package/data/docs/bpta-stability-address-sanitizer-overview.md +23 -0
- package/data/docs/bpta-stability-address-sanitizer-principle.md +179 -0
- package/data/docs/bpta-stability-analysis.md +17 -0
- package/data/docs/bpta-stability-app-analyzer.md +11 -0
- package/data/docs/bpta-stability-app-crash-cpp-way.md +200 -0
- package/data/docs/bpta-stability-app-crash-js-way.md +148 -0
- package/data/docs/bpta-stability-app-crash.md +13 -0
- package/data/docs/bpta-stability-app-freeze-ark-runtime.md +339 -0
- package/data/docs/bpta-stability-app-freeze-opt.md +80 -0
- package/data/docs/bpta-stability-app-freeze-way.md +410 -0
- package/data/docs/bpta-stability-app-freeze.md +12 -0
- package/data/docs/bpta-stability-app-killed-way.md +49 -0
- package/data/docs/bpta-stability-ark-detection.md +12 -0
- package/data/docs/bpta-stability-ark-exception-detection.md +38 -0
- package/data/docs/bpta-stability-ark-runtime-detection.md +134 -0
- package/data/docs/bpta-stability-asan-detection.md +450 -0
- package/data/docs/bpta-stability-coding-standard-api.md +2054 -0
- package/data/docs/bpta-stability-coding-standard-cpp.md +91 -0
- package/data/docs/bpta-stability-coding-standard-libuv.md +772 -0
- package/data/docs/bpta-stability-coding-standard-ndk-arkts.md +189 -0
- package/data/docs/bpta-stability-coding-standard-node.md +478 -0
- package/data/docs/bpta-stability-coding-standard.md +16 -0
- package/data/docs/bpta-stability-cpp-crash-opt.md +346 -0
- package/data/docs/bpta-stability-detection.md +14 -0
- package/data/docs/bpta-stability-deveco-testing.md +73 -0
- package/data/docs/bpta-stability-develop-detection.md +17 -0
- package/data/docs/bpta-stability-exception-exit-opt.md +12 -0
- package/data/docs/bpta-stability-fault-log.md +14 -0
- package/data/docs/bpta-stability-fault-type.md +31 -0
- package/data/docs/bpta-stability-file-handle-detection.md +96 -0
- package/data/docs/bpta-stability-gwpasan-detection.md +588 -0
- package/data/docs/bpta-stability-hwasan-detection.md +360 -0
- package/data/docs/bpta-stability-ide-static-detection.md +343 -0
- package/data/docs/bpta-stability-js-crash-opt.md +21 -0
- package/data/docs/bpta-stability-js-memleak-detection.md +214 -0
- package/data/docs/bpta-stability-leak-detection.md +15 -0
- package/data/docs/bpta-stability-leak-opt.md +251 -0
- package/data/docs/bpta-stability-leak-way.md +459 -0
- package/data/docs/bpta-stability-log-specs.md +31 -0
- package/data/docs/bpta-stability-log-standard-hilog.md +191 -0
- package/data/docs/bpta-stability-log-standard.md +11 -0
- package/data/docs/bpta-stability-memleak-detection-overview.md +109 -0
- package/data/docs/bpta-stability-native-memleak-detection.md +204 -0
- package/data/docs/bpta-stability-operate-apm.md +113 -0
- package/data/docs/bpta-stability-operate-app-event.md +320 -0
- package/data/docs/bpta-stability-operate-event.md +11 -0
- package/data/docs/bpta-stability-operate.md +15 -0
- package/data/docs/bpta-stability-opt.md +18 -0
- package/data/docs/bpta-stability-overview.md +17 -0
- package/data/docs/bpta-stability-ram-detection.md +17 -0
- package/data/docs/bpta-stability-runtime-address-sanitizer-detection.md +21 -0
- package/data/docs/bpta-stability-runtime-appkilled-detection.md +44 -0
- package/data/docs/bpta-stability-runtime-crash-detection.md +14 -0
- package/data/docs/bpta-stability-runtime-detection.md +14 -0
- package/data/docs/bpta-stability-runtime-exception-exit-detection.md +12 -0
- package/data/docs/bpta-stability-runtime-freeze-detection.md +21 -0
- package/data/docs/bpta-stability-runtime-leak-detection.md +31 -0
- package/data/docs/bpta-stability-testing.md +11 -0
- package/data/docs/bpta-stability-thread-detection.md +11 -0
- package/data/docs/bpta-stability-thread-leak-detection.md +35 -0
- package/data/docs/bpta-stability-tsan-detection.md +477 -0
- package/data/docs/bpta-stability-ubsan-detection.md +350 -0
- package/data/docs/bpta-startup-response-optimization.md +12 -0
- package/data/docs/bpta-state-refresh.md +48 -0
- package/data/docs/bpta-static-scenarios.md +63 -0
- package/data/docs/bpta-status-management.md +872 -0
- package/data/docs/bpta-surface-encoder.md +427 -0
- package/data/docs/bpta-swiper_high_performance_development_guide.md +357 -0
- package/data/docs/bpta-tablet-pc.md +11 -0
- package/data/docs/bpta-taskpool_usage_specifications_and_faqs.md +625 -0
- package/data/docs/bpta-text-expand-collapse.md +274 -0
- package/data/docs/bpta-texture-compression-improve-performance.md +336 -0
- package/data/docs/bpta-thread-priority-setting.md +233 -0
- package/data/docs/bpta-threads-serialization-timeout-analysis.md +169 -0
- package/data/docs/bpta-time-optimization-of-the-main-thread.md +1239 -0
- package/data/docs/bpta-travel-navigation.md +11 -0
- package/data/docs/bpta-tv.md +11 -0
- package/data/docs/bpta-ui-component-encapsulation.md +585 -0
- package/data/docs/bpta-ui-component-performance-optimization.md +597 -0
- package/data/docs/bpta-ui-dynamic-operations.md +618 -0
- package/data/docs/bpta-ui-skip-analysis.md +191 -0
- package/data/docs/bpta-unified-drag-and-drop.md +1189 -0
- package/data/docs/bpta-use-of-background-hardware-resources.md +16 -0
- package/data/docs/bpta-use-of-background-software-resources.md +14 -0
- package/data/docs/bpta-use-of-background-tasks.md +23 -0
- package/data/docs/bpta-utilize-hwc-efficiently.md +461 -0
- package/data/docs/bpta-vdeocast.md +558 -0
- package/data/docs/bpta-video-adaptation-based-web.md +462 -0
- package/data/docs/bpta-video-barrage.md +68 -0
- package/data/docs/bpta-video-codec.md +42 -0
- package/data/docs/bpta-video-component-long-video.md +659 -0
- package/data/docs/bpta-video-component-short-video.md +337 -0
- package/data/docs/bpta-video-layer.md +32 -0
- package/data/docs/bpta-video-practices.md +12 -0
- package/data/docs/bpta-video-render.md +1225 -0
- package/data/docs/bpta-video-rom.md +37 -0
- package/data/docs/bpta-video-thumbnail.md +179 -0
- package/data/docs/bpta-video-wifi.md +40 -0
- package/data/docs/bpta-vsync-power-optimization.md +116 -0
- package/data/docs/bpta-waterflow-based-on-scrollcomponents.md +989 -0
- package/data/docs/bpta-waterflow-operations.md +991 -0
- package/data/docs/bpta-waterflow-performance-optimization.md +191 -0
- package/data/docs/bpta-wavewheel-for-image-editor.md +421 -0
- package/data/docs/bpta-wear.md +12 -0
- package/data/docs/bpta-web-adaptation.md +451 -0
- package/data/docs/bpta-web-app-jump-and-pull-up.md +310 -0
- package/data/docs/bpta-web-click-response-delay-analysis.md +164 -0
- package/data/docs/bpta-web-completion-delay-analysis.md +209 -0
- package/data/docs/bpta-web-develop-optimization.md +2596 -0
- package/data/docs/bpta-web-development.md +15 -0
- package/data/docs/bpta-web-frame-rate-performance-analysis.md +252 -0
- package/data/docs/bpta-web-interceptor.md +724 -0
- package/data/docs/bpta-web-performance-optimization.md +11 -0
- package/data/docs/bpta-window-and-screen-management.md +12 -0
- package/data/docs/bpta-zhenlv.md +559 -0
- package/data/docs/changelog.md +1410 -0
- package/data/docs/low-power-consumption-suggestions.md +246 -0
- package/data/docs/multi-business-office.md +275 -0
- package/data/docs/multi-communication-app.md +240 -0
- package/data/docs/multi-community-app.md +257 -0
- package/data/docs/multi-convenient-life.md +501 -0
- package/data/docs/multi-financial-app.md +288 -0
- package/data/docs/multi-news-read.md +286 -0
- package/data/docs/multi-picture-app.md +219 -0
- package/data/docs/multi-shopping-price-comparison.md +254 -0
- package/data/docs/multi-short-video-app.md +315 -0
- package/data/docs/multi-ticket-class.md +458 -0
- package/data/docs/multi-travel-accommodation.md +361 -0
- package/data/docs/multi-travel-navigation.md +449 -0
- package/data/docs/multi-video-app.md +492 -0
- package/data/index.md +2886 -0
- package/dist/data.js +180 -0
- package/dist/index.js +203 -0
- package/dist/search.js +102 -0
- package/package.json +57 -0
- package/scripts/trim-code-extra.mjs +78 -0
- package/scripts/trim-code.mjs +106 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# 基于Canvas实现录像回放时间轴
|
|
2
|
+
|
|
3
|
+
> 来源: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-implement-timeline-based-on-canvas
|
|
4
|
+
> 文档标识(fileName): bpta-implement-timeline-based-on-canvas
|
|
5
|
+
> 目录(catalogName): best-practices
|
|
6
|
+
> 语言: cn
|
|
7
|
+
> 更新时间: 2026-06-23 03:36:08
|
|
8
|
+
> 导航地址: /hmos/hmos-dp1
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
#### **概述**
|
|
12
|
+
|
|
13
|
+
在安防监控、车载回放等场景中,录像回放是核心功能。用户通过滑动时间轴,查看不同时间节点的历史视频。本文基于Canvas绘图能力和视频组件,提供功能完备的录像回放时间轴解决方案,封装了[核心组件TimeBarView](https://gitcode.com/harmonyos_samples/timebar/blob/master/time_bar/src/main/ets/components/TimeBarView.ets),助力开发者快速实现时间轴功能。该组件集成了时间轴绘制、单指滑动浏览、双指缩放切换时间粒度等功能。
|
|
14
|
+
|
|
15
|
+
本文主要介绍如何实现TimeBarView时间轴组件,并结合“滑动时间轴控制视频播放”的核心场景,阐述TimeBarView组件的使用方法。
|
|
16
|
+
|
|
17
|
+
TimeBarView时间轴组件提供以下核心功能:
|
|
18
|
+
|
|
19
|
+
- 支持自定义时间轴样式,可配置刻度线、中间指示线、视频区域的外观(如颜色、尺寸、位置)。
|
|
20
|
+
- 支持双指缩放以调整时间刻度精度,单指滑动以定位至目标时间点。
|
|
21
|
+
- 支持设置时间轴当前进度。
|
|
22
|
+
- 支持基于时间轴组件的二次自定义绘制。
|
|
23
|
+
|
|
24
|
+
#### **实现原理**
|
|
25
|
+
|
|
26
|
+
## 关键技术
|
|
27
|
+
|
|
28
|
+
TimeBarView组件采用分层绘制,依次为刻度线、中间线、视频区域及顶层自定义绘制区域。通过滑动和缩放手势事件,实时更新状态并触发时间轴重绘。详细实现参考本章[开发流程](#section42461138131619)。
|
|
29
|
+
|
|
30
|
+
刻度线绘制主要将时间戳转换为Canvas像素坐标。例如,开发者自定义刻度间隔的宽度为intervalWidth(如intervalWidth = 10vp),相同长度的时间间隔对应10分钟,实现“固定时间对应固定像素”的精准映射,确保任意时间戳均能通过公式计算出唯一的画布坐标。
|
|
31
|
+
|
|
32
|
+
**图1** 时间-像素映射示意图
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
## 开发流程
|
|
36
|
+
|
|
37
|
+
1. 绘制时间轴
|
|
38
|
+
1. 时间刻度绘制
|
|
39
|
+
|
|
40
|
+
**计算基本参数**
|
|
41
|
+
|
|
42
|
+
- scaleNum属性:表示当前画布上需绘制的时间间隔数量。viewWidth属性表示时间轴画布的总宽度,intervalWidth属性表示每个时间格子在画布上占用的宽度(intervalWidth值为自定义,例如组件内为10vp/格)。加2是为了预留左右两边的额外格子,避免滚动或缩放时边缘出现空白。
|
|
43
|
+
- middleLineDuration属性:计算画布左半部分对应的实际时间。
|
|
44
|
+
- leftTime:表示画布最左侧边缘对应的实际时间戳(毫秒)。
|
|
45
|
+
|
|
46
|
+
时间轴根据画布大小、缩放比例动态调整显示的时间范围,同时始终以中心点为视觉锚点,确保交互的连贯性。
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
// Number of small divisions visible
|
|
50
|
+
const scaleNum = Math.floor(viewWidth / this.intervalWidth) + 2;
|
|
51
|
+
|
|
52
|
+
// Duration represented from left edge to the middle line
|
|
53
|
+
// keep sub-minute precision to avoid truncation that caused a visual gap near the end when zoomed in.
|
|
54
|
+
const middleLineDuration = (viewWidth / 2) * (TimeMsUnit.TEN_MINUTE / this.intervalWidth);
|
|
55
|
+
|
|
56
|
+
// Time at the far left edge
|
|
57
|
+
this.leftTime = this._currentTime - middleLineDuration;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**绘制刻度线**
|
|
61
|
+
|
|
62
|
+
以10分钟为最小单位生成刻度,在小时模式(MODE_HOUR)下,每60分钟绘制一次大刻度及时间文本;在分钟模式(MODE_MINUTE)下,将10分钟划分为10个细分刻度,因此循环10次绘制刻度线。drawTickLine()方法用于绘制大、小刻度,drawTimeText()方法用于绘制大刻度对应的时间文本。
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
// Find the first tick (aligned to 10 minutes)
|
|
66
|
+
let minuteNum = Math.floor(this.leftTime / TimeMsUnit.TEN_MINUTE);
|
|
67
|
+
let xPosition =
|
|
68
|
+
(minuteNum * TimeMsUnit.TEN_MINUTE - this.leftTime) * (this.intervalWidth / TimeMsUnit.TEN_MINUTE);
|
|
69
|
+
|
|
70
|
+
for (let i = 0; i < scaleNum; i++) {
|
|
71
|
+
const currentX = xPosition + i * this.intervalWidth;
|
|
72
|
+
if (this.divisorMode == ScaleMode.MODE_HOUR) {
|
|
73
|
+
const isMajorTick = minuteNum % 6 === 0;
|
|
74
|
+
const tickLength =
|
|
75
|
+
isMajorTick ? this.timeScaleOption.scaleLineHeight * 2 : this.timeScaleOption.scaleLineHeight;
|
|
76
|
+
const tickRange = this.drawTickLine(currentX, tickLength);
|
|
77
|
+
if (isMajorTick) {
|
|
78
|
+
this.drawTimeText(currentX, minuteNum, tickRange);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
} else if (this.divisorMode === ScaleMode.MODE_MINUTE) {
|
|
82
|
+
for (let j = 0; j < 10; j++) {
|
|
83
|
+
const positionX = j === 0 ? currentX : currentX + j * this.intervalWidth * 0.1;
|
|
84
|
+
const isMajorTick = j === 0;
|
|
85
|
+
const tickLength =
|
|
86
|
+
isMajorTick ? this.timeScaleOption.scaleLineHeight * 2 : this.timeScaleOption.scaleLineHeight;
|
|
87
|
+
const tickRange = this.drawTickLine(positionX, tickLength);
|
|
88
|
+
if (isMajorTick) {
|
|
89
|
+
this.drawTimeText(positionX, minuteNum, tickRange);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
minuteNum++;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
2. 中间指示线绘制
|
|
97
|
+
|
|
98
|
+
中间线是时间轴上的当前时间标记,固定在画布中央,用于标识当前选中或播放的时间点。
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
/** Draw middle indicator line at canvas center. */
|
|
102
|
+
private drawMiddleLine() {
|
|
103
|
+
this.context.beginPath();
|
|
104
|
+
this.context.moveTo(this.context.width / 2, 0);
|
|
105
|
+
this.context.lineTo(this.context.width / 2, this.middleIndicatorOption.length);
|
|
106
|
+
this.context.strokeStyle = this.middleIndicatorOption.fillColor;
|
|
107
|
+
this.context.lineWidth = 2;
|
|
108
|
+
this.context.stroke();
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
3. 视频区域绘制
|
|
112
|
+
|
|
113
|
+
**获取图片pixelMap对象**
|
|
114
|
+
|
|
115
|
+
视频区域用于显示视频片段的时间分布(如录制片段、有效视频区间),采用离屏预渲染,避免滑动缩放时重复计算绘制。
|
|
116
|
+
|
|
117
|
+
- 预渲染时机:当视频片段数据timeRange变化时(通过@Watch('onTimeRangeChange')监听),执行预渲染。
|
|
118
|
+
- 预渲染规则:使用[OffscreenCanvasRenderingContext2D](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-offscreencanvasrenderingcontext2d)构造离屏Canvas画布对象offPaint,按1vp等于1分钟的比例绘制所有视频片段,调用offPaint.getPixelMap()方法生成videoPixelMap像素图。
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
// Offscreen canvas (height uses current view height option)
|
|
122
|
+
const offSettings: RenderingContextSettings = new RenderingContextSettings(false);
|
|
123
|
+
const offCanvas: OffscreenCanvas = new OffscreenCanvas(videoAreaWidth, this.timeBarOption.height);
|
|
124
|
+
const offPaint = offCanvas.getContext('2d', offSettings);
|
|
125
|
+
// ...
|
|
126
|
+
// Draw each segment; clamp and floor pixel coordinates to avoid overlap
|
|
127
|
+
segArr.forEach((recordSegment) => {
|
|
128
|
+
const beginTime = parseTimeString(recordSegment.beginTime).getTime();
|
|
129
|
+
const endTime = parseTimeString(recordSegment.endTime).getTime();
|
|
130
|
+
|
|
131
|
+
let leftX = (beginTime - this._minTime) / TimeMsUnit.ONE_MINUTE;
|
|
132
|
+
let rightX = (endTime - this._minTime) / TimeMsUnit.ONE_MINUTE;
|
|
133
|
+
|
|
134
|
+
// Clamp
|
|
135
|
+
leftX = Math.max(0, Math.min(videoAreaWidth - 1, leftX));
|
|
136
|
+
rightX = Math.max(leftX + 1, Math.min(videoAreaWidth, rightX));
|
|
137
|
+
|
|
138
|
+
const width = Math.max(1, rightX - leftX);
|
|
139
|
+
const videoAreaHeight = this.videoAreaOption.topOffset + this.videoAreaOption.height > this.timeBarOption.height
|
|
140
|
+
? this.timeBarOption.height - this.videoAreaOption.topOffset : this.videoAreaOption.height;
|
|
141
|
+
offPaint.fillRect(leftX, this.videoAreaOption.topOffset, width, videoAreaHeight);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const data = offPaint.getPixelMap(0, 0, videoAreaWidth, this.timeBarOption.height);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**实时绘制**
|
|
148
|
+
|
|
149
|
+
缩放时,通过矩阵变换(缩放)将预渲染图适配当前画布比例,避免重复绘制。
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
// Disable smoothing to keep crisp edges on narrow color bars
|
|
153
|
+
this.context.imageSmoothingEnabled = false;
|
|
154
|
+
|
|
155
|
+
// Offscreen bitmap uses 1px/minute base.
|
|
156
|
+
// Compute the left bitmap x that corresponds to current leftTime.
|
|
157
|
+
const bitmapLeftBase = (this._minTime - this.leftTime) / TimeMsUnit.ONE_MINUTE;
|
|
158
|
+
|
|
159
|
+
// Front-scale: intervalWidth=10px => 1px/minute; so scale factor is intervalWidth/10.
|
|
160
|
+
const videoZoomSize = this.intervalWidth / 10;
|
|
161
|
+
|
|
162
|
+
// Draw with transform; do not clear the canvas here (we already cleared in drawScales)
|
|
163
|
+
this.context.save();
|
|
164
|
+
this.context.scale(videoZoomSize, 1);
|
|
165
|
+
this.context.drawImage(this.videoPixelMap, bitmapLeftBase, 0);
|
|
166
|
+
this.context.restore();
|
|
167
|
+
```
|
|
168
|
+
2. 滑动时间轴
|
|
169
|
+
|
|
170
|
+
滑动功能允许用户通过单指拖拽浏览时间轴,核心逻辑如下:
|
|
171
|
+
|
|
172
|
+
- 手势监听:通过PanGesture()回调监听手指按下、移动、抬起事件。
|
|
173
|
+
- 灵敏度控制:当累计位移(_panResidual)超过灵敏度阈值(MOVE_SENSITIVE)时,将其作为有效位移(effectiveDelta )处理,避免手指轻微抖动触发频繁更新。
|
|
174
|
+
- 边界限制:通过clampToBounds()方法限制滑动范围,防止滑动至无数据区域。
|
|
175
|
+
- 回调通知:滑动过程中实时触发onMoveScaleCallback()回调,通知外部当前选中时间。
|
|
176
|
+
- 帧同步合并渲染:将一帧内的多次重绘请求合并为一次,确保每次重绘均在新帧开始时执行。重绘的scheduleRedraw()方法基于DisplaySync实现帧同步刷新。
|
|
177
|
+
|
|
178
|
+
将有效位移(effectiveDelta)通过刻度密度(intervalWidth)属性转换为时间偏移量,更新时间轴当前时间(_currentTime属性),同步至TimeBarModel组件控制器,供外部获取。调用scheduleRedraw()方法,延迟绘制至下一帧,减少频繁绘制引起的性能消耗,确保滑动过程的视觉流畅性。
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
// Capture raw delta for accumulation.
|
|
182
|
+
const rawDelta = event.offsetX - this._touchDownPosition;
|
|
183
|
+
this._touchDownPosition = event.offsetX;
|
|
184
|
+
|
|
185
|
+
// Accumulate sub-pixel movement for smoother tracking.
|
|
186
|
+
this._panResidual += rawDelta;
|
|
187
|
+
if (Math.abs(this._panResidual) < this.MOVE_SENSITIVE) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const effectiveDelta = this._panResidual;
|
|
192
|
+
this._panResidual = 0;
|
|
193
|
+
|
|
194
|
+
// Update middle-line time, then clamp into [min, max]
|
|
195
|
+
const nextTime = this._currentTime - (effectiveDelta * (TimeMsUnit.TEN_MINUTE / this.intervalWidth));
|
|
196
|
+
this._currentTime = this.clampToBounds(nextTime);
|
|
197
|
+
|
|
198
|
+
this.model.currentTime = this._currentTime;
|
|
199
|
+
|
|
200
|
+
// Redraw and notify
|
|
201
|
+
this.scheduleRedraw(); // Defer redraw to next frame for smoother visuals.
|
|
202
|
+
this._onTimeBarMoveListener?.onMoveScaleCallback(this._currentTime, PlayStatus.PLAYING);
|
|
203
|
+
```
|
|
204
|
+
3. 缩放时间轴
|
|
205
|
+
|
|
206
|
+
缩放功能允许通过双指捏合/张开切换时间粒度。核心逻辑如下:
|
|
207
|
+
|
|
208
|
+
- 手势监听:通过PinchGesture()回调监听双指缩放事件。
|
|
209
|
+
- 缩放因子过滤:设置scaleChange > 0.1,避免微小缩放动作触发频繁更新。
|
|
210
|
+
- intervalWidth调整:缩放时修改intervalWidth属性(10分钟对应的像素宽度),放大时增加,缩小时减少。
|
|
211
|
+
- 模式切换:根据intervalWidth阈值切换显示模式(小时/分钟)。
|
|
212
|
+
- intervalWidth < 60:小时模式(10分钟/刻度,6个刻度 = 1小时)。
|
|
213
|
+
- 60≤intervalWidth < 180:分钟模式(1分钟/细分刻度)。
|
|
214
|
+
- intervalWidth ≥ 180:最大缩放限制,锁定分钟模式。
|
|
215
|
+
- 边界限制:设置最小(10vp)和最大(180vp)缩放阈值,避免过度缩放。
|
|
216
|
+
|
|
217
|
+
**图2** 缩放时间轴示意图
|
|
218
|
+

|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
// Update per-division width
|
|
222
|
+
if (this.zoomSize > 1) {
|
|
223
|
+
this.intervalWidth += 10;
|
|
224
|
+
} else {
|
|
225
|
+
this.intervalWidth -= 10;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Switch modes and enforce bounds
|
|
229
|
+
if (this.intervalWidth < 60) {
|
|
230
|
+
this.divisorMode = ScaleMode.MODE_HOUR;
|
|
231
|
+
if (this.intervalWidth < 10) {
|
|
232
|
+
this.intervalWidth = 10;
|
|
233
|
+
}
|
|
234
|
+
} else if (this.intervalWidth < 180) {
|
|
235
|
+
this.divisorMode = ScaleMode.MODE_MINUTE;
|
|
236
|
+
} else {
|
|
237
|
+
this.divisorMode = ScaleMode.MODE_MINUTE;
|
|
238
|
+
this.intervalWidth = 180;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
4. 数据驱动交互
|
|
242
|
+
|
|
243
|
+
为实现时间轴组件与外部(如视频控制器)的数据联动,构建了TimeBarModel类。TimeBarModel封装了时间轴的两个核心数据:timeRange(视频片段集合)和currentTime(当前时间戳)。
|
|
244
|
+
|
|
245
|
+
- timeRange:当外部传入录像片段时,自动对timeRange排序并计算有效时间边界(minTime/maxTime),确保时间轴仅显示有录像的时段。
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
set timeRange(segments: RecordSegment[]) {
|
|
249
|
+
if (!segments || segments.length === 0) {
|
|
250
|
+
this._timeRange = [];
|
|
251
|
+
this.updateTimeBounds();
|
|
252
|
+
this.notifyDataChange('timeRange');
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const segArr: RecordSegment[] = [...segments];
|
|
257
|
+
|
|
258
|
+
segArr.sort((a, b) => {
|
|
259
|
+
const ta = parseTimeString(a.beginTime).getTime();
|
|
260
|
+
const tb = parseTimeString(b.beginTime).getTime();
|
|
261
|
+
return ta - tb;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
this._timeRange = [...segArr];
|
|
265
|
+
|
|
266
|
+
// Update time bounds (min/max time)
|
|
267
|
+
this.updateTimeBounds();
|
|
268
|
+
// Ensure current time stays within valid bounds
|
|
269
|
+
this.currentTime = this.clampToBounds(this._currentTime);
|
|
270
|
+
// Notify external listeners of the data change
|
|
271
|
+
this.notifyDataChange('timeRange');
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
- currentTime:通过getter和setter机制实现双向同步,既接收外部视频播放进度的更新,也在时间轴滑动时将最新时间输出给外部。
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
set currentTime(time: number) {
|
|
278
|
+
if (!Number.isFinite(time) || time <= 0) {
|
|
279
|
+
return;
|
|
280
|
+
} // ignore invalid time values
|
|
281
|
+
|
|
282
|
+
const clampedTime = this.clampToBounds(time);
|
|
283
|
+
if (this._currentTime === clampedTime) {
|
|
284
|
+
return;
|
|
285
|
+
} // do not trigger update if time hasn't changed
|
|
286
|
+
|
|
287
|
+
this._currentTime = clampedTime;
|
|
288
|
+
this.notifyDataChange('currentTime');
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
- 数据变更通知:通过onDataChange()回调,监听timeRange和currentTime的变化,简化了开发者调用。
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
private notifyDataChange(type: 'timeRange' | 'currentTime') {
|
|
295
|
+
this._onDataChange && this._onDataChange(type);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### 时间轴控制视频播放场景
|
|
300
|
+
|
|
301
|
+
## 场景描述
|
|
302
|
+
|
|
303
|
+
TimeBarView时间轴与视频播放联动,滑动时间轴可快速定位至目标录像片段。
|
|
304
|
+
|
|
305
|
+
滑动停止时,若时间轴中线对应的时间点在录像片段有效时间内,视频立即跳转并继续播放;若处于两端录像间的空白区域,系统自动跳转至最近的录像起始时间点,避免无画面时段,提高效率。时间轴滑动存在硬性边界限制,用户试图将时间轴向右滑动至所有录像片段的最末端(即最新一段录像的结束时间)时,将无法继续拖动,防止超出录像数据范围导致播放异常。
|
|
306
|
+
|
|
307
|
+
**图3** 效果图
|
|
308
|
+

|
|
309
|
+
|
|
310
|
+
## 开发步骤
|
|
311
|
+
|
|
312
|
+
1. 引入TimeBarView时间轴组件
|
|
313
|
+
|
|
314
|
+
创建TimeBarModel实例作为数据载体,实例对象viewModel通过组件参数传入TimeBarView时间轴组件,即可渲染基本的时间轴。核心代码如下:
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
import {
|
|
318
|
+
TimeBarView,
|
|
319
|
+
TimeBarModel,
|
|
320
|
+
// ...
|
|
321
|
+
} from '@samples/time_bar';
|
|
322
|
+
// ...
|
|
323
|
+
@Component
|
|
324
|
+
struct TimeBarVideoLinkage {
|
|
325
|
+
// ...
|
|
326
|
+
private viewModel: TimeBarModel = new TimeBarModel();
|
|
327
|
+
// ...
|
|
328
|
+
build() {
|
|
329
|
+
NavDestination() {
|
|
330
|
+
Row() {
|
|
331
|
+
// ...
|
|
332
|
+
Column() {
|
|
333
|
+
TimeBarView({
|
|
334
|
+
model: this.viewModel,
|
|
335
|
+
// ...
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
// ...
|
|
339
|
+
}
|
|
340
|
+
.height('100%')
|
|
341
|
+
.alignItems(VerticalAlign.Top)
|
|
342
|
+
}
|
|
343
|
+
.title($r('app.string.route_title2'))
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+

|
|
349
|
+
|
|
350
|
+
TimeBarView组件属性参考:[TimeBarView 接口信息](https://gitcode.com/harmonyos_samples/timebar#具体实现)。
|
|
351
|
+
2. 时间轴展示视频区域
|
|
352
|
+
|
|
353
|
+
开发者处理视频片段,生成RecordSegment类型的集合。通过viewModel对象的timeRange属性传递给组件,在时间轴上即可绘制视频区域。核心代码如下:
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
async getTimeInfoFromVideo() {
|
|
357
|
+
if (this.videosInfo.length === 0) {
|
|
358
|
+
try {
|
|
359
|
+
this.videosInfo = await extractOnlineVideosInfo(LEGITIMATE_VIDEO_URLS);
|
|
360
|
+
} catch (e) {
|
|
361
|
+
this.videosInfo = [];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// ...
|
|
365
|
+
const fileInfoList: Array<RecordSegment> = [];
|
|
366
|
+
const initialTimeISO = getTodayStartMs();
|
|
367
|
+
|
|
368
|
+
// Generate segments aligned to the time bar (including gaps)
|
|
369
|
+
this.videosInfo.forEach((curInfo, index) => {
|
|
370
|
+
const seg = new RecordSegment();
|
|
371
|
+
|
|
372
|
+
const startOffset = this.timelineOffsets[index] || 0;
|
|
373
|
+
const durMs = Number(curInfo.duration) || 0;
|
|
374
|
+
|
|
375
|
+
seg.beginTime = dayjs(initialTimeISO).add(startOffset, 'millisecond').format(MILLISECOND_FORMAT);
|
|
376
|
+
seg.endTime = dayjs(initialTimeISO).add(startOffset + durMs, 'millisecond').format(MILLISECOND_FORMAT);
|
|
377
|
+
|
|
378
|
+
fileInfoList.push(seg)
|
|
379
|
+
});
|
|
380
|
+
this.viewModel.timeRange = fileInfoList;
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+

|
|
385
|
+
|
|
386
|
+
可向TimeBarView组件传递videoAreaOption属性,以修改时间区域的背景色及在时间轴垂直方向的位置;传递timeScaleOption属性,以修改时间轴刻度的长度、颜色及对齐方式。
|
|
387
|
+
3. 绑定时间轴事件监听器,同步时间状态
|
|
388
|
+
|
|
389
|
+
在onContextReady()回调中,获取TimeBarView实例并绑定setTimeBarMoveListener()方法,监听时间轴滑动事件,实时同步当前选中时间(curTime)与操作状态(timeBarStatus)。核心代码如下:
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
private handleContextReady = (_ctx: CanvasRenderingContext2D, component: TimeBarView) => {
|
|
393
|
+
this.timeBarRef = component;
|
|
394
|
+
this.timeBarRef.setTimeBarMoveListener({
|
|
395
|
+
onMoveScaleCallback: (curTime: number, status?: PlayStatus) => {
|
|
396
|
+
this.currentTime = curTime;
|
|
397
|
+
this.timeBarStatus = status;
|
|
398
|
+
}
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
Column() {
|
|
405
|
+
TimeBarView({
|
|
406
|
+
model: this.viewModel,
|
|
407
|
+
onContextReady: this.handleContextReady
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+

|
|
413
|
+
|
|
414
|
+
onMoveScaleCallback()回调会在时间轴开始滑动(START)、滑动过程中(PLAYING)、松手后(STOP)触发,curTime为时间轴中间线对应的绝对时间戳,是视频跳转的核心依据。
|
|
415
|
+
4. 实现时间同步逻辑,处理视频跳转
|
|
416
|
+
|
|
417
|
+
时间轴滑动时,通过@Watch监听currentTime属性变化,处理视频跳转逻辑。
|
|
418
|
+
|
|
419
|
+
- 有效区域滑动:拖动时间轴至某段视频内,松手后视频精准跳转至对应时间并播放。
|
|
420
|
+
- 空白区域滑动:拖动至两段视频的空白间隔,视频自动跳转至下一段视频的起始位置。
|
|
421
|
+
- 边界滑动:拖动至视频范围最右侧(最后一段视频结束时间),时间轴无法继续右滑,视频停留在最后一帧。
|
|
422
|
+
1. 计算目标视频位置(时间映射与边界处理)
|
|
423
|
+
|
|
424
|
+
从时间轴拖动的currentTime(选中时间)出发,通过“时间偏移计算→片段定位→进度校正”,确定视频需跳转的目标进度。核心代码如下:
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
const totalTimelineMs = this.totalTimelineMs || 0;
|
|
428
|
+
const rawOffset = (this.curTime ?? this.initialTime) - this.initialTime; // relative offset (ms)
|
|
429
|
+
const clampedOffset = clamp(rawOffset, 0, totalTimelineMs);
|
|
430
|
+
|
|
431
|
+
// Resolve segment index (including gaps) and derive target segment window
|
|
432
|
+
const info = findSegmentIndexByTimeline(this.timelineOffsets ?? [], this.videosInfo, clampedOffset);
|
|
433
|
+
const prevIndex = this.curIndex;
|
|
434
|
+
const nextIndex = info.index !== -1 ? info.index : prevIndex;
|
|
435
|
+
|
|
436
|
+
// Start time and duration of the target segment
|
|
437
|
+
const segStartMs = this.timelineOffsets?.[nextIndex] ?? 0;
|
|
438
|
+
const segDurMs = Number(this.videosInfo[nextIndex]?.duration) || 0;
|
|
439
|
+
|
|
440
|
+
// Whether dragged to the "absolute end"
|
|
441
|
+
const playEnd = (nextIndex === this.videosInfo.length - 1) && (clampedOffset === totalTimelineMs);
|
|
442
|
+
|
|
443
|
+
// Compute the preview/target progress inside the segment (seconds)
|
|
444
|
+
const videoProgressSec = this.computeProgressSeconds(clampedOffset, segStartMs, segDurMs, info, playEnd);
|
|
445
|
+
|
|
446
|
+
const prevSrc = this.videoSrcArray[prevIndex] ?? '';
|
|
447
|
+
const nextSrc = this.videoSrcArray[nextIndex] ?? '';
|
|
448
|
+
const indexChanged = nextIndex !== prevIndex;
|
|
449
|
+
const willReload = indexChanged && nextSrc !== prevSrc;
|
|
450
|
+
|
|
451
|
+
// Decide whether player source must reload (URL change) and apply index switch side-effects
|
|
452
|
+
this.decideAndApplyIndexChange(indexChanged, willReload, nextIndex, segStartMs);
|
|
453
|
+
```
|
|
454
|
+
2. 执行视频跳转与播放控制
|
|
455
|
+
|
|
456
|
+
根据视频进度属性(目标进度)videoProgressSec,结合视频加载状态执行跳转,并控制播放行为。核心代码如下:
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
private performSeek(videoProgressSec: number, willReload: boolean) {
|
|
460
|
+
if (willReload) {
|
|
461
|
+
// Source will reload: cache and let onPrepared execute precise seek
|
|
462
|
+
this.pendingSeekSec = videoProgressSec;
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// No reload (or no segment change): attempt immediate precise seek
|
|
467
|
+
if (this.durationTime === 0) {
|
|
468
|
+
// Duration is not available yet: still cache the seek
|
|
469
|
+
this.pendingSeekSec = videoProgressSec;
|
|
470
|
+
} else {
|
|
471
|
+
this.controller.setCurrentTime(videoProgressSec, SeekMode.Accurate);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### 常见问题
|
|
477
|
+
|
|
478
|
+
## **canvas画的时间轴,在手势捏合缩放时画面不停闪烁,是否有解决方案**
|
|
479
|
+
|
|
480
|
+
在Canvas画布进行缩放操作时,尤其是在处理手势缩放时,可能会出现画面闪烁的问题。这是由于缩放操作导致画布上的图形重新计算和绘制,引起视觉上的闪烁效果。为减少这种现象,可采取以下方法:设置临界点,在手势捏合持续回调中,不是每次移动都重新绘制图形,而是设定特定条件,当满足这些条件时才重新绘制。例如,可检查手势移动的距离,当移动超过特定阈值时才更新画面。
|
|
481
|
+
|
|
482
|
+
```
|
|
483
|
+
if (Math.abs(offsetX - this.lastOffsetX) < 0.5 && Math.abs(offsetY - this.lastOffsetY) < 0.5) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
this.lastOffsetX = offsetX;
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
此段代码表示仅当X轴与Y轴的位移均超过0.5时,才更新画布,从而减少不必要的重绘。
|
|
490
|
+
|
|
491
|
+
#### 示例代码
|
|
492
|
+
|
|
493
|
+
- [实现可缩放时间轴功能](https://gitcode.com/harmonyos_samples/timebar)
|