ArkUI TextDrag 组件知识库
文档版本:v1.0 更新时间:2026-02-04 源码版本:OpenHarmony ace_engine (master 分支)
📚 目录
概述
组件定位
TextDrag 组件是 OpenHarmony ArkUI 框架中的文本拖拽预览组件,用于在文本选择后显示拖拽预览效果。它是一个独立的 FrameNode,悬浮在主内容之上,展示被选中的文本内容。
技术架构
┌─────────────────────────────────────────────────────────┐
│ 文本选择状态 │
│ TextPattern 或 TextFieldPattern │
│ 用户选择文本区域 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ TextDragBase 接口 │
│ 源码:text_drag_base.h │
│ 提供拖拽所需的文本信息 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ TextDragPattern 创建拖拽节点 │
│ 源码:text_drag_pattern.cpp:87-123 │
│ 1. CreateDragNode() - 创建拖拽FrameNode │
│ 2. CalculateTextDragData() - 计算拖拽数据 │
│ 3. Initialize() - 初始化拖拽内容 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 拖拽预览渲染 │
│ TextDragPaintMethod + TextDragOverlayModifier │
│ 绘制拖拽预览效果 │
└─────────────────────────────────────────────────────────┘
功能特性
| 功能类别 | 具体功能 |
|---|---|
| 拖拽预览 | 显示选中文本的预览效果 |
| 自适应尺寸 | 根据选中内容自动计算预览框大小 |
| 圆角背景 | 支持圆角背景渲染 |
| 透明度效果 | 支持半透明拖拽效果 |
| 图片支持 | 支持包含图片的文本拖拽 |
| 动画支持 | 支持拖拽动画效果 |
| 多行处理 | 正确处理跨行文本选择 |
目录结构
核心代码目录
frameworks/core/components_ng/pattern/text_drag/
├── text_drag_base.h # TextDrag 基类接口
├── text_drag_pattern.h # TextDrag Pattern 定义
├── text_drag_pattern.cpp # TextDrag Pattern 实现
├── text_drag_paint_method.h # 拖拽绘制方法
├── text_drag_paint_method.cpp # 拖拽绘制实现
├── text_drag_overlay_modifier.h # 拖拽覆盖修饰器
└── text_drag_overlay_modifier.cpp # 拖拽覆盖修饰器实现
代码规模
| 项目 | 说明 |
|---|---|
| 核心文件 | 7 个文件 |
| Pattern文件 | text_drag_pattern.h (285行) |
| Paint文件 | text_drag_paint_method.h/cpp |
| Modifier文件 | text_drag_overlay_modifier.h/cpp |
核心类继承关系
类继承图
AceType (基类)
↓
TextDragBase (拖拽基类接口)
↑
│ (被继承)
│
TextPattern (纯文本显示)
TextFieldPattern (文本输入)
Pattern (基类)
↓
TextDragPattern (拖拽预览Pattern)
TextDragBase 接口
源码位置:text_drag_base.h
核心接口方法
class TextDragBase : public virtual AceType {
public:
// 判断是否为 TextArea
virtual bool IsTextArea() const = 0;
// 获取文本区域
virtual const RectF& GetTextRect() const = 0;
virtual RectF GetTextContentRect(bool isActualText = false) const = 0;
// 获取行高
virtual float GetLineHeight() const = 0;
// 获取文本框(选中区域)
virtual std::vector<RectF> GetTextBoxes() = 0;
// 获取父节点全局偏移
virtual OffsetF GetParentGlobalOffset() const = 0;
// 拖拽节点管理
virtual const RefPtr<FrameNode>& MoveDragNode() = 0;
virtual const RefPtr<Paragraph>& GetDragParagraph() const = 0;
// 拖拽生命周期回调
virtual void OnDragNodeFloating() {}
virtual void CloseSelectOverlay() = 0;
virtual void CloseHandleAndSelect() { CloseSelectOverlay(); }
// 手柄显示控制
virtual void ShowHandles(const bool isNeedShowHandles) { ShowHandles(); }
virtual void ShowHandles() { CreateHandles(); }
virtual bool IsHandlesShow() { return true; }
virtual void CreateHandles() {}
// 键盘控制
virtual bool CloseKeyboard(bool forceClose) = 0;
// 拖拽坐标
virtual OffsetF GetDragUpperLeftCoordinates() = 0;
// Span图片布局
virtual void InitSpanImageLayout(
const std::vector<int32_t>& placeholderIndex,
const std::vector<RectF>& rectsForPlaceholders,
OffsetF contentOffset) {}
virtual OffsetF GetContentOffset() { return OffsetF(0, 0); }
// AI实体识别相关
virtual void ResetAISelected(AIResetSelectionReason reason) {}
virtual void ShowAIEntityMenuForCancel() {}
virtual bool IsPreviewMenuShow() { return false; }
// 拖拽节点分离回调
virtual void OnDragNodeDetachFromMainTree() {}
};
实现类
TextDragBase 被以下类实现:
- TextPattern - 纯文本显示组件
- TextFieldPattern - 文本输入组件(包括 TextArea)
Pattern层详解
TextDragPattern
源码位置:text_drag_pattern.h
类定义
class TextDragPattern : public Pattern {
DECLARE_ACE_TYPE(TextDragPattern, Pattern);
public:
TextDragPattern() = default;
~TextDragPattern() override = default;
// 创建拖拽节点
static RefPtr<FrameNode> CreateDragNode(const RefPtr<FrameNode>& hostNode);
// 初始化拖拽数据
void Initialize(const RefPtr<Paragraph>& paragraph, const TextDragData& data)
{
paragraph_ = paragraph;
textDragData_ = data;
}
// 更新段落
void UpdateParagraph(const RefPtr<Paragraph>& paragraph)
{
paragraph_ = paragraph;
}
// 创建绘制方法
RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
// 获取拖拽信息
const WeakPtr<Paragraph>& GetParagraph() const { return paragraph_; }
const RectF& GetTextRect() const { return textDragData_.textRect_; }
float GetFrameWidth() const { return textDragData_.frameWidth_; }
float GetFrameHeight() const { return textDragData_.frameHeight_; }
float GetLineHeight() const { return textDragData_.lineHeight_; }
const SelectPositionInfo& GetSelectPosition() const { return textDragData_.selectPosition_; }
bool OneLineSelected() const { return textDragData_.oneLineSelected_; }
// 路径生成
const std::shared_ptr<RSPath>& GetClipPath();
const std::shared_ptr<RSPath>& GetBackgroundPath();
const std::shared_ptr<RSPath>& GetSelBackgroundPath();
// 动画状态
bool IsAnimating() {
return overlayModifier_ && overlayModifier_->IsAnimating();
}
// 节点分离回调
void OnDetachFromMainTree() override;
protected:
// 计算拖拽数据
static TextDragData CalculateTextDragData(
RefPtr<TextDragBase>& pattern,
RefPtr<FrameNode>& dragNode,
const RefPtr<FrameNode>& hostNode = nullptr);
// 布局交换
bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty,
const DirtySwapConfig& config) override;
// 路径生成方法
std::shared_ptr<RSPath> GenerateClipPath();
std::shared_ptr<RSPath> GenerateBackgroundPath(float offset, float radiusRatio = 1.0f);
std::shared_ptr<RSPath> GenerateSelBackgroundPath(float offset);
// 手柄计算
static RectF GetHandler(const bool isLeftHandler,
const std::vector<RectF> boxes,
const RectF contentRect,
const OffsetF globalOffset,
const OffsetF textStartOffset);
static void AdjustHandlers(const RectF contentRect,
RectF& leftHandler, RectF& rightHandler);
// 其他辅助方法
void GenerateBackgroundPoints(std::vector<TextPoint>& points,
float offset, bool needAdjust = true);
void CalculateLineAndArc(std::vector<TextPoint>& points,
std::shared_ptr<RSPath>& path, float radiusRatio);
void CalculateLine(std::vector<TextPoint>& points, std::shared_ptr<RSPath>& path);
static void CalculateOverlayOffset(RefPtr<FrameNode>& dragNode,
OffsetF& offset, const RefPtr<FrameNode>& hostNode = nullptr);
static void DropBlankLines(std::vector<RectF>& boxes);
private:
RefPtr<TextDragOverlayModifier> overlayModifier_;
TextDragData textDragData_;
WeakPtr<Paragraph> paragraph_;
RefPtr<Paragraph> animatingParagraph_;
std::shared_ptr<RSPath> clipPath_;
std::shared_ptr<RSPath> backGroundPath_;
std::shared_ptr<RSPath> selBackGroundPath_;
std::list<RefPtr<FrameNode>> imageChildren_;
std::vector<RectF> rectsForPlaceholders_;
TextDragInfo info_;
std::function<void()> onDetachFromMainTree_ = nullptr;
};
核心职责
- 拖拽节点创建:
CreateDragNode()静态方法创建拖拽 FrameNode - 拖拽数据计算:
CalculateTextDragData()计算拖拽预览的位置和尺寸 - 绘制管理:通过
CreateNodePaintMethod()创建绘制方法 - 路径生成:生成裁剪路径、背景路径、选中背景路径
- 生命周期管理:处理拖拽节点的附加和分离
拖拽数据结构
TextDragData
源码位置:text_drag_pattern.h:54-73
struct TextDragData {
TextDragData() {}
TextDragData(RectF textRect, float frameWidth, float frameHeight,
float lineHeight, float lastLineHeight)
: textRect_(textRect), frameWidth_(frameWidth),
frameHeight_(frameHeight), lineHeight_(lineHeight),
lastLineHeight_(lastLineHeight)
{}
RectF textRect_; // 文本区域
float frameWidth_ = 0; // 框架宽度
float frameHeight_ = 0; // 框架高度
float lineHeight_ = 0; // 行高
float lastLineHeight_ = 0; // 最后一行高度
SelectPositionInfo selectPosition_; // 选择位置信息
bool oneLineSelected_ = false; // 是否单行选中
void initSelecitonInfo(SelectPositionInfo selectionInfo, bool oneLineSelected)
{
selectPosition_ = selectionInfo;
oneLineSelected_ = oneLineSelected;
}
};
SelectPositionInfo
源码位置:text_drag_pattern.h:34-52
struct SelectPositionInfo {
SelectPositionInfo() {}
SelectPositionInfo(float startX, float startY, float endX, float endY)
: startX_(startX), startY_(startY), endX_(endX), endY_(endY)
{}
void InitGlobalInfo(float globalX, float globalY)
{
globalX_ = globalX;
globalY_ = globalY;
}
float startX_ = 0; // 起始X坐标
float startY_ = 0; // 起始Y坐标
float endX_ = 0; // 结束X坐标
float endY_ = 0; // 结束Y坐标
float globalX_ = 0; // 全局X坐标
float globalY_ = 0; // 全局Y坐标
};
TextDragInfo
struct TextDragInfo {
// 拖拽手柄动画信息
// (具体定义在其他头文件中)
};
拖拽渲染
TextDragPaintMethod
类定义
class TextDragPaintMethod : public NodePaintMethod {
DECLARE_ACE_TYPE(TextDragPaintMethod, NodePaintMethod);
public:
TextDragPaintMethod(const WeakPtr<TextDragPattern>& textDragPattern,
const RefPtr<TextDragOverlayModifier>& overlayModifier);
~TextDragPaintMethod() override = default;
RefPtr<Modifier> GetOverlayModifier(PaintWrapper* paintWrapper) override;
void UpdateOverlayModifier(PaintWrapper* paintWrapper) override;
private:
WeakPtr<TextDragPattern> textDragPattern_;
RefPtr<TextDragOverlayModifier> overlayModifier_;
};
TextDragOverlayModifier
源码位置:text_drag_overlay_modifier.h
类定义
class TextDragOverlayModifier : public OverlayModifier {
DECLARE_ACE_TYPE(TextDragOverlayModifier, OverlayModifier);
public:
explicit TextDragOverlayModifier(const WeakPtr<TextDragPattern>& textDragPattern);
~TextDragOverlayModifier() override = default;
void onDraw(DrawingContext& context) override;
// 动画状态
bool IsAnimating() const { return isAnimating_; }
void SetAnimating(bool animating) { isAnimating_ = animating; }
private:
WeakPtr<TextDragPattern> textDragPattern_;
bool isAnimating_ = false;
};
渲染流程
┌─────────────────────────────────────────────────────────┐
│ TextDragOverlayModifier::onDraw() │
│ 1. 获取 Paragraph │
│ 2. 获取 ClipPath(裁剪路径) │
│ 3. 获取 BackgroundPath(背景路径) │
│ 4. 获取 SelBackgroundPath(选中背景路径) │
│ 5. 绘制背景 │
│ 6. 绘制选中内容 │
│ 7. 应用裁剪 │
└─────────────────────────────────────────────────────────┘
拖拽计算
CreateDragNode 流程
源码位置:text_drag_pattern.cpp:87-123
RefPtr<FrameNode> TextDragPattern::CreateDragNode(const RefPtr<FrameNode>& hostNode)
{
CHECK_NULL_RETURN(hostNode, nullptr);
// 1. 获取 TextDragBase 接口
auto hostPattern = hostNode->GetPattern<TextDragBase>();
// 2. 创建唯一的节点ID
const auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
// 3. 创建 TextDrag FrameNode
auto dragNode = FrameNode::GetOrCreateFrameNode(
V2::TEXTDRAG_ETS_TAG, nodeId,
[]() { return AceType::MakeRefPtr<TextDragPattern>(); });
// 4. 复制前景色
auto dragContext = dragNode->GetRenderContext();
auto hostContext = hostNode->GetRenderContext();
if (hostContext->HasForegroundColor()) {
dragContext->UpdateForegroundColor(hostContext->GetForegroundColor().value());
}
// 5. 获取 TextDragPattern 并计算拖拽数据
auto dragPattern = dragNode->GetPattern<TextDragPattern>();
auto data = CalculateTextDragData(hostPattern, dragNode, hostNode);
// 6. 初始化拖拽内容
dragPattern->Initialize(hostPattern->GetDragParagraph(), data);
dragPattern->SetLastLineHeight(data.lineHeight_);
// 7. 设置拖拽节点尺寸
CalcSize size(NG::CalcLength(dragPattern->GetFrameWidth()),
NG::CalcLength(dragPattern->GetFrameHeight()));
dragNode->GetLayoutProperty()->UpdateUserDefinedIdealSize(size);
// 8. 设置分离回调
auto onDetachFromMainTreeCallback = [weak = WeakPtr<TextDragBase>(hostPattern)]() {
auto textDragBasePattern = weak.Upgrade();
CHECK_NULL_VOID(textDragBasePattern);
textDragBasePattern->OnDragNodeDetachFromMainTree();
};
dragPattern->SetOnDetachFromMainTree(std::move(onDetachFromMainTreeCallback));
return dragNode;
}
CalculateTextDragData 流程
源码位置:text_drag_pattern.cpp:157-200
TextDragData TextDragPattern::CalculateTextDragData(
RefPtr<TextDragBase>& pattern,
RefPtr<FrameNode>& dragNode,
const RefPtr<FrameNode>& hostNode)
{
// 1. 计算文本起始偏移
OffsetF textStartOffset = {
pattern->GetTextRect().GetX(),
pattern->IsTextArea() ? pattern->GetTextRect().GetY()
: pattern->GetTextContentRect().GetY()
};
// 2. 获取内容区域
auto contentRect = pattern->GetTextContentRect(true);
// 3. 计算偏移量
float bothOffset = TEXT_DRAG_OFFSET.ConvertToPx() * CONSTANT_HALF;
// 4. 获取选中文本框
auto boxes = pattern->GetTextBoxes();
CHECK_NULL_RETURN(!boxes.empty(), {});
// 5. 去除空白行
DropBlankLines(boxes);
// 6. 获取全局偏移并计算Overlay偏移
auto globalOffset = pattern->GetParentGlobalOffset();
CalculateOverlayOffset(dragNode, globalOffset, hostNode);
// 7. 计算左右手柄位置
RectF leftHandler = GetHandler(true, boxes, contentRect, globalOffset, textStartOffset);
RectF rightHandler = GetHandler(false, boxes, contentRect, globalOffset, textStartOffset);
// 8. 调整手柄位置
AdjustHandlers(contentRect, leftHandler, rightHandler);
// 9. 计算宽度和高度
float width = rightHandler.GetX() - leftHandler.GetX();
float height = rightHandler.GetY() - leftHandler.GetY() + rightHandler.Height();
// 10. 计算全局坐标
auto dragOffset = TEXT_DRAG_OFFSET.ConvertToPx();
float globalX = leftHandler.GetX() + globalOffset.GetX() - dragOffset;
float globalY = leftHandler.GetY() + globalOffset.GetY() - dragOffset;
// 11. 处理最小宽度
auto box = boxes.front();
float delta = 0.0f;
if (leftHandler.GetY() == rightHandler.GetY()) {
if (width + bothOffset < TEXT_DRAG_MIN_WIDTH.ConvertToPx()) {
delta = TEXT_DRAG_MIN_WIDTH.ConvertToPx() - (width + bothOffset);
width += delta;
globalX -= delta / CONSTANT_HALF;
}
} else {
globalX = contentRect.Left() + globalOffset.GetX() - dragOffset;
dragPattern->AdjustMaxWidth(width, contentRect, boxes);
}
// 12. 设置内容和位置
// ... (省略部分代码)
return TextDragData(...);
}
路径生成算法
GenerateBackgroundPath
std::shared_ptr<RSPath> TextDragPattern::GenerateBackgroundPath(
float offset, float radiusRatio)
{
std::vector<TextPoint> points;
GenerateBackgroundPoints(points, offset, true);
auto path = std::make_shared<RSPath>();
CalculateLineAndArc(points, path, radiusRatio);
return path;
}
GenerateBackgroundPoints
生成背景路径的关键点,包括:
- 左上角点
- 右上角点
- 右下角点
- 左下角点
- 圆角控制点
执行流程
拖拽创建流程
┌─────────────────────────────────────────────────────────┐
│ 用户选择文本 │
│ TextPattern 或 TextFieldPattern │
│ 用户长按或拖拽选择文本 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 创建拖拽节点 │
│ TextDragPattern::CreateDragNode(hostNode) │
│ 1. 创建 FrameNode(V2::TEXTDRAG_ETS_TAG) │
│ 2. 创建 TextDragPattern 实例 │
│ 3. CalculateTextDragData() - 计算拖拽数据 │
│ 4. Initialize(paragraph, data) - 初始化 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 添加到Overlay │
│ OverlayManager::AddOverlayNode(dragNode) │
│ 拖拽节点作为Overlay显示在主内容之上 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 渲染拖拽预览 │
│ TextDragPaintMethod::GetOverlayModifier() │
│ TextDragOverlayModifier::onDraw() │
│ 1. 获取/生成路径 │
│ 2. 绘制圆角背景 │
│ 3. 绘制选中文本 │
└─────────────────────────────────────────────────────────┘
拖拽更新流程
┌─────────────────────────────────────────────────────────┐
│ 选择变化 │
│ 用户调整选择范围 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 重新计算拖拽数据 │
│ CalculateTextDragData() │
│ 1. 获取新的 TextBoxes │
│ 2. 重新计算手柄位置 │
│ 3. 更新尺寸和位置 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 更新拖拽节点 │
│ dragNode->GetLayoutProperty()->UpdateUserDefinedIdealSize() │
│ MarkDirty() - 标记需要重新布局和渲染 │
└─────────────────────────────────────────────────────────┘
拖拽销毁流程
┌─────────────────────────────────────────────────────────┐
│ 用户取消选择或完成操作 │
│ - 点击空白区域 │
│ - 按下ESC键 │
│ - 完成拖拽操作 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 关闭选择Overlay │
│ TextDragBase::CloseSelectOverlay() │
│ TextFieldPattern::CloseSelectOverlay() │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 从Overlay移除拖拽节点 │
│ OverlayManager::RemoveOverlayNode(dragNode) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 触发分离回调 │
│ TextDragPattern::OnDetachFromMainTree() │
│ 调用 onDetachFromMainTree_ 回调 │
│ 通知宿主节点拖拽已分离 │
└─────────────────────────────────────────────────────────┘
关键实现细节
1. 手柄位置计算
GetHandler 方法计算左右手柄的位置:
RectF GetHandler(const bool isLeftHandler,
const std::vector<RectF> boxes,
const RectF contentRect,
const OffsetF globalOffset,
const OffsetF textStartOffset)
{
// isLeftHandler = true: 计算左手柄
// isLeftHandler = false: 计算右手柄
if (isLeftHandler) {
// 获取第一个可见的box
return GetFirstBoxRect(boxes, contentRect, textStartOffset.GetY());
} else {
// 获取最后一个可见的box
return GetLastBoxRect(boxes, contentRect, textStartOffset.GetY());
}
}
2. 跨行选择处理
当选择跨越多行时:
- 左手柄:位于第一行选中文本的左上角
- 右手柄:位于最后一行选中文本的右下角
- 拖拽预览:包含从第一行到最后一行的所有选中内容
3. 单行选择优化
当只有一行被选中时(oneLineSelected_ = true):
- 拖拽预览宽度受限,最小为
TEXT_DRAG_MIN_WIDTH(64.0_vp) - 背景路径使用简化的圆角矩形
4. 圆角背景实现
拖拽预览使用圆角背景,圆角半径为 TEXT_DRAG_RADIUS (18.0_vp):
constexpr Dimension TEXT_DRAG_RADIUS = 18.0_vp;
路径生成通过 GenerateBackgroundPath() 实现:
- 生成四个角的控制点
- 使用
RSPath的arcTo()方法绘制圆角 - 使用
lineTo()方法连接直线段
5. 透明度效果
拖拽预览的背景色使用半透明效果:
constexpr uint32_t TEXT_DRAG_COLOR_BG = 0xf2ffffff;
6. 图片支持
拖拽预览支持包含图片的文本:
// 初始化Span图片布局
void InitSpanImageLayout(const std::list<RefPtr<FrameNode>>& imageChildren,
const std::vector<RectF>& rectsForPlaceholders)
{
imageChildren_ = imageChildren;
rectsForPlaceholders_ = rectsForPlaceholders;
}
渲染时会将图片与文本一起绘制。
7. 动画支持
拖拽预览支持动画效果:
bool IsAnimating() {
return overlayModifier_ && overlayModifier_->IsAnimating();
}
与TextPattern/TextFieldPattern的关系
TextDragBase 接口实现
| 实现类 | 说明 |
|---|---|
| TextPattern | 纯文本显示组件,实现 TextDragBase 接口以支持文本拖拽 |
| TextFieldPattern | 文本输入组件,实现 TextDragBase 接口以支持输入内容的拖拽 |
调用关系
TextPattern / TextFieldPattern
↓ 实现
TextDragBase 接口
↓ 使用
TextDragPattern::CreateDragNode()
↓ 创建
独立的 TextDrag FrameNode (拖拽预览)
数据流向
TextPattern/TextFieldPattern
↓ 提供
- GetTextRect() - 文本区域
- GetTextBoxes() - 选中文本框
- GetParentGlobalOffset() - 全局偏移
- GetDragParagraph() - 文本段落
↓ 使用
TextDragPattern::CalculateTextDragData()
↓ 生成
TextDragData (拖拽数据)
↓ 初始化
TextDragPattern
↓ 渲染
拖拽预览效果
使用示例
TextPattern 中的使用
TextPattern 在用户选择文本时创建拖拽预览:
// TextPattern 实现了 TextDragBase
class TextPattern : public Pattern, public TextDragBase {
// ...
};
TextFieldPattern 中的使用
TextFieldPattern 在用户选择输入内容时创建拖拽预览:
// TextFieldPattern 实现了 TextDragBase
class TextFieldPattern : public ScrollablePattern, public TextDragBase {
// ...
};
调试指南
常用日志标签
| 日志标签 | 说明 |
|---|---|
AceLogTag::ACE_TEXT |
文本拖拽相关日志 |
关键断点位置
| 文件 | 方法 | 说明 |
|---|---|---|
| text_drag_pattern.cpp | CreateDragNode() |
拖拽节点创建 |
| text_drag_pattern.cpp | CalculateTextDragData() |
拖拽数据计算 |
| text_drag_overlay_modifier.cpp | onDraw() |
拖拽渲染 |
| text_drag_pattern.cpp | GenerateBackgroundPath() |
背景路径生成 |
参考源码
核心文件
-
基类接口:
-
Pattern层:
-
渲染层:
-
修饰器:
文档维护:如有疑问或需要补充,请参考上述源码位置。