Skip to content

Commit ab995b9

Browse files
zyqqyiqiuzhengLuozf12345
authored
TDTreeSelect: 一级菜单选中项右侧增加向外弯折圆角效果 (#880)
* fix: 测试 * fix(tree-select): 前后选项圆角 * feature: 新增外弯折圆角半径 --------- Co-authored-by: yiqiuzheng <yiqiuzheng@tencent.com> Co-authored-by: Luozf <35024333+Luozf12345@users.noreply.github.com>
1 parent eaa83da commit ab995b9

3 files changed

Lines changed: 134 additions & 40 deletions

File tree

tdesign-component/example/assets/api/tree-select_api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@
2525
| multiple | bool | false | 支持多选 |
2626
| onChange | TDTreeSelectChangeEvent? | - | 选中值发生变化 |
2727
| options | List<TDSelectOption> | const [] | 展示的选项列表 |
28+
| outwardCornerRadius | double | 9 | 一级菜单选中项的外弯折圆角半径 |
2829
| style | TDTreeSelectStyle | TDTreeSelectStyle.normal | 一级菜单样式 |

tdesign-component/lib/src/components/tree/td_tree_select.dart

Lines changed: 132 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class TDTreeSelect extends StatefulWidget {
4949
this.multiple = false,
5050
this.style = TDTreeSelectStyle.normal,
5151
this.height = 336,
52+
this.outwardCornerRadius = 9,
5253
}) : super(key: key);
5354

