How to scroll to active text field in bottom sheet? - flutter

Here is self contained code that demo's the issue I am seeing.
When i click to view bottom sheet, it shows correctly:
But when I click into a textfield, it doesn't scroll the sheet up.
How do I get the screen to ensure field is visible and scrolls to the active text field? From what I can tell, it seems like it's related to using the DefaultTabController. On other screens, I don't have the issue...but still need to find a solution to this specific use-case.
import 'package:flutter/material.dart';
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
#override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
void showBottom() {
showModalBottomSheet(
context: context,
// isScrollControlled: true,
builder: (_) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
children: [
Text('testing bottom sheet.'),
TextFormField(),
TextFormField(),
TextFormField(),
],
),
);
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text('testing'),
bottom: TabBar(
indicatorColor: Colors.purple,
tabs: [
Tab(
child: Text(
'Zones',
style: TextStyle(color: Colors.black),
),
),
Text('My Profile', style: TextStyle(color: Colors.black))
],
),
),
body: TabBarView(
children: [
Container(
child: Text('Tab 1'),
),
Container(
child: Column(
children: [
Text('This is tab 2'),
TextButton(onPressed: (){
showBottom();
},child: Text('Show bottom'),)
],
),
)
],
),
));
}
}

Uncomment the line : isScrollControlled: true, this will allow the bottom sheet to take the space.

Related

How to open a new screen within the same tab and keep showing the TabBar

I would like when I click on button "Nova Reserva", it opens a new screen, but in the same tab, without losing the TabBar.
APP
enter image description here
Current
enter image description here
Code TabBarView
TabBarView(
controller: _tabController,
children: const [
HomeTab(),
ResearchesTab(),
SchedulesTab(),
Center(
child: Text('MENSAGENS'),
),
Center(
child: Text('CADASTROS'),
),
],
),
Code TabBar
child: TabBar(
physics: const BouncingScrollPhysics(),
controller: _tabController,
isScrollable: true,
indicatorPadding: EdgeInsets.symmetric(
vertical: size.height * .005,
),
indicatorSize: TabBarIndicatorSize.label,
indicator: BoxDecoration(
border: Border(
bottom: BorderSide(
color: CustomColors.orange,
width: size.height * .004,
),
),
),
labelPadding: EdgeInsets.symmetric(
horizontal: size.width * .04,
),
tabs: const [
TabBarTile(
image: 'assets/images/home.png',
label: 'Home',
),
TabBarTile(
image: 'assets/images/pesquisas.png',
label: 'Pesquisas',
),
TabBarTile(
image: 'assets/images/agendamentos.png',
label: 'Agendamentos',
),
TabBarTile(
image: 'assets/images/mensagens.png',
label: 'Mensagens',
),
TabBarTile(
image: 'assets/images/cadastros.png',
label: 'Cadastros',
),
],
),
In the button I'm using navigation with GetX, but I've also tried with MaterialPageRoute and I wasn't successful.
My objective
enter image description here
Create a Boolean variable that will change the tab bar's body according to its value. Change the tab bar's body content by changing the flag of the Boolean value.
Complete Code : -
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: _title,
home: MyStatelessWidget(),
);
}
}
class MyStatelessWidget extends StatefulWidget {
const MyStatelessWidget({super.key});
#override
State<MyStatelessWidget> createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
bool buttonOnePressed = false; // Declare the Boolean variable
#override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 1,
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('TabBar Widget'),
bottom: const TabBar(
tabs: <Widget>[
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
Tab(
text: "Tab 3",
),
],
),
),
body: TabBarView(
children: <Widget>[
const Center(
child: Text("Tab 1"),
),
buttonOnePressed // Display widgets according to Boolean variable
? const Center(
child: Text("From Button 1"),
)
: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
setState(() {
buttonOnePressed = true; // change Boolean value
});
},
child: const Text("Button 1"),
),
const SizedBox(width: 30),
ElevatedButton(
onPressed: () {}, child: const Text("Button 2"))
],
),
),
const Center(
child: Text("It's sunny here"),
),
],
),
),
);
}
}
Output : -

