Scroll to specific widget Flutter web - flutter

I am creating a simple web portfolio to have hand-on practice in flutter. I was wondering how other website work when we click on home/about/contact button the web scroll to that specific widget.
I tried to do this but didn't get it how to implement this functionality
Code example will be helpful and will be appreciated as upvote.

you can give global key to the widget you want to scroll to
e.g
final dataKey = new GlobalKey();
assign it to the widget
Container(key:dataKey);
and then on the button onpressed write this code
onPressed: (){
Scrollable.ensureVisible(dataKey.currentContext);
}

you could use this package scroll_to_id
and here is an exemple made by github#yusukeinouehatchout
import 'package:flutter/material.dart';
import 'package:scroll_to_id/scroll_to_id.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ScrollToId? scrollToId;
final ScrollController scrollController = ScrollController();
List<Color> _colorList = [
Colors.green,
Colors.red,
Colors.yellow,
Colors.blue
];
void _scrollListener() {
print(scrollToId!.idPosition());
}
#override
void initState() {
super.initState();
/// Create ScrollToId instance
scrollToId = ScrollToId(scrollController: scrollController);
scrollController.addListener(_scrollListener);
}
/// Generate 10 Container
/// Case [Axis.horizontal] set buildStackHorizontal() to body
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Scroll to id',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Scroll to id'),
),
body: buildStackVertical(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.navigate_next),
onPressed: () {
scrollToId!.animateToNext(
duration: Duration(milliseconds: 500), curve: Curves.ease);
},
),
),
);
}
/// [Axis.vertical]
/// https://raw.githubusercontent.com/wiki/yusukeinouehatchout/scroll_to_id/gif/scroll_to_id_vertical.gif
Widget buildStackVertical() {
return Stack(
alignment: Alignment.topRight,
children: [
InteractiveScrollViewer(
scrollToId: scrollToId,
children: List.generate(10, (index) {
return ScrollContent(
id: '$index',
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 200,
child: Text(
'$index',
style: TextStyle(color: Colors.white, fontSize: 50),
),
color: _colorList[index % _colorList.length],
),
);
}),
),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate(10, (index) {
return GestureDetector(
child: Container(
width: 100,
alignment: Alignment.center,
height: 50,
child: Text(
'$index',
style: TextStyle(color: Colors.white),
),
color: _colorList[index % _colorList.length],
),
onTap: () {
/// scroll with animation
scrollToId!.animateTo('$index',
duration: Duration(milliseconds: 500),
curve: Curves.ease);
/// scroll with jump
// scrollToId.jumpTo('$index');
},
);
}),
),
)
],
);
}
/// [Axis.horizontal]
/// https://raw.githubusercontent.com/wiki/yusukeinouehatchout/scroll_to_id/gif/scroll_to_id_horizontal.gif
Widget buildStackHorizontal() {
return Column(
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(10, (index) {
return Expanded(
child: GestureDetector(
child: Container(
alignment: Alignment.center,
height: 80,
child: Text(
'$index',
style: TextStyle(color: Colors.white),
),
color: _colorList[index % _colorList.length],
),
onTap: () {
/// scroll with animation
scrollToId!.animateTo('$index',
duration: Duration(milliseconds: 500),
curve: Curves.ease);
/// scroll with jump
// scrollToId.jumpTo('$index');
},
),
);
}),
),
),
Expanded(
child: InteractiveScrollViewer(
scrollToId: scrollToId,
scrollDirection: Axis.horizontal,
children: List.generate(10, (index) {
return ScrollContent(
id: '$index',
child: Container(
alignment: Alignment.center,
width: 200,
child: Text(
'$index',
style: TextStyle(color: Colors.white, fontSize: 50),
),
color: _colorList[index % _colorList.length],
),
);
}),
),
),
],
);
}
}

I faced the same problem but I managed to solve it with this package it's helpful and easy scroll_to_index
define a listview controller
ListView( controller: controller, )
then you just need to wrap the elements in your screen with AutoScrollTag like
AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: YOUR_CHILD_HERE
)
finally scroll to our element like this
controller.scrollToIndex(index, preferPosition: AutoScrollPosition.begin)

Related

How to build an on tap Expandable container

