从API version 23开始,ArkUI开发框架在NDK接口提供了Picker容器组件。Picker容器组件用于实现用户自定义选项的选择操作,支持滚动选择、触感反馈、循环滚动等功能。Picker组件通过设置选择指示器样式,可以自定义选中项的显示效果,适用于日期选择、时间选择、文本选择等场景。从API版本26.0.0开始,可通过NODE_PICKER_DISPLAYED_ITEM_COUNT、NODE_PICKER_ITEM_HEIGHT配置可见选项行数与每行行高,语义与ArkTS侧UIPickerComponent的displayedItemCount、itemHeight一致;详细参数格式见信息选择类组件相关属性。
创建Picker后,可以设置Picker属性,并监听Picker事件。
使用NDK接口构建UI界面以及NDK基本使用,可以参考接入ArkTS页面。
通过调用createNode()得到组件对象指针,节点类型为ARKUI_NODE_PICKER,并设置ArkUI_NodeAttributeType中的相关属性,创建一个Picker容器组件。
以下示例展示了创建Picker组件并设置基本属性的方法。
static ArkUI_NodeHandle CreatePicker(ArkUI_NativeNodeAPI_1 *api)
{
ArkUI_NodeHandle picker = api->createNode(ARKUI_NODE_PICKER);
if (picker == nullptr) {
return nullptr;
}
if (g_state) {
g_state->pickerNode = picker;
}
ArkUI_NumberValue widthValue = {.f32 = K_PICKER_WIDTH_RATIO};
ArkUI_AttributeItem widthItem = {&widthValue, sizeof(widthValue) / sizeof(ArkUI_NumberValue)};
api->setAttribute(picker, NODE_WIDTH_PERCENT, &widthItem);
UpdatePickerSelectedIndex();
SetDisplayedItemCount(K_VISIBLE_COUNT);
SetItemHeight(K_ITEM_HEIGHT);
api->registerNodeEvent(picker, NODE_PICKER_EVENT_ON_CHANGE, K_ON_CHANGE_EVENT_ID, nullptr);
api->registerNodeEvent(picker, NODE_PICKER_EVENT_ON_SCROLL_STOP, K_ON_SCROLL_STOP_EVENT_ID, nullptr);
if (g_state) {
for (const auto &item : g_state->dataArray) {
ArkUI_NodeHandle optionNode = CreatePickerOption(api, item);
if (optionNode != nullptr) {
api->addChild(picker, optionNode);
}
}
}
return picker;
} 参考示例中列表组件的实现方式,可以将Picker组件常用的属性设置封装到自定义的工具类中方便后续使用。
class ContainerPickerCanLoopMaker : public BaseNode {
public:
static ArkUI_NodeHandle CreateNativeNode();
ContainerPickerCanLoopMaker()
: BaseNode(NodeApiInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_PICKER)),
nodeApi_(NodeApiInstance::GetInstance()->GetNativeNodeAPI())
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
}
~ContainerPickerCanLoopMaker() override = default;
// ========================================
// 基础尺寸设置接口
// ========================================
void SetPickerSize(float width, float height) { SetSize(width, height); }
void SetPickerSizePercent(float widthPercent, float heightPercent) { SetSizePercent(widthPercent, heightPercent); }
void SetPickerWidthPercent(float widthPercent)
{
SetAttributeFloat32(nodeApi_, GetHandle(), NODE_WIDTH_PERCENT, widthPercent);
}
void SetPickerHeightPercent(float heightPercent)
{
SetAttributeFloat32(nodeApi_, GetHandle(), NODE_HEIGHT_PERCENT, heightPercent);
}
// ========================================
// Picker特有属性设置接口
// ========================================
void SetSelectedIndex(uint32_t index)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_NumberValue selectedIndexValue = {.u32 = index};
ArkUI_AttributeItem selectedIndexItem = {&selectedIndexValue,
sizeof(selectedIndexValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_OPTION_SELECTED_INDEX, &selectedIndexItem);
}
void SetCanLoop(bool canLoop)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_NumberValue canLoopValue = {.i32 = canLoop ? 1 : 0};
ArkUI_AttributeItem canLoopItem = {&canLoopValue, sizeof(canLoopValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_CAN_LOOP, &canLoopItem);
}
void SetHapticFeedback(bool enabled)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_NumberValue enableHapticFeedbackValue = {.i32 = enabled ? 1 : 0};
ArkUI_AttributeItem enableHapticFeedbackItem = {&enableHapticFeedbackValue,
sizeof(enableHapticFeedbackValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_ENABLE_HAPTIC_FEEDBACK, &enableHapticFeedbackItem);
}
void SetSelectionIndicatorBackground(uint32_t backgroundColor, float cornerRadius = 10.0f)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_PickerIndicatorStyle *indicatorStyle =
OH_ArkUI_PickerIndicatorStyle_Create(ARKUI_PICKER_INDICATOR_BACKGROUND);
if (indicatorStyle == nullptr) {
return;
}
ArkUI_PickerIndicatorBackground background = {.backgroundColor = backgroundColor,
.topLeftRadius = cornerRadius,
.topRightRadius = cornerRadius,
.bottomLeftRadius = cornerRadius,
.bottomRightRadius = cornerRadius};
OH_ArkUI_PickerIndicatorStyle_ConfigureBackground(indicatorStyle, &background);
ArkUI_AttributeItem selectionIndicatorItem = {.object = indicatorStyle};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_SELECTION_INDICATOR, &selectionIndicatorItem);
}
void SetSelectionIndicatorDivider(uint32_t dividerColor, float strokeWidth = 2.0f, float startMargin = 20.0f,
float endMargin = 20.0f)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_PickerIndicatorStyle *indicatorStyle =
OH_ArkUI_PickerIndicatorStyle_Create(ARKUI_PICKER_INDICATOR_DIVIDER);
if (indicatorStyle == nullptr) {
return;
}
ArkUI_PickerIndicatorDivider divider = {.strokeWidth = strokeWidth,
.dividerColor = dividerColor,
.startMargin = startMargin,
.endMargin = endMargin};
OH_ArkUI_PickerIndicatorStyle_ConfigureDivider(indicatorStyle, ÷r);
ArkUI_AttributeItem selectionIndicatorItem = {.object = indicatorStyle};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_SELECTION_INDICATOR, &selectionIndicatorItem);
}
// ========================================
// 公共辅助方法
// ========================================
ArkUI_NativeNodeAPI_1 *GetNodeAPI() const { return nodeApi_; }
protected:
void OnNodeEvent(ArkUI_NodeEvent *event) override { BaseNode::OnNodeEvent(event); }
private:
ArkUI_NativeNodeAPI_1 *nodeApi_ = nullptr;
}; 通过设置ArkUI_NodeAttributeType中的NODE_PICKER_OPTION_SELECTED_INDEX属性,可以设置Picker组件的默认选中项索引。
ArkUI_NumberValue selectedIndexValue = {.u32 = index};
ArkUI_AttributeItem selectedIndexItem = {&selectedIndexValue,
sizeof(selectedIndexValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_OPTION_SELECTED_INDEX, &selectedIndexItem); 通过设置NODE_PICKER_ENABLE_HAPTIC_FEEDBACK属性,可以控制Picker组件是否启用触感反馈。开启后,当用户滚动选择器时,如果系统硬件支持,会产生触感反馈。
使用ArkUI_NativeNodeAPI_1时可直接调用setAttribute。
ArkUI_NumberValue enableHapticFeedbackValue = {.i32 = enabled ? 1 : 0};
ArkUI_AttributeItem enableHapticFeedbackItem = {&enableHapticFeedbackValue,
sizeof(enableHapticFeedbackValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_ENABLE_HAPTIC_FEEDBACK, &enableHapticFeedbackItem); 若使用上文封装的ContainerPickerCanLoopMaker,可调用已封装的接口。
picker->SetHapticFeedback(K_HAPTIC_FEEDBACK);
通过设置NODE_PICKER_CAN_LOOP属性,可以控制Picker组件是否支持循环滚动。设置为true时,选择器可以无限循环滚动;设置为false时,滚动到首尾时会停止。
当子组件个数小于或等于可见选项行数(由NODE_PICKER_DISPLAYED_ITEM_COUNT设置,默认为7)时,无论设置为true还是false,都不会循环滚动。
使用ArkUI_NativeNodeAPI_1时可直接调用setAttribute。
ArkUI_NumberValue canLoopValue = {.i32 = canLoop ? 1 : 0};
ArkUI_AttributeItem canLoopItem = {&canLoopValue, sizeof(canLoopValue) / sizeof(ArkUI_NumberValue)};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_CAN_LOOP, &canLoopItem); 若使用上文封装的ContainerPickerCanLoopMaker,可调用已封装的接口。
picker->SetCanLoop(K_CAN_LOOP);
从API版本26.0.0开始,可通过NODE_PICKER_DISPLAYED_ITEM_COUNT设置可见选项行数,通过NODE_PICKER_ITEM_HEIGHT设置每一行的高度(vp)。未设置时,默认分别为7行与40vp;取值范围、偶数行数规范及越界行为与UIPickerComponent的displayedItemCount、itemHeight一致。立体滚轮样式下可视高度会受旋转影响,若增大行数或行高,请相应增大Picker容器高度。
使用ArkUI_NativeNodeAPI_1时可直接调用setAttribute。
ArkUI_NumberValue itemCountValue = {.i32 = count};
ArkUI_AttributeItem itemCountItem = {&itemCountValue, sizeof(itemCountValue) / sizeof(ArkUI_NumberValue)};
g_state->api->setAttribute(g_state->pickerNode, NODE_PICKER_DISPLAYED_ITEM_COUNT, &itemCountItem); ArkUI_NumberValue itemHeightValue = {.f32 = heightVp};
ArkUI_AttributeItem itemHeightItem = {&itemHeightValue, sizeof(itemHeightValue) / sizeof(ArkUI_NumberValue)};
g_state->api->setAttribute(g_state->pickerNode, NODE_PICKER_ITEM_HEIGHT, &itemHeightItem); 通过设置NODE_PICKER_SELECTION_INDICATOR属性,可以自定义Picker组件的选择指示器样式。选择指示器包括背景样式和分割线样式两部分。
选择指示器的背景样式通过ArkUI_PickerIndicatorBackground结构体设置,包括背景颜色和圆角半径。
void SetSelectionIndicatorBackground(uint32_t backgroundColor, float cornerRadius = 10.0f)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_PickerIndicatorStyle *indicatorStyle =
OH_ArkUI_PickerIndicatorStyle_Create(ARKUI_PICKER_INDICATOR_BACKGROUND);
if (indicatorStyle == nullptr) {
return;
}
ArkUI_PickerIndicatorBackground background = {.backgroundColor = backgroundColor,
.topLeftRadius = cornerRadius,
.topRightRadius = cornerRadius,
.bottomLeftRadius = cornerRadius,
.bottomRightRadius = cornerRadius};
OH_ArkUI_PickerIndicatorStyle_ConfigureBackground(indicatorStyle, &background);
ArkUI_AttributeItem selectionIndicatorItem = {.object = indicatorStyle};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_SELECTION_INDICATOR, &selectionIndicatorItem);
} 选择指示器的分割线样式通过ArkUI_PickerIndicatorDivider结构体设置,包括线宽、颜色和边距。
void SetSelectionIndicatorDivider(uint32_t dividerColor, float strokeWidth = 2.0f, float startMargin = 20.0f,
float endMargin = 20.0f)
{
if (!IsNotNull(nodeApi_) || !IsNotNull(GetHandle())) {
return;
}
ArkUI_PickerIndicatorStyle *indicatorStyle =
OH_ArkUI_PickerIndicatorStyle_Create(ARKUI_PICKER_INDICATOR_DIVIDER);
if (indicatorStyle == nullptr) {
return;
}
ArkUI_PickerIndicatorDivider divider = {.strokeWidth = strokeWidth,
.dividerColor = dividerColor,
.startMargin = startMargin,
.endMargin = endMargin};
OH_ArkUI_PickerIndicatorStyle_ConfigureDivider(indicatorStyle, ÷r);
ArkUI_AttributeItem selectionIndicatorItem = {.object = indicatorStyle};
nodeApi_->setAttribute(GetHandle(), NODE_PICKER_SELECTION_INDICATOR, &selectionIndicatorItem);
} 将背景样式或分割线样式组合到ArkUI_PickerIndicatorStyle结构体中,并设置给Picker组件。
若使用上文封装的ContainerPickerCanLoopMaker,可调用已封装的接口。
picker->SetSelectionIndicatorDivider(0xFF0000FF, 2.0f, 20.0f, 20.0f);
本示例通过registerNodeEvent注册Picker组件的事件类型ArkUI_NodeEventType,使用ArkUI_NodeEventItem结构体为每个事件指定独立的回调函数。开发者无需额外注册全局回调函数,每个事件项直接绑定回调函数。Picker组件支持的事件如下:
| 枚举 | 说明 | 起始版本 |
|---|---|---|
| NODE_PICKER_EVENT_ON_CHANGE | Picker组件中选择某项时触发的事件。 | 23 |
| NODE_PICKER_EVENT_ON_SCROLL_STOP | Picker组件中选择某项且滚动停止时触发的事件。 | 23 |
通过registerNodeEvent注册NODE_PICKER_EVENT_ON_CHANGE事件,使用ArkUI_NodeEventItem结构体指定回调函数,可以监听Picker组件的选择变化。事件回调中会返回选中项的索引值。
api->registerNodeEvent(picker, NODE_PICKER_EVENT_ON_CHANGE, K_ON_CHANGE_EVENT_ID, nullptr);
通过registerNodeEvent注册NODE_PICKER_EVENT_ON_SCROLL_STOP事件,使用ArkUI_NodeEventItem结构体指定回调函数,可以监听Picker组件滚动停止时的选择变化。与NODE_PICKER_EVENT_ON_CHANGE事件相比,该事件只在滚动停止时触发,适合需要在滚动完成后再处理选择的场景。
api->registerNodeEvent(picker, NODE_PICKER_EVENT_ON_SCROLL_STOP, K_ON_SCROLL_STOP_EVENT_ID, nullptr);