--- /dev/null
+/*
+ * Copyright (c) CompanyNameMagicTag 2025-2025. All rights reserved.
+ * Description: ArcScaleListDesktopFragment.h
+ * Author:
+ * Create: 2025-07-04
+ */
+
+#ifndef ARC_SCALE_LIST_DESKTOP_FRAGMENT_H
+#define ARC_SCALE_LIST_DESKTOP_FRAGMENT_H
+
+#include "UIDesktopFragment.h"
+#include "ApplistAdapter.h"
+#include "ChangeSliceListener.h"
+#include "components/ui_list.h"
+#include "drag_event.h"
+#include "UiConfig.h"
+
+
+namespace OHOS {
+class ArcScaleListItemView;
+class ArcScaleListDesktopFragment : public UIDesktopFragment {
+public:
+ bool OnClick(UIView &view, const ClickEvent &event) override;
+ void AddAppItemToList(const AppItem &item) override;
+ void ClearAppItemToList() override;
+ void RefreshAppList() override;
+
+protected:
+ void OnCreateView(void* data) override;
+ void OnDestroyView() override;
+
+private:
+ UIViewGroup * ArcScaleListGroup_{nullptr};
+ UITransformList * ArcScaleList_{nullptr};
+ ArcScaleListItemAdapter * ArcScaleListAdapter_{nullptr};
+ UIView::OnDragListener * ArcScaleListDragListener_{nullptr};
+};
+
+class AppListOnDragListener : public UIView::OnDragListener {
+public:
+ AppListOnDragListener()
+ {
+ continueDrag_ = false;
+ }
+ ~AppListOnDragListener() override {}
+ bool OnDragStart(UIView& view, const DragEvent& event) override
+ {
+ UNUSED(view);
+ UNUSED(event);
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Applist Ondragstart!!");
+ continueDrag_ = true;
+ return false;
+ }
+
+ bool OnDrag(UIView& view, const DragEvent& event) override
+ {
+ UNUSED(view);
+ if (!continueDrag_) {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AppList : Can not continue drag!!");
+ return false;
+ }
+ if ((event.GetDragDirection() == DragEvent::DIRECTION_LEFT_TO_RIGHT) &&
+ (event.GetDeltaX() > X_DRAG_OFFSET) && (event.GetDeltaX() > (DOUBLES * MATH_ABS(event.GetDeltaY())))) {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Applist Ondrag!!");
+ NativeAbility::GetInstance().ChangeSlice(VIEW_MAIN, TransitionType::TRANSITION_ZOOM);
+ }
+
+ return false;
+ }
+
+ bool OnDragEnd(UIView& view, const DragEvent& event) override
+ {
+ UNUSED(view);
+ UNUSED(event);
+ return false;
+ }
+private:
+ bool continueDrag_{false};
+};
+}
+
+#endif // LIST_DESKTOP_FRAGMENT_H
--- /dev/null
+/*
+ * Copyright (c) CompanyNameMagicTag 2025-2025. All rights reserved.
+ * Description: ArcScaleListDesktopFragment.cpp
+ * Author:
+ * Create: 2025-07-04
+ */
+
+#include "applist/include/ArcScaleListDesktopFragment.h"
+#include "applist/include/DesktopFactory.h"
+#include "applist/include/ApplistModel.h"
+#include "wearable_log.h"
+
+namespace OHOS {
+REGIST_DESKTOP_STYLE(ARC_SCALE_LIST_STYLE, ArcScaleListDesktopFragment);
+
+/* ---------------------------------- 弧形列表 ---------------------------------- */
+#define ARC_SCALE_LIST_SCALE_FACTOR (440)
+#define ARC_SCALE_LIST_X (13)
+#define ARC_SCALE_LIST_Y (0)
+#define ARC_SCALE_LIST_WIDTH (HORIZONTAL_RESOLUTION - ARC_SCALE_LIST_X)
+#define ARC_SCALE_LIST_HEIGHT (VERTICAL_RESOLUTION)
+
+/**
+ * @brief 根据位置变换列表项的基础函数
+ *
+ * 这个函数根据列表项在垂直列表中的位置来调整其缩放比例。它使用一个缓动函数来计算缩放比例,使得列表项在接近列表中心时逐渐放大,远离列表中心时逐渐缩小。
+ *
+ * @param list 指向 UITransformList 类型的指针,代表要操作的列表。
+ * @param item 指向 UIView 类型的指针,代表要变换的列表项。
+ * @return 如果变换成功,返回 true;否则返回 false。
+ */
+static bool TransformItemBaseOnPosition(UITransformList* list, UIView* item)
+{
+ // 检查传入的参数是否有效
+ if (list == nullptr || item == nullptr) {
+ return false;
+ }
+ // 检查列表项的类型是否为 UI_TRANSFORM_GROUP
+ if (item->GetViewType() != UI_TRANSFORM_GROUP) {
+ return false;
+ }
+ // 将列表项转换为 UITransformGroup 类型
+ UITransformGroup* group = dynamic_cast<UITransformGroup*>(item);
+ // 如果转换失败,返回 false
+ if (group == nullptr) {
+ return false;
+ }
+ // 获取列表项的宽度和高度
+ int16_t w = group->GetWidth();
+ int16_t h = group->GetHeight();
+ // 如果列表的方向是垂直的
+ if (list->GetDirection() == UIList::VERTICAL) {
+ // 计算列表的垂直中心位置
+ int16_t midY = list->GetY() + (list->GetHeight() >> 1);
+ // 获取列表项的垂直位置
+ int16_t y = group->GetY();
+ // 计算列表项到列表中心的垂直偏移量
+ int offset = (y + (h >> 1) - midY);
+ // 使用 SineEaseIn 缓动函数计算缩放比例
+ int temp = EasingEquation::SineEaseIn(0, ARC_SCALE_LIST_SCALE_FACTOR, abs(offset), ARC_SCALE_LIST_SCALE_FACTOR);
+ // 计算最终的缩放比例
+ float scale = 1.0 - (static_cast<float>(temp) / ARC_SCALE_LIST_SCALE_FACTOR);
+ // 应用缩放比例到列表项
+ group->Scale(Vector2<float>(scale, scale), Vector2<float>(w * 0.75, h >> 1));
+ // 如果列表项在列表的中心区域,返回 true
+ if ((y <= midY) && (y + group->GetHeight() >= midY)) {
+ return true;
+ }
+ }
+ // 如果列表项不在列表的中心区域,返回 false
+ return false;
+}
+
+
+void ArcScaleListDesktopFragment::OnCreateView(void* data)
+{
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ArcScaleListDesktopFragment::OnCreateView");
+ if(nullptr == ArcScaleListAdapter_)
+ {
+ ArcScaleListAdapter_ = new ArcScaleListItemAdapter();
+ if(nullptr == ArcScaleListAdapter_)
+ {
+ return;
+ }
+ }
+ ArcScaleListAdapter_->SetItemClickListener(this);
+ /* -------------------------------------------------------------------------- */
+ /* -------------------------------------------------------------------------- */
+ if (nullptr == ArcScaleList_)
+ {
+ ArcScaleList_ = new UITransformList(UIList::VERTICAL);
+ if (nullptr == ArcScaleList_)
+ {
+ return;
+ }
+ }
+ ArcScaleList_->SetPosition(ARC_SCALE_LIST_X, ARC_SCALE_LIST_Y, ARC_SCALE_LIST_WIDTH, ARC_SCALE_LIST_HEIGHT);
+ ArcScaleList_->SetItemTransformFunc(&TransformItemBaseOnPosition);
+ ArcScaleList_->SetDraggable(true);
+ ArcScaleList_->SetThrowDrag(true);
+ ArcScaleList_->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+ // 让首尾元素也能滑动到屏幕中线处:在顶部/底部各预留半屏的空白区
+ ArcScaleList_->SetScrollBlankSize(VERTICAL_RESOLUTION / 2, UIAbstractScroll::Direction::TOP);
+ ArcScaleList_->SetScrollBlankSize(VERTICAL_RESOLUTION / 2, UIAbstractScroll::Direction::BOTTOM);
+ ArcScaleList_->SetMaxScrollDistance(1000);
+ ArcScaleList_->SetYScrollBarVisible(true);
+ ArcScaleList_->SetReboundSize(5);
+ ArcScaleList_->EnableAutoAlign(true);
+ ArcScaleList_->SetItemSpace(20);
+ ArcScaleList_->SetSelectPosition(ARC_SCALE_LIST_HEIGHT / 2);
+ ArcScaleList_->SetRotateFactor(1.0);
+ ArcScaleList_->RequestFocus();
+ ArcScaleList_->RefreshList();
+ /* -------------------------------------------------------------------------- */
+ if(nullptr == ArcScaleListDragListener_)
+ {
+ ArcScaleListDragListener_ = new AppListOnDragListener();
+ if (nullptr == ArcScaleListDragListener_)
+ return;
+ }
+ ArcScaleList_->SetOnDragListener(ArcScaleListDragListener_);
+ /* -------------------------------------------------------------------------- */
+ fragmentView_.Add(ArcScaleList_);
+}
+
+
+void ArcScaleListDesktopFragment::OnDestroyView()
+{
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ArcScaleListDesktopFragment::OnDestroyView");
+ int16_t arclistHeadY = ArcScaleList_->GetChildrenHead()->GetY();
+ int16_t arclistHeadIndex = ArcScaleList_->GetChildrenHead()->GetViewIndex();
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%d],listHeadY = %d,listHeadIndex = %d", __LINE__,arclistHeadY,arclistHeadIndex);
+ ApplistModel *model = &ApplistModel::GetInstance();
+ model->SetArcListHeadItemY(arclistHeadY); //设置头部Y坐标
+ model->SetArcListStartIndex(arclistHeadIndex); //设置头部Index
+
+ ClearAppItemToList();
+
+ if (ArcScaleList_ != nullptr) {
+ delete ArcScaleList_;
+ ArcScaleList_ = nullptr;
+ }
+ if (ArcScaleListAdapter_ != nullptr) {
+ delete ArcScaleListAdapter_;
+ ArcScaleListAdapter_ = nullptr;
+ }
+ if (ArcScaleListDragListener_ != nullptr) {
+ delete ArcScaleListDragListener_;
+ ArcScaleListDragListener_ = nullptr;
+ }
+}
+
+bool ArcScaleListDesktopFragment::OnClick(UIView &view, const ClickEvent &event)
+{
+ UNUSED(event);
+ AppItemView *itemView = dynamic_cast<AppItemView *>(&view);
+ if (itemView == nullptr) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "itemView is nullptr");
+ return false;
+ }
+ AppViewId viewId = itemView->GetViewId();
+ char *uid = (char *)itemView->GetAppUid();
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ArcScaleListDesktopFragment::OnClick viewid = %d", viewId);
+ return SwitchView(viewId, uid, TransitionType::TRANSITION_INVALID, ARC_SCALE_LIST_STYLE);
+}
+
+
+
+void ArcScaleListDesktopFragment::AddAppItemToList(const AppItem &item)
+{
+ ArcScaleListAdapter_->AddListItem(item);
+}
+
+void ArcScaleListDesktopFragment::ClearAppItemToList()
+{
+ ArcScaleListAdapter_->ClearItem();
+}
+
+void ArcScaleListDesktopFragment::RefreshAppList(void)
+{
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ArcScaleListDesktopFragment::RefreshAppList");
+ if (ArcScaleList_ == nullptr || ArcScaleListAdapter_ == nullptr) {
+ return;
+ }
+ uint16_t startIndex = 0;
+ int16_t headY = 0;
+ ApplistModel *model = &ApplistModel::GetInstance();
+ if (model->GetArcListStartIndex() >= model->GetAppListNum()) {
+ startIndex = model->GetAppListNum() - 1;
+ headY = VERTICAL_RESOLUTION / 2;
+ } else {
+ uint16_t presliceId = NativeAbility::GetInstance().GetPreSliceId();
+ if (presliceId == VIEW_MAIN) //如果是从主页进入的,那么startIndex = 0,headY = 0
+ {
+ startIndex = 0;
+ headY = 53;
+ } else { //如果是从其他页面进入的,那么startIndex = model->GetArcListStartIndex(),headY = model->GetArcListHeadItemY()
+ startIndex = model->GetArcListStartIndex();
+ headY = model->GetArcListHeadItemY();
+ }
+ if (headY == 0) {
+ headY = VERTICAL_RESOLUTION / 2;
+ // headY = -42;
+ }
+ }
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%d],startIndex = %d,headY = %d", __LINE__,startIndex,headY);
+ ArcScaleList_->SetAdapter(ArcScaleListAdapter_);
+ ArcScaleList_->SetStartIndex(startIndex);//设置起始索引。
+ ArcScaleList_->ScrollBy(headY);//滚动到指定的 headY 位置。
+ ArcScaleList_->RefreshList();
+}
+
+/* ---------------------------------- 弧形列表 ---------------------------------- */
+#define ARC_SCALE_LIST_ITEM_WIDTH (440)
+#define ARC_SCALE_LIST_ITEM_HEIGHT (120)
+
+#define ARC_SCALE_LIST_IMAGE_X (20)
+#define ARC_SCALE_LIST_IMAGE_WIDTH (ARC_SCALE_LIST_ITEM_HEIGHT - 10)
+#define ARC_SCALE_LIST_IMAGE_HEIGHT (ARC_SCALE_LIST_ITEM_HEIGHT - 10)
+#define ARC_SCALE_LIST_IMAGE_Y ((ARC_SCALE_LIST_ITEM_HEIGHT - ARC_SCALE_LIST_IMAGE_HEIGHT) / 2)
+
+#define ARC_SCALE_LIST_TEXT_X (ARC_SCALE_LIST_IMAGE_X + ARC_SCALE_LIST_IMAGE_WIDTH + 20)
+#define ARC_SCALE_LIST_TEXT_WIDTH (ARC_SCALE_LIST_ITEM_WIDTH - ARC_SCALE_LIST_TEXT_X)
+#define ARC_SCALE_LIST_TEXT_HEIGHT (44)
+#define ARC_SCALE_LIST_TEXT_Y ((ARC_SCALE_LIST_ITEM_HEIGHT - ARC_SCALE_LIST_TEXT_HEIGHT) / 2)
+
+ArcScaleListItemView::ArcScaleListItemView()
+{
+ Resize(ARC_SCALE_LIST_ITEM_WIDTH, ARC_SCALE_LIST_ITEM_HEIGHT);
+ SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+ SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919);
+ SetStyle(STYLE_BORDER_RADIUS, 100); // 胶囊形状
+ SetTouchable(true);
+ SetUpChild();
+}
+
+ArcScaleListItemView::~ArcScaleListItemView()
+{
+ RemoveAll();
+ if (image_ != nullptr) {
+ delete image_;
+ image_ = nullptr;
+ }
+ if (label_ != nullptr) {
+ delete label_;
+ label_ = nullptr;
+ }
+}
+
+void ArcScaleListItemView::SetItemInfo(const AppItem &itemInfo)
+{
+ itemInfo_ = itemInfo;
+ image_->SetSrc(itemInfo.iconSmall);
+ if(VIEW_EXTERN_APP != itemInfo.id) {
+ label_->SetTextId(itemInfo.labelId);
+ } else {
+ label_->SetText(itemInfo.label);
+ }
+}
+
+void ArcScaleListItemView::SetUpChild()
+{
+ if (image_ == nullptr) {
+ image_ = new UIImageView();
+ if (image_ == nullptr) {
+ return ;
+ }
+ }
+ image_->SetPosition(ARC_SCALE_LIST_IMAGE_X, ARC_SCALE_LIST_IMAGE_Y, ARC_SCALE_LIST_IMAGE_WIDTH, ARC_SCALE_LIST_IMAGE_HEIGHT);
+ image_->SetAutoEnable(false);
+ image_->SetResizeMode(UIImageView::FILL);
+ Add(image_);
+ /* -------------------------------------------------------------------------- */
+ if (label_ == nullptr) {
+ label_ = new UILabelExt();
+ if (label_ == nullptr) {
+ delete image_;
+ image_ = nullptr;
+ return ;
+ }
+ }
+ label_->SetPosition(ARC_SCALE_LIST_TEXT_X, ARC_SCALE_LIST_TEXT_Y, ARC_SCALE_LIST_TEXT_WIDTH, ARC_SCALE_LIST_TEXT_HEIGHT);
+ label_->SetStyle(STYLE_LINE_HEIGHT,44);
+ label_->SetStyle(STYLE_TEXT_FONT,38);
+ label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 38);
+ label_->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);
+ label_->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_TOP);
+ Add(label_);
+}
+AppViewId ArcScaleListItemView::GetViewId()
+{
+ return (AppViewId)itemInfo_.id;
+}
+const char *ArcScaleListItemView::GetAppUid()
+{
+ return itemInfo_.uid;
+}
+UILabelExt *ArcScaleListItemView::GetLabel(void)
+{
+ return label_;
+}
+UIImageView *ArcScaleListItemView::GetImage(void)
+{
+ return image_;
+}
+}