So I was trying to build a user id page for my flutter app where you tap on a container and the containers height is increased and a different set of data is shown. On expanded I also wanted to add a scrollable tabview and that's second part of the problem.
the expected ui looks like thishttps://i.stack.imgur.com/62sro.gif.
I have tried Expanded and expansion tile, Can't quite achieve the output
Is there any other method to achieve this?
Welcome #Anand Pillai,
First add this line to your pubspec.yaml expandable: ^5.0.1
try this code
import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late PageController _pageController;
final ExpandableController _controller = ExpandableController();
int activePage = 1;
int _counter = 0;
List<String> images = [
"https://images.pexels.com/photos/14686142/pexels-photo-14686142.jpeg",
"https://wallpaperaccess.com/full/2637581.jpg",
"https://uhdwallpapers.org/uploads/converted/20/01/14/the-mandalorian-5k-1920x1080_477555-mm-90.jpg"
];
List<Widget> indicators(imagesLength, currentIndex) {
return List<Widget>.generate(imagesLength, (index) {
return Container(
margin: const EdgeInsets.all(3),
width: 10,
height: 10,
decoration: BoxDecoration(
color: currentIndex == index ? Colors.white : Colors.blueGrey,
shape: BoxShape.circle),
);
});
}
AnimatedContainer slider(images, pagePosition, active) {
// double margin = active ? 10 : 20;
return AnimatedContainer(
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOutCubic,
// margin: EdgeInsets.all(margin),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(images[pagePosition]),
fit: BoxFit.cover,
)),
);
}
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
alignment: Alignment.center,
children: [imageSlider(), expandedWidget(context)],
),
),
],
));
}
Positioned expandedWidget(BuildContext context) {
return Positioned.fill(
bottom: _controller.expanded ? 0 : 60,
left: 0,
right: 0,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_controller.expanded
? const SizedBox.shrink()
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators(images.length, activePage)),
ExpandableNotifier(
child: AnimatedContainer(
height: _controller.expanded ? 400 : 110.0,
width: double.infinity,
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.all(15.0),
margin: _controller.expanded
? EdgeInsets.zero
: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 255, 79, 77).withOpacity(0.8),
borderRadius: _controller.expanded
? const BorderRadius.only(
topRight: Radius.circular(15),
topLeft: Radius.circular(15),
)
: BorderRadius.circular(15.0),
),
duration: const Duration(milliseconds: 500),
child: Column(
children: <Widget>[
ScrollOnExpand(
scrollOnExpand: true,
scrollOnCollapse: false,
child: ExpandablePanel(
controller: _controller
..addListener(() {
setState(() {});
}),
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true,
iconColor: Colors.white,
),
header: Padding(
padding: const EdgeInsets.all(10),
child: Text(
"ExpandablePanel",
style: Theme.of(context)
.textTheme
.bodyText1!
.copyWith(color: Colors.white),
)),
collapsed: const Text(
"loremIpsum",
style: TextStyle(color: Colors.white),
softWrap: true,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
expanded: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
for (var _ in Iterable.generate(5))
const Padding(
padding: EdgeInsets.only(bottom: 10),
child: Text(
"loremIpsum",
style: TextStyle(color: Colors.white),
softWrap: true,
overflow: TextOverflow.fade,
)),
],
),
builder: (_, collapsed, expanded) {
return Padding(
padding: const EdgeInsets.only(
left: 10, right: 10, bottom: 10),
child: Expandable(
collapsed: collapsed,
expanded: expanded,
theme: const ExpandableThemeData(crossFadePoint: 0),
),
);
},
),
),
],
),
)),
],
));
}
PageView imageSlider() {
return PageView.builder(
itemCount: images.length,
physics: _controller.expanded
? const NeverScrollableScrollPhysics()
: ScrollPhysics(),
padEnds: false,
controller: _pageController,
onPageChanged: (page) {
setState(() {
activePage = page;
});
},
itemBuilder: (context, pagePosition) {
bool active = pagePosition == activePage;
return slider(images, pagePosition, active);
});
}
}
class _MyHomePageState extends State<MyHomePage> {
double _margin = 30, _height = 100, _width = 300;
final Text _widget1 = const Text('This is my Foo');
final Text _widget2 = const Text('This is Bar');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: GestureDetector(
// When the child is tapped, set state is called.
onTap: () {
setState(() {
_margin = _margin == 30 ? 0 : 30;
_height = _height == 100 ? 300 : 100;
_width = _width == 300 ? MediaQuery.of(context).size.width : 300;
});
},
// The custom button
child: Align(
alignment: Alignment.bottomCenter,
child: AnimatedContainer(
width: _width,
height: _height,
curve: Curves.easeInExpo,
margin: EdgeInsets.fromLTRB(_margin, 0, _margin, _margin),
duration: Duration(milliseconds: 250),
padding: const EdgeInsets.all(0),
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(8.0),
),
child: _margin == 30 ? _widget1 : _widget2,
),
),
)),
);
}
}
Simple logic is to animate the container when tapped and change the widget in it. On tap it calls setsate that sets the height, width, margin and child of the container.

