繁体   English   中英

如何更改 Flutter/Dart 中按钮的样式和位置?

[英]How to change the style and location of buttons in Flutter/Dart?

我有一个代码:

 // New Game route class NewGameRoute extends StatelessWidget { const NewGameRoute({key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'New Game', home: ListFromCSV1(), ); } } class ListFromCSV1 extends StatefulWidget { const ListFromCSV1({Key? key}): super(key: key); @override _ListFromCSVState1 createState() => _ListFromCSVState1(); } class _ListFromCSVState1 extends State<ListFromCSV1> { List<List<dynamic>> _listData = [ [""] ]; int _listCount = 0; bool _isFirstLoad = true; String assetPath = "files/main.jpg"; @override initState() { _loadCSV(); } // This function is only triggered at init, so we only load csv once void _loadCSV() async { String _rawData = await rootBundle.loadString("files/Text.csv"); _listData = const CsvToListConverter().convert(_rawData); } // This function is triggered when my button is pressed void _nextCSV() { setState(() { _listData = _listData; _listCount < _listData.length - 1? _isFirstLoad? _isFirstLoad = false: _listCount++: _listCount; // assetPath = _listData[_listCount][1] == ""? "files/main.jpg": _listData[_listCount][1]; assetPath = _listData[_listCount][1] == ""? assetPath: _listData[_listCount][1]; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('New Game'), ), body: Container( height: MediaQuery.of(context).size.height, decoration: BoxDecoration( image: DecorationImage( image: AssetImage(assetPath), fit: BoxFit.cover)), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ // const SizedBox(height: 30), ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('files/sheet.jpg'), fit: BoxFit.cover)), ), ), Text( _listData[_listCount][0] ), ], ), ), // const SizedBox(height: 30), ClipRRect( borderRadius: BorderRadius.circular(4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), // onPressed: () {}, onPressed: _nextCSV, child: const Text('OK'), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: () {}, // onPressed: _nextCSV, child: const Text('Hide'), ), ], ), ), ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: _nextCSV, child: const Text('Show'), ), ], ), ), // const SizedBox(height: 30), ], ), ), ); } }

它看起来像这样:

在此处输入图像描述

我需要它看起来像这样:

在此处输入图像描述

  1. 如何使 sheet.jpg 图像用作 OK 和 Hide 按钮的背景? 现在它是纯文本背景。

  2. 如何使 OK 和 Hide 按钮与 Hide 按钮具有相同的样式? 我了解我需要使用以下代码:

    边界半径:BorderRadius.circular(4),孩子:堆栈(孩子:[ Positioned.fill(孩子:容器(装饰:const BoxDecoration(渐变:LinearGradient(colors:[颜色(0xFF0D47A1),颜色(0xFF1976D2),颜色(0xFF42A5F5) , ], ), ), ), ),

但是我对小部件的孩子感到困惑,这就是为什么代码根本不想被执行。

这只是一个样式问题,所以不要看类和函数。 谢谢你。

Edit1.I 希望这些按钮具有来自 sheet.jpg 的背景,而屏幕的 rest 具有来自 main.jpg 的背景以及稍后取自 csv 文件的背景。

但如果我使用这段代码:

 class ListFromCSV extends StatefulWidget { const ListFromCSV({Key? key}): super(key: key); @override _ListFromCSVState createState() => _ListFromCSVState(); } class _ListFromCSVState extends State<ListFromCSV> { List<List<dynamic>> _listData = [ [""] ]; int _listCount = 0; bool _isFirstLoad = true; String assetPath = "assets/files/main.jpeg"; @override void initState() { _loadCSV(); } // This function is only triggered at init, so we only load csv once void _loadCSV() async { String rawData = await rootBundle.loadString("assets/files/Text.csv"); _listData = const CsvToListConverter().convert(rawData); assetPath = _listData[_listCount][1] == ""? "assets/files/main.jpeg": _listData[_listCount][1]; } // This function is triggered when my button is pressed void _nextCSV() { setState(() { _listData = _listData; _listCount < _listData.length - 1? _isFirstLoad? _isFirstLoad = false: _listCount++: _listCount; assetPath = _listData[_listCount][1] == ""? assetPath: _listData[_listCount][1]; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('New Game'), ), body: Container( height: MediaQuery.of(context).size.height, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/files/sheet.jpeg"), fit: BoxFit.cover)), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( decoration: BoxDecoration( border: Border.all(color: Colors.yellow, width: 3) ), child: Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage(assetPath), fit: BoxFit.cover)), ), ), Text(_listData[_listCount][0]), ], ), ), ClipRRect( borderRadius: BorderRadius.circular(4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( style: TextButton.styleFrom( side: BorderSide(color: Colors.yellow, width: 3), padding: const EdgeInsets.all(16.0), primary: Colors.white, backgroundColor: Colors.transparent, textStyle: const TextStyle(fontSize: 20), ), // onPressed: () {}, onPressed: _nextCSV, child: const Text('OK'), ), TextButton( style: TextButton.styleFrom( side: BorderSide(color: Colors.yellow, width: 3), padding: const EdgeInsets.all(16.0), primary: Colors.white, backgroundColor: Colors.transparent, textStyle: const TextStyle(fontSize: 20), ), onPressed: () {}, // onPressed: _nextCSV, child: const Text('Hide'), ), ], ), ), ], ), ), // your other widgets ], ), ), ); } }

它看起来像这样:

在此处输入图像描述

我想要这个:

在此处输入图像描述

我知道我必须用 sheet.jpg 将现有按钮包装在容器中。 但是我一直丢失标点符号,这使得代码根本不想运行。

编辑2。 如何使 sheet.jpg 不仅作为 OK 和 Hide 按钮的背景,而且还作为它们之间的空间? 我示意性地描述了这一点:

在此处输入图像描述

我试图将这些按钮“提升”到一个容器中。 但是当我这样做时:

 child: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('files/sheet.jpg'), fit: BoxFit.cover)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ImageButton(label: 'OK', onButtonTap: _nextCSV), ImageButton(label: 'Hide', onButtonTap: () {}), ], ), ),

