介绍
可以快速构建一个标题组件 可以选择是否展示装饰
![](https://img.haomeiwen.com/i27902463/8a7a14c0305976ab.png)
代码演示
基础用法
HcTitle(
title: "这里是标题",
),
带副标题
HcTitle(
title: "这里是标题",
subtitle: "这里是副标题",
),
副标题首字母大写
HcTitle(
title: "猜你喜欢",
subTitleCapitalize: true,
subtitle: 'guess you like it',
),
带点组件
HcTitle(
icon: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: Colors.pink,
borderRadius: BorderRadius.all(Radius.circular(5))),
),
title: "猜你喜欢",
subTitleCapitalize: true,
subtitle: 'guess you like it',
),
副标题和标题堆叠
HcTitle(
icon: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: Colors.pink,
borderRadius: BorderRadius.all(Radius.circular(5))),
),
title: "猜你喜欢",
subTitleCapitalize: true,
subtitle: 'guess you like it',
isTopSubtitle: true,
),
右上角带点的标题
HcTitle.topDot(
title: "玩点花的?",
isTopSubtitle: true,
subTitleCapitalize: true,
subtitle: "englist subtitle",
),
带下划线的标题
HcTitle.underLine(
title: "其实我也行,顺便换个颜色",
isTopSubtitle: true,
subTitleCapitalize: true,
color: Colors.pinkAccent,
subtitle: "englist subtitle",
),
只有副标题的标题
HcTitle(
subtitle: "什么居然没有标题 ",
)
修改标题的大小
HcTitle.dot(
title: "好大的标题",
titleStyle: TextStyle(fontSize: 30),
),
API
props
参数 | 说明 | 类型 | 默认值 | 是否必填 |
---|---|---|---|---|
title | 标题 | String? | - | false |
subtitle | 副标题 | String? | - | false |
titleStyle | 标题文字样式 | TextStyle | - | false |
icon | 左侧Icon | Widget | - | false |
more | 右侧Icon | Widget | - | false |
subtitleStyle | 副标题文字样式 | TextStyle | - | false |
alignment | 对齐方式 | MainAxisAlignment | - | false |
padding | 内边距 | EdgeInsets? | EdgeInsets.all(18) | false |
color | 组件其他的颜色 | Color | - | false |
subTitleCapitalize | 副标题是否首字母大写 | bool | true | false |
isTopSubtitle | 副标题是否展示在标题上方 | bool | false | false |
reverse | 是否翻转 | bool | false | false |
项目源码
enum HcTitleType { normal, topDot, underLine }
class HcTitle extends StatelessWidget {
//标题
final String? title;
//标题的 样式
final TextStyle titleStyle;
//副标题
final String subtitle;
//副标题的样式
final TextStyle subtitleStyle;
//左侧Icon
final Widget? icon;
//间距
final EdgeInsets? padding;
//副标题是否首字母大写
final bool subTitleCapitalize;
//主轴的对齐方式
final MainAxisAlignment alignment;
//是否翻转
final bool reverse;
//右侧更多的 组件
final Widget? more;
//副标题是否顶端显示
final bool isTopSubtitle;
//标题的类型
final HcTitleType titleType;
//组件的主题色
final Color color;
const HcTitle(
{Key? key,
this.title,
this.subtitle = "",
this.icon,
this.subTitleCapitalize = true,
this.padding,
this.alignment = MainAxisAlignment.start,
this.more,
this.titleStyle =
const TextStyle(fontSize: HcFont.f18, fontWeight: FontWeight.bold),
this.subtitleStyle = const TextStyle(
fontSize: HcFont.f14,
fontWeight: FontWeight.normal,
color: HcColor.defaultSubtitleColor),
this.isTopSubtitle = false,
this.color = Colors.blue,
this.reverse = false})
:titleType = HcTitleType.normal, super(key: key);
HcTitle.dot(
{this.title,
this.subtitle = "",
this.padding,
this.subTitleCapitalize = true,
super.key,
this.reverse = false,
this.alignment = MainAxisAlignment.start,
this.more,
this.titleStyle =
const TextStyle(fontSize: HcFont.f18, fontWeight: FontWeight.bold),
this.subtitleStyle = const TextStyle(
fontSize: HcFont.f14,
fontWeight: FontWeight.normal,
color: HcColor.defaultSubtitleColor),
this.isTopSubtitle = false,
this.color = Colors.blue})
: icon = Container(
height: 18,
width: 5,
decoration: BoxDecoration(
color: Colors.blue, borderRadius: BorderRadius.circular(5)),
),
titleType = HcTitleType.normal;
const HcTitle.underLine(
{this.title,
this.subtitle = "",
this.padding,
this.subTitleCapitalize = true,
super.key,
this.reverse = false,
this.alignment = MainAxisAlignment.start,
this.more,
this.titleStyle =
const TextStyle(fontSize: HcFont.f18, fontWeight: FontWeight.bold),
this.subtitleStyle = const TextStyle(
fontSize: HcFont.f14,
fontWeight: FontWeight.normal,
color: HcColor.defaultSubtitleColor),
this.isTopSubtitle = false,
this.color = Colors.blue})
: icon = null,
titleType = HcTitleType.underLine;
const HcTitle.topDot(
{this.title,
this.subtitle = "",
this.padding,
this.subTitleCapitalize = true,
super.key,
this.reverse = false,
this.alignment = MainAxisAlignment.start,
this.more,
this.titleStyle =
const TextStyle(fontSize: HcFont.f18, fontWeight: FontWeight.bold),
this.subtitleStyle = const TextStyle(
fontSize: HcFont.f14,
fontWeight: FontWeight.normal,
color: HcColor.defaultSubtitleColor),
this.isTopSubtitle = false,
this.color = Colors.blue})
: icon = const SizedBox(
height: 5,
width: 5,
),
titleType = HcTitleType.topDot;
@override
Widget build(BuildContext context) {
MainAxisAlignment _alignment = alignment;
if (alignment.index < 2 && reverse) {
if (alignment == MainAxisAlignment.start) {
_alignment = MainAxisAlignment.end;
} else {
_alignment = MainAxisAlignment.start;
}
}
//副标题要不要首字母大写
String finalSubtitle =
subTitleCapitalize ? HcStringUtil.capitalizeStr(subtitle) : subtitle;
//文字宽度
double textWidth = 60;
//计算表标题大小
Size titleSize = HcStringUtil.boundingTextSize(title ?? '', titleStyle);
//计算副标题大小
Size subtitleSize =
HcStringUtil.boundingTextSize(finalSubtitle, subtitleStyle);
textWidth = (subtitleSize.width + titleSize.width + 5) * 0.68;
return Padding(
padding: padding ?? const EdgeInsets.all(HcSize.defaultPadding),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
textDirection: reverse ? TextDirection.rtl : TextDirection.ltr,
mainAxisAlignment: _alignment,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (icon != null)
Padding(
padding: const EdgeInsets.only(right: 5),
child: icon!,
),
if (title != null)
_buildTitleWidget(subtitleSize, titleSize, finalSubtitle,
textWidth, _alignment)
else
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
finalSubtitle,
style: subtitleStyle,
),
),
],
),
),
if (more != null) more!
],
));
}
Widget _buildTitleWidget(Size subtitleSize, Size titleSize,
String finalSubtitle, double textWidth, MainAxisAlignment axisAlignment) {
return Stack(
clipBehavior: Clip.none,
children: [
if (titleType == HcTitleType.topDot)
Positioned(
left: -0.5 * 18,
top: -0.3 * 18,
child: Container(
decoration: BoxDecoration(
color: color, borderRadius: BorderRadius.circular(9)),
width: 18,
height: 18,
)),
if (isTopSubtitle)
Positioned(
top: titleSize.height - subtitleSize.height * 2,
right: 0,
child: SizedBox(
width: titleSize.width,
child: Text(
finalSubtitle,
textAlign: TextAlign.end,
maxLines: 2,
style: subtitleStyle.copyWith(color: color.withOpacity(0.3)),
),
),
),
if (titleType == HcTitleType.underLine)
Positioned(
bottom: 0,
right: axisAlignment == MainAxisAlignment.end ? 0 : null,
left: axisAlignment != MainAxisAlignment.end ? 0 : null,
child: Container(
width: isTopSubtitle || subtitle.isEmpty
? titleSize.width
: textWidth,
color: color,
height: titleSize.height / 2,
)),
Row(
textDirection: reverse ? TextDirection.rtl : TextDirection.ltr,
children: [
Text(
title!,
style: titleStyle,
),
if (!isTopSubtitle)
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
finalSubtitle,
style: subtitleStyle,
),
),
],
),
],
);
}
}
计算文字大小
static Size boundingTextSize(String text, TextStyle style,
{int maxLines = 2 ^ 31,
double maxWidth = double.infinity,
textDirection = TextDirection.ltr}) {
if (text.isEmpty) {
return Size.zero;
}
final TextPainter textPainter = TextPainter(
textDirection: textDirection,
text: TextSpan(text: text, style: style),
maxLines: maxLines)
..layout(maxWidth: maxWidth);
return textPainter.size;
}
capitalizeStr 首字母大写
static String capitalizeStr(String? str) {
if (str == null || str.isEmpty) {
return "";
}
List<String> splitList = str.trim().split(" ");
for (int i = 0; i < splitList.length; i++) {
String str = splitList[i];
splitList[i] = "${str[0].toUpperCase()}${str.substring(1)}";
}
return splitList.join(" ");
}
网友评论