Custom Sliver App Bar in flutter with an Image and 2 Text widgets going into app bar on scrolling

i want to implement the sliver app bar as shown in the the 2 pictures given below. After much googling , I fount about the CustomScrollView widget and the SliverAppBar widget but all the tutorials and blogs online about sliver app bars show a simple one where an image disappears into an app bar with a text as title on scrolling. However here what I want to achieve is slightly different and I am having a hard time trying to figure out how to do it. Can anyone help me with it?
You can try this:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ScrollController? _scrollController;
bool lastStatus = true;
double height = 200;
void _scrollListener() {
if (_isShrink != lastStatus) {
setState(() {
lastStatus = _isShrink;
});
}
}
bool get _isShrink {
return _scrollController != null &&
_scrollController!.hasClients &&
_scrollController!.offset > (height - kToolbarHeight);
}
#override
void initState() {
super.initState();
_scrollController = ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
_scrollController?.removeListener(_scrollListener);
_scrollController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
title: 'Horizons Weather',
home: Scaffold(
body: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
elevation: 0,
backgroundColor: Colors.blueGrey,
pinned: true,
expandedHeight: 275,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: _isShrink
? const Text(
"Profile",
)
: null,
background: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 48),
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Image.network(
headerImage,
fit: BoxFit.cover,
height: 100,
width: 100,
),
),
),
const SizedBox(
height: 16,
),
Text(
"Flipkart",
style: textTheme.headline4,
),
const SizedBox(
height: 8,
),
const Text(
"flipkart.com",
),
const SizedBox(
height: 5,
),
const Text(
"Info about the company",
),
],
),
),
),
actions: _isShrink
? [
Padding(
padding: const EdgeInsets.only(left: 8, right: 12),
child: Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 8, right: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Flipkart",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
"flipkart.com",
style: TextStyle(
fontSize: 12,
),
),
],
),
),
ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Image.network(
headerImage,
fit: BoxFit.cover,
height: 30,
width: 30,
),
),
],
),
),
]
: null,
),
];
},
body: CustomScrollView(
scrollBehavior: const ConstantScrollBehavior(),
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text("Item: $index")),
);
},
childCount: 50,
),
),
],
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
const UserAccountsDrawerHeader(
accountName: Text("Zakaria Hossain"),
accountEmail: Text("zakariaaltime#gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.orange,
child: Text(
"A",
style: TextStyle(fontSize: 40.0),
),
),
),
ListTile(
leading: Icon(Icons.home),
title: Text("Home"),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text("Settings"),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.contacts),
title: Text("Contact Us"),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
),
);
}
}
Demo

Is there a way of making beautiful dropdown menu in flutter?

I want to make beautiful dropdown menu like this. I already tried making it with containers, but it's taking very long time. Is there any package or a way of configuring default dropdownmenu and items?
You could use a Container() Widget with Boxdecoration and as a child the DropdownButton() Widget.
Use DropdownButtonHideUnderline() as a Parent to hide the default Underline.
Sample Code:
Container(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
height: 40.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.yellow,
),
child: DropdownButtonHideUnderline(
child: DropdownButton() // your Dropdown Widget here
),
);
try this:
import 'package:flutter/material.dart';
void main() => runApp(ExampleApp());
class ExampleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: PopMenu(),
);
}
}
class PopMenu extends StatefulWidget {
#override
_PopMenuState createState() => _PopMenuState();
}
class _PopMenuState extends State<PopMenu> {
List<String> _menuList = ['menu 1', 'menu 2', 'menu 3'];
GlobalKey _key = LabeledGlobalKey("button_icon");
OverlayEntry _overlayEntry;
Offset _buttonPosition;
bool _isMenuOpen = false;
void _findButton() {
RenderBox renderBox = _key.currentContext.findRenderObject();
_buttonPosition = renderBox.localToGlobal(Offset.zero);
}
void _openMenu() {
_findButton();
_overlayEntry = _overlayEntryBuilder();
Overlay.of(context).insert(_overlayEntry);
_isMenuOpen = !_isMenuOpen;
}
void _closeMenu() {
_overlayEntry.remove();
_isMenuOpen = !_isMenuOpen;
}
OverlayEntry _overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
top: _buttonPosition.dy + 70,
left: _buttonPosition.dx,
width: 300,
child: _popMenu(),
);
},
);
}
Widget _popMenu() {
return Material(
child: Container(
width: 300,
height: 300,
decoration: BoxDecoration(
color: Color(0xFFF67C0B9),
borderRadius: BorderRadius.circular(4),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate(
_menuList.length,
(index) {
return GestureDetector(
onTap: () {},
child: Container(
alignment: Alignment.center,
width: 300,
height: 100,
child: Text(_menuList[index]),
),
);
},
),
),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
key: _key,
width: 300,
height: 50,
decoration: BoxDecoration(
color: Color(0xFFF5C6373),
borderRadius: BorderRadius.circular(25),
),
child: Row(
children: [
Expanded(
child: Center(child: Text('menu 1')),
),
IconButton(
icon: Icon(Icons.arrow_downward),
color: Colors.white,
onPressed: () {
_isMenuOpen ? _closeMenu() : _openMenu();
},
),
],
),
),
),
);
}
}

