feat: expandable text component
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import 'package:cims_apps/application/component/expandable_widget/see_more_less_widget.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ExpandableWidget extends StatelessWidget {
|
||||
final String? content;
|
||||
final double? fontSize;
|
||||
final int maxLinesToShow;
|
||||
final Alignment? alignmentMore;
|
||||
final bool? hideTextMore;
|
||||
final bool? hideIconMore;
|
||||
|
||||
ExpandableWidget({
|
||||
super.key,
|
||||
required this.content,
|
||||
this.fontSize,
|
||||
this.maxLinesToShow = 1,
|
||||
this.alignmentMore,
|
||||
this.hideTextMore = false,
|
||||
this.hideIconMore = true,
|
||||
});
|
||||
|
||||
ValueNotifier<bool> expanded = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TextSpan textSpan = TextSpan(
|
||||
text: content ?? "",
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? 16.0,
|
||||
color: ColorPalette.slate400,
|
||||
),
|
||||
);
|
||||
|
||||
final TextPainter textPainter = TextPainter(
|
||||
text: textSpan,
|
||||
maxLines: expanded.value ? null : maxLinesToShow,
|
||||
textDirection: TextDirection.ltr,
|
||||
strutStyle: StrutStyle(
|
||||
fontSize: fontSize ?? 16.0,
|
||||
)
|
||||
);
|
||||
|
||||
textPainter.layout(maxWidth: SizeConfig.width);
|
||||
|
||||
final int numberOfLines = textPainter.computeLineMetrics().length;
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: expanded,
|
||||
builder: (context, values, _) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
if (!expanded.value && numberOfLines >= maxLinesToShow) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
content ?? "",
|
||||
maxLines: maxLinesToShow,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? 16.0,
|
||||
color: ColorPalette.slate400,
|
||||
),
|
||||
),
|
||||
/* See More :: type 1 - See More | 2 - See Less */
|
||||
SeeMoreLessWidget(
|
||||
textData: 'See More',
|
||||
type: 1,
|
||||
section: 1,
|
||||
onSeeMoreLessTap: () {
|
||||
expanded.value = true;
|
||||
},
|
||||
alignment: alignmentMore,
|
||||
hideIconMore: hideIconMore!,
|
||||
hideTextMore: hideTextMore!,
|
||||
),
|
||||
/* See More :: type 1 - See More | 2 - See Less */
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
content ?? "",
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? 16.0,
|
||||
color: ColorPalette.slate400,
|
||||
),
|
||||
),
|
||||
if (expanded.value && numberOfLines >= maxLinesToShow)
|
||||
/* See Less :: type 1 - See More | 2 - See Less */
|
||||
SeeMoreLessWidget(
|
||||
textData: 'See Less',
|
||||
type: 2,
|
||||
section: 1,
|
||||
onSeeMoreLessTap: () {
|
||||
expanded.value = false;
|
||||
},
|
||||
alignment: alignmentMore,
|
||||
hideIconMore: hideIconMore!,
|
||||
hideTextMore: hideTextMore!,
|
||||
),
|
||||
/* See Less :: type 1 - See More | 2 - See Less */
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SeeMoreLessWidget extends StatelessWidget {
|
||||
final String? textData;
|
||||
final int? type; /* type 1 - See More | 2 - See Less */
|
||||
final Function? onSeeMoreLessTap;
|
||||
final int?
|
||||
section; /* 1: About the course | 2 - Who can take up this course? | 3 - Mentors | 4 - Course Video Reviews */
|
||||
final Alignment? alignment;
|
||||
final bool hideTextMore;
|
||||
final bool hideIconMore;
|
||||
|
||||
const SeeMoreLessWidget({
|
||||
super.key,
|
||||
required this.textData,
|
||||
required this.type,
|
||||
required this.onSeeMoreLessTap,
|
||||
required this.section,
|
||||
required this.alignment,
|
||||
required this.hideTextMore,
|
||||
required this.hideIconMore,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: alignment ?? Alignment.centerLeft,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (onSeeMoreLessTap != null) {
|
||||
onSeeMoreLessTap!();
|
||||
}
|
||||
},
|
||||
child: Text.rich(
|
||||
softWrap: true,
|
||||
style: const TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
TextSpan(
|
||||
text: "",
|
||||
children: [
|
||||
if(!hideTextMore)
|
||||
TextSpan(
|
||||
text: textData,
|
||||
style: const TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
if(!hideTextMore && !hideIconMore)
|
||||
const WidgetSpan(
|
||||
child: SizedBox(
|
||||
width: 3.0,
|
||||
),
|
||||
),
|
||||
if(!hideIconMore)
|
||||
WidgetSpan(
|
||||
child: Icon(
|
||||
(type == 1)
|
||||
? Icons.keyboard_arrow_down
|
||||
: Icons.keyboard_arrow_up,
|
||||
color: ColorPalette.slate300,
|
||||
size: 28,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user