Evade flutter overflow when using row

[this is on desktop,not web or android]
I have following code, which creates a split screen (one side of screen has shortcuts to content and other side shows that content) it also acts somewhat as drawer since it can be closed or opened.
the left pane i reduce in one of two cases, when user clicks arrow button, or when the window side is less then 700. but if i try to take right edge of the screen and move very fast to reduce the size of whole window, the row will overflow and i will get an error.
So far i tryed using several things to achive this layout :
Using Flexible and setting fit and flex properties, (same issue as now since parent of them was again a row)
way that i am showing you now.
Also i could try to limit the size of screen lets say min value is 640 x 480 and that would also somewhat prevent error from happening.
I am just wondering is there another way to achieve this layout .
I also tryed several packages from pub.dev and ALL of them have same overflow error in their implementation .(easy_sidemenu,side_menu_navigation, etc)
my code
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: MyHomePage(
title: "My home",
),
);
}
}
class MyHomePage extends ConsumerStatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
ConsumerState<MyHomePage> createState() => _MyHomePageState();
}
final List<bool> isSelected = [false, false, false];
class _MyHomePageState extends ConsumerState<MyHomePage> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
elevation: 0,
toolbarHeight: 35,
centerTitle: true,
title: Text(widget.title),
),
body: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 500),
width: width > 700 ? 250 : 50,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 5),
children: [
TextButton(
onPressed: () {},
child: Row(
children: [
Icon(
Icons.home,
color: Theme.of(context).colorScheme.secondary,
size: 30,
),
const Flexible(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
"Home",
maxLines: 1,
style:
TextStyle(overflow: TextOverflow.clip),
),
),
),
],
),
),
]),
),
const SizedBox(
height: 5,
),
TextButton(
onPressed: () {},
child: Row(
children: const [
Icon(
Icons.settings,
size: 30,
),
Flexible(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
"Settings",
maxLines: 1,
style: TextStyle(overflow: TextOverflow.clip),
),
),
),
],
),
),
],
),
),
IconButton(onPressed: () {}, icon: const Icon(Icons.arrow_back)),
Expanded(
child: Container(
color: Colors.red,
)),
],
),
);
}
}

how to create bar under component?

I am developing a flutter app, I need to create a navigation bar like this
the problem is I don't know how to add that bar under categories (which changes to red when the component is selected).
any idea?
You can use TabBar and TabBarView.
you can change UI the way you like.
Demo result
demo Widget
class MyStatelessWidget extends StatefulWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
_MyStatelessWidgetState createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget>
with SingleTickerProviderStateMixin {
final tabs = <Widget>[
Tab(
icon: Icon(Icons.cloud_outlined),
),
Tab(
icon: Text("second tab"),
),
Tab(
icon: Icon(Icons.brightness_5_sharp),
),
];
late final TabController controller;
#override
void initState() {
controller = TabController(length: tabs.length, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) => Scaffold(
appBar: AppBar(
title: TextField(
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
suffixIcon: Icon(Icons.search),
),
),
actions: [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.more),
),
],
bottom: TabBar(controller: controller, tabs: tabs),
),
body: TabBarView(
controller: controller,
children: <Widget>[
Center(
child: Text("It's cloudy here"),
),
Center(
child: Text("It's rainy here"),
),
Center(
child: Text("It's sunny here"),
),
],
),
),
);
}
}

How to navigate to another Tab from via onTap() callback of another Tab of the same TabBarView parent?