Flutter - How to make a custom TabBar

This is the output that I want. I am still new in flutter so can anyone let me know if there is already a widget for this kind of switch or how should I make one ??
Also, I want the data shown below this button to change if I choose the other button but I guess that's obvious.
Thanks in advance.
You can use the TabBar widget to achieve this. I added a full example demonstrating how you can create this using the TabBar widget:
CODE
class StackOver extends StatefulWidget {
#override
_StackOverState createState() => _StackOverState();
}
class _StackOverState extends State<StackOver>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Tab bar',
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
// give the tab bar a height [can change hheight to preferred height]
Container(
height: 45,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(
25.0,
),
),
child: TabBar(
controller: _tabController,
// give the indicator a decoration (color and border radius)
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(
25.0,
),
color: Colors.green,
),
labelColor: Colors.white,
unselectedLabelColor: Colors.black,
tabs: [
// first tab [you can add an icon using the icon property]
Tab(
text: 'Place Bid',
),
// second tab [you can add an icon using the icon property]
Tab(
text: 'Buy Now',
),
],
),
),
// tab bar view here
Expanded(
child: TabBarView(
controller: _tabController,
children: [
// first tab bar view widget
Center(
child: Text(
'Place Bid',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
),
),
),
// second tab bar view widget
Center(
child: Text(
'Buy Now',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
],
),
),
);
}
}
OUTPUT
Try out this you have to change some colour and font:-
import 'package:flutter/material.dart';
typedef SwitchOnChange = Function(int);
class CustomSwitch extends StatefulWidget {
SwitchOnChange onChange;
CustomSwitch({this.onChange});
#override
State<StatefulWidget> createState() {
return CustomSwitchState();
}
}
class CustomSwitchState extends State<CustomSwitch>
with TickerProviderStateMixin {
AnimationController controller;
Animation animation;
GlobalKey key = GlobalKey();
#override
void initState() {
Future.delayed(Duration(milliseconds: 100)).then((v) {
controller = AnimationController(
vsync: this, duration: Duration(milliseconds: 300));
tabWidth = key.currentContext.size.width / 2;
// var width = (media.size.width - (2 * media.padding.left)) / 2;
animation = Tween<double>(begin: 0, end: tabWidth).animate(controller);
setState(() {});
controller.addListener(() {
setState(() {});
});
});
super.initState();
}
var selectedValue = 0;
double tabWidth = 0;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
selectedValue == 0 ? this.controller.forward() : controller.reverse();
selectedValue = selectedValue == 0 ? 1 : 0;
},
child: Container(
key: key,
height: 44,
decoration: BoxDecoration(
color: Colors.grey, borderRadius: BorderRadius.circular(22)),
child: Stack(
children: <Widget>[
Row(
children: <Widget>[
Transform.translate(
offset: Offset(animation?.value ?? 0, 0),
child: Container(
height: 44,
width: tabWidth,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(22),
boxShadow: [
BoxShadow(color: Colors.grey, blurRadius: 3),
]),
),
),
],
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: tabWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.directions_walk),
SizedBox(width: 5),
Text("Place Bid")
],
),
),
Container(
width: tabWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.directions_walk),
SizedBox(width: 5),
Text("Buy now")
],
),
)
],
),
),
],
),
),
);
}
}
The following is my workaround, which I believe to be the best method.
import 'package:flutter/material.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({
super.key,
});
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('Settings'),
bottom: PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
child: Container(
height: 50,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
10,
),
color: Colors.grey[200],
),
child: TabBar(
labelColor: Colors.white,
unselectedLabelColor: Colors.black,
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(
10,
),
color: Colors.pink,
),
tabs: const [
Tab(
text: 'Basic',
),
Tab(
text: 'Advanced',
)
],
),
),
),
),
),
body: const TabBarView(
children: [
Center(
child: Text(
'Basic Settings',
style: TextStyle(
fontSize: 30,
),
),
),
Center(
child: Text(
'Advanced Settings',
style: TextStyle(
fontSize: 30,
),
),
),
],
),
),
);
}
}
You can use also PageView widget.
const double borderRadius = 25.0;
class CustomSwitchState extends StatefulWidget {
#override
_CustomSwitchStateState createState() => _CustomSwitchStateState();
}
class _CustomSwitchStateState extends State<CustomSwitchState> with SingleTickerProviderStateMixin {
PageController _pageController;
int activePageIndex = 0;
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: _menuBar(context),
),
Expanded(
flex: 2,
child: PageView(
controller: _pageController,
physics: const ClampingScrollPhysics(),
onPageChanged: (int i) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
activePageIndex = i;
});
},
children: <Widget>[
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Center(child: Text("Place Bid"),),
),
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Center(child: Text("Buy Now"),),
),
],
),
),
],
),
),
),
));
}
Widget _menuBar(BuildContext context) {
return Container(
width: 300.0,
height: 50.0,
decoration: const BoxDecoration(
color: Color(0XFFE0E0E0),
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
onTap: _onPlaceBidButtonPress,
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(vertical: 15),
alignment: Alignment.center,
decoration: (activePageIndex == 0) ? const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
) : null,
child: Text(
"Place Bid",
style: (activePageIndex == 0) ? TextStyle(color: Colors.white) : TextStyle(color: Colors.black),
),
),
),
),
Expanded(
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
onTap: _onBuyNowButtonPress,
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(vertical: 15),
alignment: Alignment.center,
decoration: (activePageIndex == 1) ? const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
) : null,
child: Text(
"Buy Now",
style: (activePageIndex == 1) ? TextStyle(color: Colors.white, fontWeight: FontWeight.bold) : TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
],
),
);
}
void _onPlaceBidButtonPress() {
_pageController.animateToPage(0,
duration: const Duration(milliseconds: 500), curve: Curves.decelerate);
}
void _onBuyNowButtonPress() {
_pageController.animateToPage(1,
duration: const Duration(milliseconds: 500), curve: Curves.decelerate);
}
}
OUTPUT
If you want tab layout like this you can use this
Output:
import 'package:flutter/material.dart';
import 'package:icons_helper/icons_helper.dart';
class DetailScreen extends StatefulWidget {
var body;
String title = "";
DetailScreen(this.body, this.title);
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<DetailScreen> with TickerProviderStateMixin {
late int _startingTabCount;
List<Tab> _tabs = <Tab>[];
List<Widget> _generalWidgets = <Widget>[];
late TabController _tabController;
#override
void initState() {
_startingTabCount = widget.body["related_modules"].length;
_tabs = getTabs(_startingTabCount);
_tabController = getTabController();
super.initState();
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
bottom: TabBar(
isScrollable: true,
tabs: _tabs,
controller: _tabController,
),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.blue,
],
stops: [0.3, 1.0],
),
),
),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
onPressed: () {
Navigator.of(context, rootNavigator: true).pop(context);
},
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.skip_previous),
color: Colors.white,
onPressed: () {
goToPreviousPage();
},
),
Container(
margin: EdgeInsets.only(right: 15),
child: IconButton(
icon: Icon(Icons.skip_next),
color: Colors.white,
onPressed: () {
goToNextPage();
},
),
)
],
),
body: Column(
children: <Widget>[
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
controller: _tabController,
children: getWidgets(),
),
),
],
),
);
}
TabController getTabController() {
return TabController(length: _tabs.length, vsync: this)
..addListener(_updatePage);
}
Tab getTab(int widgetNumber) {
return Tab(
icon: Column(
children: [
if (widget.body["related_modules"][widgetNumber]["icon"].toString() ==
"fa-comments-o") ...[
Icon(
Icons.comment_outlined,
),
] else if (widget.body["related_modules"][widgetNumber]["icon"]
.toString() ==
"fa-map-marker") ...[
Icon(
Icons.location_on_rounded,
),
] else if (widget.body["related_modules"][widgetNumber]["icon"]
.toString() ==
"fa-address-card") ...[
Icon(
Icons.contact_page_sharp,
),
] else ...[
Icon(
getIconUsingPrefix(
name: widget.body["related_modules"][widgetNumber]["icon"]
.toString()
.substring(3),
),
)
]
],
),
text: widget.body["related_modules"][widgetNumber]["label"].toString(),
);
}
Widget getWidget(int widgetNumber) {
return Center(
child: Text("Widget nr: $widgetNumber"),
);
}
List<Tab> getTabs(int count) {
_tabs.clear();
for (int i = 0; i < count; i++) {
_tabs.add(getTab(i));
}
return _tabs;
}
List<Widget> getWidgets() {
_generalWidgets.clear();
for (int i = 0; i < _tabs.length; i++) {
_generalWidgets.add(getWidget(i));
}
return _generalWidgets;
}
void _updatePage() {
setState(() {});
}
//Tab helpers
bool isFirstPage() {
return _tabController.index == 0;
}
bool isLastPage() {
return _tabController.index == _tabController.length - 1;
}
void goToPreviousPage() {
_tabController.animateTo(_tabController.index - 1);
}
void goToNextPage() {
isLastPage()
? showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text("End reached"),
content: Text("This is the last page.")))
: _tabController.animateTo(_tabController.index + 1);
}
}

