Related
I am trying to reproduce Apple memo recorder button. Right now, I am trying to reduce the size of Stop Button. First, I have tried without the SizedBox and then with. I am getting the same result.Even if embedded in a SizedBox, I can not achieve what I want.
Please, can somebody tells me what I am missing? Thank you.
Container _RecordButton(){
return Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false?
_createRecordElevatedButton() : _createStopElevatedButton()),);
}
ElevatedButton _createRecordElevatedButton(
{IconData icon, Function onPressFunc}) {
return ElevatedButton(
onPressed: () {
if (isRecording = false){
setState(() {
isRecording = true;
});
}},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(Colors.red), // <-- Button color
/*overlayColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.pressed))
return Colors.red; // <-- Splash color
}*/));
}
SizedBox _createStopElevatedButton(
{IconData icon, Function onPressFunc}) {
return SizedBox(
height: 14,
width: 14,
child: ElevatedButton(
onPressed: () {
/* if (isRecording = true){
setState(() {
isRecording = false;
});
}*/
},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(10,10)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
side: BorderSide(color: Colors.red)
)
),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(Colors.red), // <-- Button color
/*overlayColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.pressed))
return Colors.red; // <-- Splash color
}*/)),
);
}
Wrap your elevated button with container and give height and width accordingly.
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.grey)),
child: Container(
padding: EdgeInsets.all(7),
width: 50.0,
height: 50.0,
child: ElevatedButton(
onPressed: () {},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(10, 10)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(color: Colors.red))),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(Colors.red),
),
child: null,
)),
),
Please replace your code with below code:
class MyElevatedButton extends StatefulWidget {
const MyElevatedButton({Key? key}) : super(key: key);
#override
_MyElevatedButtonState createState() => _MyElevatedButtonState();
}
class _MyElevatedButtonState extends State<MyElevatedButton> {
bool isRecording=false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false
? _createRecordElevatedButton(icon: Icons.add)
: _createStopElevatedButton(icon: Icons.minimize,onPressFunc: (){})),
),
],
),
),
),
);
}
/* Container _RecordButton() {
return Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false
? _createRecordElevatedButton()
: _createStopElevatedButton()),
);
}*/
Widget _createRecordElevatedButton(
// ignore: unused_element
{required IconData icon,/* VoidCallback onPressFunc*/}) {
return ElevatedButton(
onPressed: () {
if (isRecording = false) {
setState(() {
isRecording = true;
});
}
},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor:
MaterialStateProperty.all(Colors.red), // <-- Button color
/*overlayColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.pressed))
return Colors.red; // <-- Splash color
}*/
), child: Text('play'),);
}
// ignore: unused_element
SizedBox _createStopElevatedButton({required IconData icon, required VoidCallback onPressFunc}) {
return SizedBox(
height: 14,
width: 14,
child: ElevatedButton(
onPressed: () {
/* if (isRecording = true){
setState(() {
isRecording = false;
});
}*/
},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(10, 10)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
side: BorderSide(color: Colors.red))),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor:
MaterialStateProperty.all(Colors.red), // <-- Button color
/*overlayColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.pressed))
return Colors.red; // <-- Splash color
}*/
), child: Text('onPressed'),),
);
}
}
Try this code :
MyElevatedButton
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class MyElevatedButton extends StatefulWidget {
const MyElevatedButton({Key? key}) : super(key: key);
#override
_MyElevatedButtonState createState() => _MyElevatedButtonState();
}
class _MyElevatedButtonState extends State<MyElevatedButton> {
bool isRecording=false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false
? _createRecordElevatedButton() /*_createRecordElevatedButton(icon: Icons.add,)*/
: _createStopElevatedButton()),
),
],
),
),
),
);
}
Widget _createRecordElevatedButton(){
return GestureDetector(
onTap: (){
setState(() {
isRecording = true;
});
print('clickOnPressedButton');
},
child: Container(
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(child: Text('Play',style: TextStyle(fontSize: 12,color: Colors.white),)),
),
);
}
Widget _createStopElevatedButton(){
return GestureDetector(
onTap: (){
setState(() {
isRecording = false;
});
print('clickOnPressedButton');
},
child: Container(
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(child: Text('Pause',style: TextStyle(fontSize: 12,color: Colors.white),)),
),
);
}
}
How to create appbar like this? In flutter default search button I will have to click on the SearchIcon later it will give the search tab but i need it directly like the image posted and also along with the seachbar notification button and navigation drawer.
Edit:
Below is the final working code
with the help of Ravindra S. Patil
import 'package:flutter/material.dart';
import '../widget/app_drawer.dart';
import '../widget/bottom_navigation.dart';
import 'package:badges/badges.dart';
// ignore: use_key_in_widget_constructors
class HomeScreen extends StatefulWidget {
static String routeName = '/home_screen';
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigation(),
endDrawerEnableOpenDragGesture: false,
drawer: AppDrawer(),
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
toolbarHeight: 80,
title: Container(
margin: const EdgeInsets.only(
top: 20,
bottom: 20,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(
10,
),
),
child: TextFormField(
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
),
borderRadius: BorderRadius.all(
Radius.circular(
10.0,
),
),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
),
borderRadius: BorderRadius.all(
Radius.circular(
10.0,
),
),
),
hintText: 'Search petients,transcript,contacts',
prefixIcon: IconButton(
icon: Icon(Icons.menu),
onPressed: () => {
if (_scaffoldKey.currentState.isDrawerOpen)
{_scaffoldKey.currentState.openEndDrawer()}
else
{_scaffoldKey.currentState.openDrawer()}
},
),
suffixIcon: Stack(
children: [
Container(
padding: const EdgeInsets.only(
top: 8,
),
child: const Icon(
Icons.notifications,
size: 30,
),
),
Positioned(
right: 15,
child: Badge(
shape: BadgeShape.circle,
badgeColor: Colors.red,
borderRadius: BorderRadius.circular(
5,
),
badgeContent: const Text(
'2',
style: TextStyle(
color: Colors.white,
),
),
),
),
],
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(
10.0,
),
),
),
),
),
),
),
);
}
}
Try below code hope its help to you. Used badges package here for display notification.
Refer TextFormField here
Refer InputDecoration here
Scaffold(
appBar: AppBar(
toolbarHeight: 80,
title: Container(
margin: EdgeInsets.only(
top: 20,
bottom: 20,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(
10,
),
),
child: TextFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
),
borderRadius: const BorderRadius.all(
const Radius.circular(
10.0,
),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
),
borderRadius: const BorderRadius.all(
const Radius.circular(
10.0,
),
),
),
hintText: 'Search petients,transcript,contacts',
prefixIcon: Icon(
Icons.menu,
),
suffixIcon: Stack(
children: [
Container(
padding: EdgeInsets.only(
top: 8,
),
child: Icon(
Icons.notifications,
size: 30,
),
),
Positioned(
right: 15,
child: Badge(
shape: BadgeShape.circle,
badgeColor: Colors.red,
borderRadius: BorderRadius.circular(
5,
),
badgeContent: Text(
'2',
style: TextStyle(
color: Colors.white,
),
),
),
),
],
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(
10.0,
),
),
),
),
),
),
),
);
Your result screen->
import 'package:flutter/material.dart';
class SearchList extends StatefulWidget {
SearchList({ Key key }) : super(key: key);
#override
_SearchListState createState() => new _SearchListState();
}
class _SearchListState extends State<SearchList>
{
Widget appBarTitle = new Text("Search Sample", style: new TextStyle(color: Colors.white),);
Icon actionIcon = new Icon(Icons.search, color: Colors.white,);
final key = new GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = new TextEditingController();
List<String> _list;
bool _IsSearching;
String _searchText = "";
_SearchListState() {
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
});
}
else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
});
}
});
}
#override
void initState() {
super.initState();
_IsSearching = false;
init();
}
void init() {
_list = List();
_list.add("Google");
_list.add("IOS");
_list.add("Andorid");
_list.add("Dart");
_list.add("Flutter");
_list.add("Python");
_list.add("React");
_list.add("Xamarin");
_list.add("Kotlin");
_list.add("Java");
_list.add("RxAndroid");
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new ListView(
padding: new EdgeInsets.symmetric(vertical: 8.0),
children: _IsSearching ? _buildSearchList() : _buildList(),
),
);
}
List<ChildItem> _buildList() {
return _list.map((contact) => new ChildItem(contact)).toList();
}
List<ChildItem> _buildSearchList() {
if (_searchText.isEmpty) {
return _list.map((contact) => new ChildItem(contact))
.toList();
}
else {
List<String> _searchList = List();
for (int i = 0; i < _list.length; i++) {
String name = _list.elementAt(i);
if (name.toLowerCase().contains(_searchText.toLowerCase())) {
_searchList.add(name);
}
}
return _searchList.map((contact) => new ChildItem(contact))
.toList();
}
}
Widget buildBar(BuildContext context) {
return new AppBar(
centerTitle: true,
title: appBarTitle,
actions: <Widget>[
new IconButton(icon: actionIcon, onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(Icons.close, color: Colors.white,);
this.appBarTitle = new TextField(
controller: _searchQuery,
style: new TextStyle(
color: Colors.white,
),
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: new TextStyle(color: Colors.white)
),
);
_handleSearchStart();
}
else {
_handleSearchEnd();
}
});
},),
]
);
}
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
this.actionIcon = new Icon(Icons.search, color: Colors.white,);
this.appBarTitle =
new Text("Search Sample", style: new TextStyle(color: Colors.white),);
_IsSearching = false;
_searchQuery.clear();
});
}
}
class ChildItem extends StatelessWidget {
final String name;
ChildItem(this.name);
#override
Widget build(BuildContext context) {
return new ListTile(title: new Text(this.name));
}
}
I'm developing an application on flutter and I'm having a problem with the position of the ElevatedButton. When the Validator returns the error message below the TextFormField, the widget expands downward and the position of the add button changes. I would like to keep the add button pinned to the same position as the beginning of the app
button in normal position
Button out of its original position after returning the validator
My code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Lista de Compras"),
backgroundColor: Colors.green,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(15, 10, 5, 10),
child: Form(
key: _formKey,
child: Row(
children: <Widget>[
Theme(
data: ThemeData(
primaryColor: Colors.green,
hintColor: Colors.green),
child: Expanded(
child: TextFormField(
controller: _controlador,
validator: (value) {
if (value.isEmpty) {
return "Insira um item";
}
return null;
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green),
borderRadius:
BorderRadius.circular(100)),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(100)),
labelText: "Novo item",
hintText: "Insira um item",
hintStyle: TextStyle(color: Colors.grey),
labelStyle:
TextStyle(color: Colors.green),
suffixIcon: IconButton(
onPressed: () => _controlador.clear(),
icon: Icon(Icons.clear,
color: Colors.grey),
))))),
Padding(padding: EdgeInsets.only(right: 6)),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green,
shape: CircleBorder(),
padding: EdgeInsets.all(12)),
child: Icon(Icons.add, color: Colors.white),
onPressed: () {
if (_formKey.currentState.validate()) {
_addCompras();
}
}),
],
),
)),
This is an expected behaviour, when TextFormField show an errorText this will append a text below the TextFormField adding extra height for about 22. Check working example below :
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
children: [
MeasureSize(
child: FormWidget(),
onChange: (size) {
print(size);
},
),
MeasureSize(
child: FormWidget(hideError: false),
onChange: (size) {
print(size);
},
),
FormWidget(
hideError: false,
addPaddingToTrailingButton: true,
),
],
),
),
);
}
}
class FormWidget extends StatelessWidget {
final bool hideError;
final bool addPaddingToTrailingButton;
FormWidget({
this.hideError = true,
this.addPaddingToTrailingButton = false,
});
#override
Widget build(BuildContext context) {
Widget trailingButton = ElevatedButton(
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(12),
),
child: Icon(Icons.add),
onPressed: () {},
);
if (addPaddingToTrailingButton) {
trailingButton = Padding(
padding: const EdgeInsets.only(bottom: 22),
child: trailingButton,
);
}
return Container(
color: Colors.grey[300],
margin: const EdgeInsets.symmetric(vertical: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 8),
Expanded(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100),
),
labelText: "Label text field",
hintText: "Hint text field",
errorText: hideError ? null : 'Error text shown',
suffixIcon: IconButton(
onPressed: () {},
icon: Icon(Icons.clear),
),
),
),
),
SizedBox(width: 8),
trailingButton,
],
),
);
}
}
typedef void OnWidgetSizeChange(Size size);
class MeasureSizeRenderObject extends RenderProxyBox {
Size oldSize;
final OnWidgetSizeChange onChange;
MeasureSizeRenderObject(this.onChange);
#override
void performLayout() {
super.performLayout();
Size newSize = child.size;
if (oldSize == newSize) return;
oldSize = newSize;
WidgetsBinding.instance.addPostFrameCallback((_) {
onChange(newSize);
});
}
}
class MeasureSize extends SingleChildRenderObjectWidget {
final OnWidgetSizeChange onChange;
const MeasureSize({
Key key,
#required this.onChange,
#required Widget child,
}) : super(key: key, child: child);
#override
RenderObject createRenderObject(BuildContext context) {
return MeasureSizeRenderObject(onChange);
}
}
I have adding a background so it will show the height difference :
TextField without errorText shown.
TextField with errorText shown.
TextField with errorText shown, with additional padding on icon button.
Check dartpad here
the answer by Allan above is very great.
But if you are facing issues learning that do it this way:
Add Elevated button to Column and add SizedBox with height 22 as its children. Here the height is calculated as (Height of TextFormField with error - of TextFormField without error) using flutter inspector.
Column(
children: [
ElevatedButton(...),
SizedBox(
height: 22,
),
],
),
Now add helperText: ' ', in TextFormField InputDecoration:
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return "Insira um item";
}
return null;
},
decoration: InputDecoration(
helperText: ' ',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.green),
borderRadius: BorderRadius.circular(100)),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100)),
labelText: "Novo item",
hintText: "Insira um item",
hintStyle: TextStyle(color: Colors.grey),
labelStyle: TextStyle(color: Colors.green),
),
),
Here you can see the dartpad for full code.
This will get you this result:
Here is my code
TextField(
controller: commentController,
maxLines: 3,
selectionHeightStyle: BoxHeightStyle.tight,
decoration: new InputDecoration(
hintText: 'Write a Comment',
hintStyle: new TextStyle(
color: Colors.grey,
),
prefixIcon: InkWell(
child: Icon(Icons.camera_alt),
onTap: () {
chooseImage();
},
),
suffixIcon: InkWell(
child: Icon(
Icons.send,
),
onTap: () {
if (filePickedName == 'nofile') {
insertMethod();
commentController.clear();
_fleshScreen();
getCommentData();
} else {
upload();
commentController.clear();
_fleshScreen();
getCommentData();
}
},
)),
style: new TextStyle(
color: Colors.black,
),
),
I want to create as this box with ImageView
facebook comment multimedia box
let me give you a widget for that
class CommentBox extends StatefulWidget {
final Widget image;
final TextEditingController controller;
final BorderRadius inputRadius;
final Function onSend,onImageRemoved;
const CommentBox({Key key, this.image, this.controller, this.inputRadius, this.onSend , this.onImageRemoved }) : super(key: key);
#override
_CommentBoxState createState() => _CommentBoxState();
}
class _CommentBoxState extends State<CommentBox> {
Widget image;
#override
void initState() {
image = widget.image;
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
height: 1,
color: Colors.grey[300],
thickness: 1,
),
const SizedBox(height: 20),
if (image != null)
_removable(
context,
_imageView(context),
),
if(widget.controller!=null) TextFormField(
controller: widget.controller,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.send,color: Theme.of(context).primaryColor,),
onPressed: widget.onSend,
),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: widget.inputRadius ?? BorderRadius.circular(32),
),
),
),
],
);
}
Widget _removable(BuildContext context, Widget child) {
return Stack(
alignment: Alignment.topRight,
children: [
child,
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
setState(() {
image = null;
widget.onImageRemoved();
});
},
)
],
);
}
Widget _imageView(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: image,
),
);
}
}
USE IT LIKE ANY WIDGET
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
SizedBox(height: 128,),
Spacer(),
CommentBox(
image: Image.asset(
"assets/svg/barber.svg",
height: 64,
width: 64,
),
controller: TextEditingController(),
onImageRemoved: (){
//on image removed
},
onSend: (){
//on send button pressed
},
),
],
),
),
),
)
I am trying to create something like the attached image. I got this far ...
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
child: ButtonTheme(
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () => print('hi'),
child: Text('Referals'),
color: Color(0xff2FBBF0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15.0),
topLeft: Radius.circular(15.0)),
),
),
RaisedButton(
onPressed: () => print('hii'),
child: Text('Stats'),
color: Color(0xff2FBBF0),
),
RaisedButton(
onPressed: () => print('hiii'),
child: Text('Edit Profile'),
color: Color(0xff2FBBF0),
// color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(15.0),
topRight: Radius.circular(15.0)),
),
),
],
),
),
),
),
But I don't really feel like it will look like the image.
I would also like the button group to be at the top of the Container. Now they're in the absolute center. Just like they would be if wrapped in a Center widget.
Here's the complete code. I have just used Container and Row because I find it more suitable and easy to achieve without any headache. :P
If you want with RaisedButton, figure it out.
Source:
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => new _DemoState();
}
class _DemoState extends State<Demo> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("DEMO")),
body: Padding( // used padding just for demo purpose to separate from the appbar and the main content
padding: EdgeInsets.all(10),
child: Container(
alignment: Alignment.topCenter,
child: Container(
height: 60,
padding: EdgeInsets.all(3.5),
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(Radius.circular(15)),
),
child: Row(
children: <Widget>[
Expanded(
child: InkWell(
onTap: () {},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12),
topLeft: Radius.circular(12))),
child: Text("Referrals",
style: TextStyle(
color: Colors.blue,
fontSize: 17,
)),
))),
Expanded(
child: InkWell(
onTap: () {},
child: Container(
alignment: Alignment.center,
child: Text("Stats",
style: TextStyle(
color: Colors.white, fontSize: 17)),
))),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: Container(color: Colors.white, width: 2)),
Expanded(
child: InkWell(
onTap: () {},
child: Container(
alignment: Alignment.center,
child: Text("Edit Profile",
style: TextStyle(
color: Colors.white, fontSize: 17)),
)))
],
)),
)));
}
}
Output Screenshot:
Check my ButtonGroup widget that I created
import 'package:flutter/material.dart';
class ButtonGroup extends StatelessWidget {
static const double _radius = 10.0;
static const double _outerPadding = 2.0;
final int current;
final List<String> titles;
final ValueChanged<int> onTab;
final Color color;
final Color secondaryColor;
const ButtonGroup({
Key key,
this.titles,
this.onTab,
int current,
Color color,
Color secondaryColor,
}) : assert(titles != null),
current = current ?? 0,
color = color ?? Colors.blue,
secondaryColor = secondaryColor ?? Colors.white,
super(key: key);
#override
Widget build(BuildContext context) {
return Material(
color: color,
borderRadius: BorderRadius.circular(_radius),
child: Padding(
padding: const EdgeInsets.all(_outerPadding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius - _outerPadding),
child: IntrinsicHeight(
child: Row(
mainAxisSize: MainAxisSize.min,
children: _buttonList(),
),
),
),
),
);
}
List<Widget> _buttonList() {
final buttons = <Widget>[];
for (int i = 0; i < titles.length; i++) {
buttons.add(_button(titles[i], i));
buttons.add(
VerticalDivider(
width: 1.0,
color: (i == current || i + 1 == current) ? color : secondaryColor,
thickness: 1.5,
indent: 5.0,
endIndent: 5.0,
),
);
}
buttons.removeLast();
return buttons;
}
Widget _button(String title, int index) {
if (index == this.current)
return _activeButton(title);
else
return _inActiveButton(title, index);
}
Widget _activeButton(String title) => FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
disabledColor: secondaryColor,
disabledTextColor: color,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
child: Text(title),
onPressed: null,
);
Widget _inActiveButton(String title, int index) => FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
color: Colors.transparent,
textColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
child: Text(title),
onPressed: () {
if (onTab != null) onTab(index);
},
);
}
You can use it like this
ButtonGroup(
titles: ["Button1", "Button2", "Button3"],
current: index,
color: Colors.blue,
secondaryColor: Colors.white,
onTab: (selected) {
setState(() {
index = selected;
});
},
)
Example:
import 'package:flutter/material.dart';
import 'package:flutter_app_test2/btn_grp.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int current = 0;
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ButtonGroup(
titles: ["Button1", "Button2", "Button3", "Button3"],
current: current,
onTab: (selected) {
print(selected);
setState(() {
current = selected;
});
},
),
),
);
}
}
try adding following in all RaisedButton widgets:
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
and buttonPadding: EdgeInsets.all(1), in ButtonBar
Source: https://api.flutter.dev/flutter/material/MaterialTapTargetSize-class.html