简体   繁体   中英

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

I have a code:

 // 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), ], ), ), ); } }

It looks like this:

在此处输入图像描述

I need it to look like this:

在此处输入图像描述

  1. How to make the sheet.jpg image used as a background for the OK and Hide buttons? Right now it's a text-only background.

  2. How can I make the OK and Hide buttons have the same style as the Hide button? I understand that I need to use the code:

    borderRadius: BorderRadius.circular(4), child: Stack( children: [ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ),

But I am confused about the children of widgets, which is why the code does not want to be executed at all.

This is just a styling issue, so don't look at classes and functions. Thank you.

Edit1.I want these buttons to have a background from sheet.jpg, while the rest of the screen has a background from main.jpg and what is taken from the csv file later.

But if I use this code:

 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 ], ), ), ); } }

It looks like this:

在此处输入图像描述

And I want this:

在此处输入图像描述

I understand that I have to wrap the existing buttons in a container with sheet.jpg. But I keep losing punctuation marks, which makes the code not want to run at all.

Edit2. How can I make sheet.jpg the background not only for the OK and Hide buttons, but also for the space between them? I schematically depicted this:

在此处输入图像描述

I was trying to just "raise" those buttons into a container. But when I do like this:

 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: () {}), ], ), ),

I get an error: "A RenderFlex overflowed by 46 pixels on the right"

Hope this helps you. I created a button-like widget named 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), ), ), ), ); } }

You can also create a new dart file and move the ImageButton widget code to that file and import and use it anywhere you want. It will reduce the number of lines of code and also increases code reusability.

If I understand correctly you can add an image to your code and later use it for your purpose in this way: See here flutter docs

For the second problem in order to add a border you need to use a container and inside the container box decoration and other stuff, but it depends on the result that you want, checks here Stack refers

You can specify the background as transparent for your buttons like this.

 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 ], ), ), ); } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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