This is my TabBarView.
I have 2 TabView - BuyerAccountBody() & SellerAccountBody()
I want to navigate via onTap() callback of a Widget in the BuyerAccountBody() to SellerAccountBody()
The code to the BuyerAccountBody() is below, where the onTap() callback in the LisTile should navigate to the 2nd TapBarView [i.e, SellerAccountBody() ]
class MyAccountView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text('My Account'),
actions: [],
bottom: TabBar(
labelStyle: kButtonTextStyle,
labelPadding: EdgeInsets.symmetric(vertical: 5),
tabs: [
Text(
'BUYER'),
Text(
'SELLER'),
],
),
),
body: TabBarView(
children: [
BuyerAccountBody(),
''' **To this Tab**
SellerAccountBody(),
'''
],
),
),
);
}
}
BuyerAccountBody() Widget.
class BuyerAccountBody extends StatefulWidget {
#override
_BuyerAccountBodyState createState() => _BuyerAccountBodyState();
}
class _BuyerAccountBodyState extends State<BuyerAccountBody> {
TabController controller;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
// ACCOUNT SETTINGS
Container(
padding: EdgeInsets.only(top: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 16),
child: Text(
'Account Settings',
style: Theme.of(context).textTheme.headline6,
),
),
SizedBox(height: 16),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[300]),
),
child: ListTile(
title: Text('Manage Your Seller Account'),
trailing: Icon(Icons.arrow_forward_ios),
''' **Navigate from here.........**
onTap: () {},
'''
),
),
],
),
),
],
),
);
}
}
Try this:
onTap: () => DefaultTabController.of(context).animateTo(1)

How to place tabs of TabBar in middle and upon clicking next tab, it starts shifting to left?

Mock I am trying to implement:
Then when starting clicking the next tab i.e 2 it shows 3rd tab (named 3) and 1st tab moves to left. Till eventually to far left slide of the screen.
Mock:
Finally, when clicked further it shows three dots to left also. FYI clicking on dots does nothing its a representation of showing that more that is there.
Now following is my code.
class TabbedAppBarSample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: choices.length,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white, // status bar color
brightness: Brightness.light,
title: TimerPage(),
bottom: TabBar(
// isScrollable: true,
indicatorColor:Colors.red,
unselectedLabelColor:Colors.grey,
labelColor: Colors.red,
tabs: choices.map((Choice choice) {
return Tab(
text: choice.title,
// icon: Icon(choice.icon),
);
}).toList(),
),
),
body: TabBarView(
children: choices.map((Choice choice) {
return Padding(
padding: const EdgeInsets.all(6.0),
child: ChoiceCard(choice: choice),
);
}).toList(),
),
),
),
);
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: '1'),
const Choice(title: '2'),
const Choice(title: '...'),
]; // above is a mock array which eventually will be coming from API call
Thanks and bear my coding I am new to flutter.
Use TabController to animate to next tab and use PreferredSize to control positon of tabbar
code snippet
appBar: AppBar(
title: Text(widget.title),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20.0),
child: Padding(
padding: const EdgeInsets.only(left: 200.0),
child: TabBar(
controller: _tabController,
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
),
),
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
}
void _toggleTab() {
_tabIndex = _tabController.index + 1;
_tabController.animateTo(_tabIndex);
}
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final appTitle = 'Tabs Demo';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({Key key, this.title}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int _tabIndex = 0;
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
}
void _toggleTab() {
_tabIndex = _tabController.index + 1;
_tabController.animateTo(_tabIndex);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
notchMargin: 20,
child: new Row(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
onTap: () {
_toggleTab();
},
child: Text(
'Next >',
style: TextStyle(fontSize: 20, color: Colors.red),
),
)
],
),
),
appBar: AppBar(
title: Text(widget.title),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20.0),
child: Padding(
padding: const EdgeInsets.only(left: 200.0),
child: TabBar(
controller: _tabController,
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
),
),
body: TabBarView(
controller: _tabController,
children: [
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 1'),
subtitle: Text('Click on Next Button to go to Tab 2.'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 2'),
subtitle: Text('Click on Next Button to go to Tab 3'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 3'),
subtitle: Text('The End'),
),
],
),
),
],
),
));
}
}