how to fix inverted 'ok' text in flatbutton?

I'm beginner in flutter. trying to design login page. when user clicks on 'ok' button then 'ok' button gets invisible and 'approved' named button gets visible using some animation. problem is that 'ok' displayed in inverted form as shown in pic. how dI correct this issue?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation class',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() => stateClass();
}
class stateClass extends State<HomePage> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation<double> animation;
Animation<double> sizeAnimation;
int currentState = 0;
#override
void initState() {
super.initState();
animationController = AnimationController(
duration: Duration(milliseconds: 1000), vsync: this);
animation = Tween<double>(begin: 0, end: 60).animate(animationController)
..addListener(() {
setState(() {});
});
sizeAnimation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
parent: animationController, curve: Curves.fastOutSlowIn))
..addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Animation login'),
),
body: Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 100,
//color: Colors.black,
child: Center(
child: Image.asset('assets/fluttericon.png'),
)),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: TextFormField(
decoration: InputDecoration(
labelText: 'enter your email id',
),
),
),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: TextFormField(
obscureText: true,
decoration: InputDecoration(
labelText: 'enter your password',
),
),
),
Container(
// color: Colors.teal,
// height: 0,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value - 1,
child: FlatButton(
onPressed: animationController.forward,
color: Colors.redAccent[200],
child: Text(
'ok',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
Container(
//color: Colors.teal,
height: 80,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value,
child: FlatButton(
onPressed: animationController.reverse,
color: Colors.redAccent[200],
child: Text(
'approved',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
],
),
)
)
);
}
}
Text container
Container(
// color: Colors.teal,
// height: 0,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value-1 ,
child: FlatButton(
onPressed: animationController.forward,
color: Colors.redAccent[200],
child: Text(
'ok',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
When I change sizeAnimation.value-1 to sizeAnimation. then 'ok' word is in erect form. but ok button is not invisible.
Screenshot preview
A possible solution for what you are trying to do is to use Fade and Rotate transitions with separate controllers for each Text widget. Here's an example of that:
class ButtonTextFadeRotation extends StatefulWidget {
#override
_ButtonTextFadeRotationState createState() => _ButtonTextFadeRotationState();
}
class _ButtonTextFadeRotationState extends State<ButtonTextFadeRotation> with TickerProviderStateMixin {
AnimationController _okAnimationController;
AnimationController _approvedAnimationController;
#override
void initState() {
_okAnimationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
value: 1
);
_approvedAnimationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
value: 0
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: ClipRect(
child: RaisedButton(
onPressed: () {
_okAnimationController.reverse();
_approvedAnimationController.forward();
},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
FadeTransition(
opacity: _okAnimationController,
child: RotationTransition(
turns: _okAnimationController,
alignment: Alignment.center,
child: Text('Ok'),
),
),
FadeTransition(
opacity: _approvedAnimationController,
child: RotationTransition(
turns: _approvedAnimationController,
alignment: Alignment.center,
child: Text('Approved'),
),
),
],
),
),
),
);
}
}