我刚接触Flutter我想为我的投资组合网站创建一个带有标签的文件夹效果,你可以点击标签来改变文件夹中心显示的内容。目前,按钮是作为行小部件的子项动态生成的。问题是,在较小的屏幕宽度下,文本要么太小,要么被完全切断。我甚至试图找出如何做一种多-行排但放弃了。
我最理想的情况是,按钮的 Package 方式是,任何会使父标签过长的按钮都放在单独的行中。然而,我愿意接受任何允许所有标签都适合屏幕而不会使按钮中的文本超级缩小的解决方案。
正如你所看到的,我目前的解决方案是在较小的屏幕宽度上缩小文本,这样它至少是可见的。我猜我要么重新设计实现效果的方式,或者有一些我不知道的相对简单的解决方案。我还尝试替换Row小部件,该小部件将FolderButtons Package 为Wrap,而不进行其他修改,这只会导致文本消失。
注意:它当前实现的方式假设并依赖于文件夹是一个完美的正方形。
下面分别是Folder、FolderButton和ScaleSize类:
class Folder extends StatefulWidget {
const Folder({super.key});
static Column? getStaticPages(String page, BuildContext context) {
Map<String, Column> pages = {
"Welcome": Column(
children: [
Text(
'Welcome',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Web Dev's Handbook": Column(
children: [
Text(
"Web Dev's Handbook",
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
),
TextButton(
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Contents()))
},
child: const Text("Go"))
],
),
"Interactive Resume": Column(
children: [
Text(
'Interactive Resume',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Settings": Column(
children: [
Text(
'Settings',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Credits": Column(
children: [
Text(
'Credits',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
};
return pages[page];
}
static List<Map<String, dynamic>> staticTabs = [
{"title": "Welcome"},
{"title": "Web Dev's Handbook"},
{"title": "Interactive Resume"},
{"title": "Settings"},
{"title": "Credits"},
];
static List<FolderButton> generateTabs(int selectedTab, Function setTab) {
List<FolderButton> newTabs = [];
for (int x = 0; x < staticTabs.length; x++) {
bool selected;
if (selectedTab == x) {
selected = true;
} else {
selected = false;
}
newTabs.add(FolderButton(
title: staticTabs[x]["title"],
count: x,
selected: selected,
setTab: setTab));
}
return newTabs;
}
@override
State<Folder> createState() => _FolderState();
}
class _FolderState extends State<Folder> {
int _selectedTab = 0;
void _setTab(int count) {
setState(() {
_selectedTab = count;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.only(left: 1, right: 1, top: 20),
child: SizedBox(
height: 750,
width: 750,
child: Column(
children: [
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 7.0),
child: Row(
children: Folder.generateTabs(_selectedTab, _setTab),
),
),
),
Flexible(
flex: 15,
fit: FlexFit.tight,
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
width: 800,
decoration:
const BoxDecoration(color: Colors.deepPurple),
child: Folder.getStaticPages(
Folder.staticTabs[_selectedTab]["title"], context)),
),
),
),
],
),
),
),
);
}
}
class FolderButton extends StatefulWidget {
const FolderButton(
{super.key,
required this.title,
required this.count,
this.selected = false,
required this.setTab});
final String title;
final int count;
final bool selected;
final Function setTab;
static final theme = <String, dynamic>{
"button": <String, dynamic>{
"picked": <bool, ButtonStyle>{
true: TextButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5), topRight: Radius.circular(5)),
side: BorderSide(
color: Colors.deepPurpleAccent,
strokeAlign: StrokeAlign.outside))),
false: TextButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5), topRight: Radius.circular(5)),
side: BorderSide(
color: Colors.deepPurple, strokeAlign: StrokeAlign.outside)),
),
}
},
// TODO Make it so I don't need to do it like this
"padding": <bool, dynamic>{
true: const EdgeInsets.only(top: 3, left: 3, right: 3),
false: const EdgeInsets.only(top: 3, left: 3, right: 3)
}
};
static Color? getTabShading(selected) {
if (selected) {
return Colors.deepPurpleAccent;
}
return Colors.deepPurple;
}
static EdgeInsetsGeometry getTabPadding(selected) {
return theme["padding"][selected];
}
@override
State<FolderButton> createState() => _FolderButtonState();
}
class _FolderButtonState extends State<FolderButton> {
void changeSelected() {}
@override
Widget build(BuildContext context) {
return Flexible(
child: Container(
height: 100,
// Button Container
decoration: BoxDecoration(
// Container Decorations
color: FolderButton.getTabShading(widget.selected),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
)),
// Button Padding
child: Padding(
padding: FolderButton.getTabPadding(widget.selected),
// Button
child: TextButton(
onPressed: () {
widget.setTab(widget.count);
},
// Style of button itself
style: FolderButton.theme["button"]?["picked"][widget.selected],
child: Text(
textAlign: TextAlign.center,
textScaleFactor: ScaleSize.textScaleFactor(context,
maxTextScaleFactor: 1.5),
// Text of the button
widget.title,
style: TextStyle(
color: Colors.deepPurpleAccent.shade100,
fontSize: 10,
height: 1))),
),
),
);
}
}
class ScaleSize {
static double textScaleFactor(BuildContext context,
{double maxTextScaleFactor = 2}) {
final width = MediaQuery.of(context).size.width;
double val = (width / 1400) * maxTextScaleFactor;
return max(1, min(val, maxTextScaleFactor));
}
}
任何一般的Flutter技巧、窍门、惯例和/或全面的好主意都是值得赞赏的。
3条答案
按热度按时间8ulbf1ek1#
也许Wrap小部件就是你所需要的,它的工作原理就像
Row
一样,直到你达到水平大小的极限,然后把下一个小部件放在前一个小部件下面的新“行”中。c9x0cxw02#
尝试使用Expanded作为Row/Column的子元素,或者你需要的任何东西。我在flutter页面给你一个简短的描述。我认为对于没有特定宽度的文本来说,它会很好。
https://api.flutter.dev/flutter/widgets/Expanded-class.html
zbdgwd5y3#
答案很简单,就是用Wrap作为Buttons的父级来重新构建组件,因为它会将溢出的子级 Package 在其余子级的下面。我还将确保在使用responsive framework包时,在响应式布局设计方面保持更多的深谋远虑。