我收到一个错误:“A RenderFlex 在右侧溢出了 46 个像素”

希望这对您有所帮助。 我创建了一个名为 ImageButton 的类似按钮的小部件。

 class ListFromCSV extends StatefulWidget { const ListFromCSV({Key? key}): super(key: key); @override _ListFromCSVState createState() => _ListFromCSVState(); } class _ListFromCSVState extends State<ListFromCSV> { List<List<dynamic>> _listData = [ [""] ]; int _listCount = 0; bool _isFirstLoad = true; String assetPath = "assets/files/main.jpeg"; @override void initState() { _loadCSV(); } // This function is only triggered at init, so we only load csv once void _loadCSV() async { String rawData = await rootBundle.loadString("assets/files/Text.csv"); _listData = const CsvToListConverter().convert(rawData); assetPath = _listData[_listCount][1] == ""? "assets/files/main.jpeg": _listData[_listCount][1]; } // This function is triggered when my button is pressed void _nextCSV() { setState(() { _listData = _listData; _listCount < _listData.length - 1? _isFirstLoad? _isFirstLoad = false: _listCount++: _listCount; assetPath = _listData[_listCount][1] == ""? assetPath: _listData[_listCount][1]; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('New Game'), ), body: Container( height: MediaQuery.of(context).size.height, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/files/sheet.jpeg"), fit: BoxFit.cover)), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage(assetPath), fit: BoxFit.cover)), ), ), Text(_listData[_listCount][0]), ], ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ImageButton(label: 'OK', onButtonTap: _nextCSV), ImageButton(label: 'Hide', onButtonTap: () {}), ], ), ], ), // your other widgets ], ), ), ); } } class ImageButton extends StatelessWidget { const ImageButton({Key? key, required this.label, required this.onButtonTap}): super(key: key); final String label; final Function onButtonTap; @override Widget build(BuildContext context) { return InkWell( onTap: () => onButtonTap(), child: Container( // customize you button shape and size and design margin: const EdgeInsets.all(8), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 32), decoration: const BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(2)), image: DecorationImage( image: AssetImage("assets/files/main.jpeg"), // you can also pass the image dynamically with variable created for the widget. fit: BoxFit.cover)), child: Center( child: Text( label, style: const TextStyle( color: Colors.white, // you can get dominant colour on image and change the text color accordingly or apply shadows to the text fontWeight: FontWeight.w500, fontSize: 16), ), ), ), ); } }

您还可以创建一个新的 dart 文件并将 ImageButton 小部件代码移动到该文件并导入并在您想要的任何地方使用它。 它将减少代码行数并增加代码的可重用性。

如果我理解正确,您可以将图像添加到您的代码中,然后以这种方式将其用于您的目的:请参阅此处 flutter 文档

对于第二个问题,为了添加边框,您需要使用容器以及容器内部的盒子装饰和其他东西,但这取决于您想要的结果,请查看此处Stack 指

您可以像这样将按钮的背景指定为透明。

 class ListFromCSV extends StatefulWidget { const ListFromCSV({Key? key}): super(key: key); @override _ListFromCSVState createState() => _ListFromCSVState(); } class _ListFromCSVState extends State<ListFromCSV> { List<List<dynamic>> _listData = [ [""] ]; int _listCount = 0; bool _isFirstLoad = true; String assetPath = "assets/files/main.jpeg"; @override void initState() { _loadCSV(); } // This function is only triggered at init, so we only load csv once void _loadCSV() async { String rawData = await rootBundle.loadString("assets/files/Text.csv"); _listData = const CsvToListConverter().convert(rawData); assetPath = _listData[_listCount][1] == ""? "assets/files/main.jpeg": _listData[_listCount][1]; } // This function is triggered when my button is pressed void _nextCSV() { setState(() { _listData = _listData; _listCount < _listData.length - 1? _isFirstLoad? _isFirstLoad = false: _listCount++: _listCount; assetPath = _listData[_listCount][1] == ""? assetPath: _listData[_listCount][1]; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('New Game'), ), body: Container( height: MediaQuery.of(context).size.height, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/files/sheet.jpeg"), fit: BoxFit.cover)), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( decoration: BoxDecoration( border: Border.all(color: Colors.yellow, width: 3) ), child: Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage(assetPath), fit: BoxFit.cover)), ), ), Text(_listData[_listCount][0]), ], ), ), ClipRRect( borderRadius: BorderRadius.circular(4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( style: TextButton.styleFrom( side: BorderSide(color: Colors.yellow, width: 3), padding: const EdgeInsets.all(16.0), primary: Colors.white, backgroundColor: Colors.transparent, textStyle: const TextStyle(fontSize: 20), ), // onPressed: () {}, onPressed: _nextCSV, child: const Text('OK'), ), TextButton( style: TextButton.styleFrom( side: BorderSide(color: Colors.yellow, width: 3), padding: const EdgeInsets.all(16.0), primary: Colors.white, backgroundColor: Colors.transparent, textStyle: const TextStyle(fontSize: 20), ), onPressed: () {}, // onPressed: _nextCSV, child: const Text('Hide'), ), ], ), ), ], ), ), // your other widgets ], ), ), ); } }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM