步骤 4 - 创建用于选择小部件的交互处理程序¶
在本教程中,您将创建一个应用程序,其中用户可以滚动 Widget Grid List Box 中包含的小部件列表,并使他们能够从该列表中选择由 Widget Item Prefab 表示的小部件。Grid List Box 3D 节点提供了您可以在 Kanzi Studio 项目中设置的水平滚动,但您需要定义处理小部件选择的应用程序逻辑。
在该教程的这一步骤中,您将实现在用户点击小组件时处理小组件项选择的功能:
触发将摄像机缩放到特定位置的动画,以便选定的小组件在应用程序窗口左侧高亮显示。
触发将选定小组件朝向摄像机的动画,使其高亮显示。
使应用程序窗口右侧由 Widget Description Layer 节点表示的描述面板可见。描述面板包含每个小部件的描述、一个返回按钮和一个购买按钮。当 Widget Description Layer 可见时,Widget Grid List Box 的滚动被禁用。当相机缩放动画进行时,Back 按钮被禁用。
要创建选择小组件的交互处理程序:
在
ProgrammerTutorialApplication类中,在Application::onProjectLoaded函数之后,实现用于选择 Widget Grid List Box 中小部件的事件处理程序。使用所选小部件的索引从 Widget Grid List Box 节点中检索所选小部件。class ProgrammerTutorialApplication : public ExampleApplication { ... private: // The handler for the ListBox.ItemSelected message from the Widget Grid List Box. // Brings the selected list box item to the front. void onListBoxItemSelected(ListBoxConcept::ItemSelectedMessageArguments& messageArguments) { // Retrieve the index of the selected list box item from the message arguments. optional<size_t> selectedItemIndex = messageArguments.getSelectedItemIndex(); if (selectedItemIndex) { // Remove old playbacks to reset the values. // You implement this function in the next step of the tutorial. removePlaybacks(); // Retrieve the selected list box item by its index. m_selectedItem = m_widgetList->getItem(*selectedItemIndex); ... } } };
目标动画重新定位摄像机。动画获取节点的当前变换,并动画到由另一个节点定义的另一个变换。现在,存储的摄像机变换已更新为所选小部件的平移。为摄像机创建动画,并启动动画。
void onListBoxItemSelected(ListBoxConcept::ItemSelectedMessageArguments& messageArguments) { ... if (selectedItemIndex) { ... // Calculate a new value for the camera animation target node and start the animation. { // Get the current transformation. Matrix4x4 selectedItemTransformation = m_selectedItem->getFinalTransformation(); // Get the camera's relative transformation target position. SRTValue3D transformationTarget = m_cameraTransformationTarget; // Add the position of the selected item to the target camera transformation. transformationTarget.setTranslation(selectedItemTransformation.getTranslation() - transformationTarget.getTranslation()); // Create the animation for the camera. m_cameraAnimation = FromToAnimation<SRTValue3D, LinearEasingFunction>::create(getDomain(), chrono::seconds(1), nullopt, transformationTarget); // Start the animation. PropertyAnimationTimelineSharedPtr cameraTimeline = PropertyAnimationTimeline::create(getDomain(), ".", Node3D::RenderTransformationProperty, m_cameraAnimation); SceneGraphTimelinePlaybackContext cameraContext(*m_camera); m_cameraPlayback = cameraTimeline->createPlayback(cameraContext); getDomain()->getRootTimelineClock()->addTimelinePlayback(m_cameraPlayback); } } ... }
现在,Camera 动画的变换目标已更新,您可以启动所选小部件的高亮动画。高亮动画将小部件围绕其 x 轴从固定值 0 度旋转到 60 度,并在
Application::onProjectLoaded函数中定义。void onListBoxItemSelected(ListBoxConcept::ItemSelectedMessageArguments& messageArguments) { ... if (selectedItemIndex) { ... // Start the animation for the selected item. PropertyAnimationTimelineSharedPtr selectedItemTimeline = PropertyAnimationTimeline::create(getDomain(), ".", Node3D::LayoutTransformationProperty, m_selectedItemAnimation); SceneGraphTimelinePlaybackContext selectedItemContext(*m_selectedItem); m_widgetHighlightPlayback = selectedItemTimeline->createPlayback(selectedItemContext); getDomain()->getRootTimelineClock()->addTimelinePlayback(m_widgetHighlightPlayback); } }
当动画开始时,禁用 Back button 的输入。
void onListBoxItemSelected(ListBoxConcept::ItemSelectedMessageArguments& messageArguments) { ... if (selectedItemIndex) { ... // Start the animation to disable input for the Back button. PropertyAnimationTimelineSharedPtr backButtonEnableTimeline = PropertyAnimationTimeline::create(getDomain(), ".", Button3D::HitTestableProperty, m_backButtonEnableAnimation); SceneGraphTimelinePlaybackContext backButtonEnableContext(*m_backButton); m_backButtonEnablePlayback = backButtonEnableTimeline->createPlayback(backButtonEnableContext); getDomain()->getRootTimelineClock()->addTimelinePlayback(m_backButtonEnablePlayback); } }
从 Programmertutorial.WidgetDescription 属性获取小部件描述,并将 Text Block 2D 节点的 Text 属性的值设置为 Programmertutorial.WidgetDescription 属性的值,并使包含应用程序窗口右侧面板的 Widget Description Layer 可见。
void onListBoxItemSelected(ListBoxConcept::ItemSelectedMessageArguments& messageArguments) { ... if (selectedItemIndex) { ... // Show the widget description by setting the Widget Description Layer visible. if (m_widgetDescriptionVisibilityPlayback) { getDomain()->getRootTimelineClock()->removeTimelinePlayback(*m_widgetDescriptionVisibilityPlayback); m_widgetDescriptionVisibilityPlayback.reset(); } // Set the widget description to the description text. The description is taken from the widget node. string widgetDescription = m_selectedItem->getProperty(*m_widgetDescriptionPropertyType); m_widgetDescriptionTextBlock->setText(widgetDescription); // Set the Widget Description Layer visible. m_widgetDescriptionNode->setVisible(true); } }
在
Application::onProjectLoaded函数中,在填充小部件列表后,为 Widget Grid List Box 节点的ListBoxConcept::ItemSelectedMessage注册消息处理程序。void onProjectLoaded() override { ... // Add a message handler for selecting the Grid List Box 3D item events. m_widgetList->addMessageHandler(GridListBox3D::ItemSelectedMessage, bind(&ProgrammerTutorialApplication::onListBoxItemSelected, this, placeholders::_1)); }
当点击小组件时,应用程序使用指定的两个动画高亮显示小组件,使 Widget Description Layer 节点可见,并在 Widget Description Layer 中显示小组件描述。