5455
/// 展示的选项列表
@@ -69,6 +70,9 @@ class TDTreeSelect extends StatefulWidget {
6970
/// 一级菜单样式
7071
final TDTreeSelectStyle style;
7172

73+
/// 一级菜单选中项的外弯折圆角半径,默认为 9
74+
final double outwardCornerRadius;
75+
7276
@override
7377
State<TDTreeSelect> createState() => _TDTreeSelectState();
7478
}
@@ -165,6 +169,12 @@ class _TDTreeSelectState extends State<TDTreeSelect> {
165169
itemBuilder: (context, index) {
166170
final option = widget.options[index];
167171
final isSelected = firstValue == option.value;
172+
// 判断上一个和下一个选项是否被选中
173+
final isPrevSelected = index > 0 &&
174+
firstValue == widget.options[index - 1].value;
175+
final isNextSelected =
176+
index < widget.options.length - 1 &&
177+
firstValue == widget.options[index + 1].value;
168178

169179
return GestureDetector(
170180
onTap: () {
@@ -181,48 +191,71 @@ class _TDTreeSelectState extends State<TDTreeSelect> {
181191
widget.onChange?.call(values, 1);
182192
});
183193
},
184-
child: Container(
185-
padding: const EdgeInsets.all(16),
186-
decoration: BoxDecoration(
187-
color: isSelected
188-
? TDTheme.of(context).bgColorContainer
189-
: null,
190-
border: isSelected &&
191-
widget.style == TDTreeSelectStyle.outline
192-
? Border(
193-
left: BorderSide(
194-
color: TDTheme.of(context).brandNormalColor,
195-
width: 3,
196-
),
197-
)
198-
: null,
199-
200-
/// todo 上下 borderRadius
201-
borderRadius: BorderRadius.only(
202-
203-
/// 选中的上一个
204-
/*topRight: Radius.circular(
205-
topAdjacent ? TDTheme.of(context).radiusLarge : 0),*/
206-
207-
/// 选中的下一个
208-
/* bottomRight: Radius.circular(
209-
bottomAdjacent ? TDTheme.of(context).radiusLarge : 0),*/
194+
child: Stack(
195+
children: [
196+
Container(
197+
width: double.infinity,
198+
padding: const EdgeInsets.all(16),
199+
decoration: BoxDecoration(
200+
color: isSelected
201+
? TDTheme.of(context).bgColorContainer
202+
: null,
203+
border: isSelected &&
204+
widget.style == TDTreeSelectStyle.outline
205+
? Border(
206+
left: BorderSide(
207+
color:
208+
TDTheme.of(context).brandNormalColor,
209+
width: 3,
210+
),
211+
)
212+
: null,
213+
),
214+
child: Text(
215+
option.label,
216+
maxLines: option.maxLines,
217+
overflow: TextOverflow.ellipsis,
218+
style: TextStyle(
219+
fontSize:
220+
TDTheme.of(context).fontBodyLarge?.size ?? 16,
221+
color: isSelected
222+
? TDTheme.of(context).brandNormalColor
223+
: TDTheme.of(context).textColorPrimary,
224+
fontWeight: isSelected
225+
? FontWeight.w600
226+
: FontWeight.normal,
210227
),
211-
),
212-
child: Text(
213-
option.label,
214-
maxLines: option.maxLines,
215-
overflow: TextOverflow.ellipsis,
216-
style: TextStyle(
217-
fontSize:
218-
TDTheme.of(context).fontBodyLarge?.size ?? 16,
219-
color: isSelected
220-
? TDTheme.of(context).brandNormalColor
221-
: TDTheme.of(context).textColorPrimary,
222-
fontWeight:
223-
isSelected ? FontWeight.w600 : FontWeight.normal,
228+
),
224229
),
225-
),
230+
// 未选中项:如果上一个是选中项,在右上角画向外弯折圆角
231+
if (!isSelected && isPrevSelected)
232+
Positioned(
233+
top: 0,
234+
right: 0,
235+
child: CustomPaint(
236+
size: Size(widget.outwardCornerRadius, widget.outwardCornerRadius),
237+
painter: _OutwardCornerPainter(
238+
color:
239+
TDTheme.of(context).bgColorContainer,
240+
corner: _Corner.topRight,
241+
),
242+
),
243+
),
244+
// 未选中项:如果下一个是选中项,在右下角画向外弯折圆角
245+
if (!isSelected && isNextSelected)
246+
Positioned(
247+
bottom: 0,
248+
right: 0,
249+
child: CustomPaint(
250+
size: Size(widget.outwardCornerRadius, widget.outwardCornerRadius),
251+
painter: _OutwardCornerPainter(
252+
color:
253+
TDTheme.of(context).bgColorContainer,
254+
corner: _Corner.bottomRight,
255+
),
256+
),
257+
),
258+
],
226259
),
227260
);
228261
},
@@ -429,3 +462,62 @@ class _TDTreeSelectState extends State<TDTreeSelect> {
429462
);
430463
}
431464
}
465+
466+
/// 向外弯折圆角的位置枚举
467+
enum _Corner {
468+
topRight,
469+
bottomRight,
470+
}
471+
472+
/// 自定义画笔:绘制向外弯折的圆角效果
473+
/// 原理:在选中项的右上角/右下角绘制一个填充色的矩形,然后用白色圆弧挖出一个反向圆角
474+
class _OutwardCornerPainter extends CustomPainter {
475+
final Color color;
476+
final _Corner corner;
477+
478+
_OutwardCornerPainter({required this.color, required this.corner});
479+
480+
@override
481+
void paint(Canvas canvas, Size size) {
482+
final paint = Paint()
483+
..color = color
484+
..style = PaintingStyle.fill;
485+
486+
final path = Path();
487+
final r = size.width;
488+
489+
switch (corner) {
490+
case _Corner.topRight:
491+
// 从右上角开始,画一个矩形区域,然后用圆弧挖出向外弯折的效果
492+
path.moveTo(0, 0);
493+
path.lineTo(r, 0);
494+
path.lineTo(r, r);
495+
path.arcToPoint(
496+
Offset(0, 0),
497+
radius: Radius.circular(r),
498+
clockwise: false,
499+
);
500+
path.close();
501+
break;
502+
case _Corner.bottomRight:
503+
// 从右下角开始,画一个矩形区域,然后用圆弧挖出向外弯折的效果
504+
path.moveTo(r, 0);
505+
path.lineTo(r, r);
506+
path.lineTo(0, r);
507+
path.arcToPoint(
508+
Offset(r, 0),
509+
radius: Radius.circular(r),
510+
clockwise: false,
511+
);
512+
path.close();
513+
break;
514+
}
515+
516+
canvas.drawPath(path, paint);
517+
}
518+
519+
@override
520+
bool shouldRepaint(covariant _OutwardCornerPainter oldDelegate) {
521+
return oldDelegate.color != color || oldDelegate.corner != corner;
522+
}
523+
}

tdesign-site/src/tree-select/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ String类型ID(问题3)
211211
| multiple | bool | false | 支持多选 |
212212
| onChange | TDTreeSelectChangeEvent? | - | 选中值发生变化 |
213213
| options | List<TDSelectOption> | const [] | 展示的选项列表 |
214+
| outwardCornerRadius | double | 9 | 一级菜单选中项的外弯折圆角半径 |
214215
| style | TDTreeSelectStyle | TDTreeSelectStyle.normal | 一级菜单样式 |
215216

216217

0 commit comments

Comments
 (0)